玩opencv時候,肯定會接觸色彩空間。最常用的是RGB色彩空間,用0~255表示每個通道。
攝影投效里有個技術(shù),叫做藍幕,也有綠幕。后期把藍色區(qū)域扣掉,然后換成別的背景。
在上圖中,細(xì)心的小伙伴會發(fā)現(xiàn),實際這個藍色并不一定是純藍(0,0,255)
有腦洞大的小朋友想到了一個方法,只提取藍色通道,然后把值接近255的都扣掉。
但是有個問題,這樣會扣到高光區(qū)域(RGB三個值都很高的區(qū)域)
另外,如果這個藍色偏亮偏暗或偏綠,或者攝像機有偏色,用(0,0,255)這個參數(shù)當(dāng)特征來匹配是很困難的事。
這兒我給大家推薦一個好用的色彩空間,叫HSV色彩空間。
H是個色相參數(shù),用0到360度表示了顏色。
S是個色彩鮮艷度的參數(shù),越大顏色越鮮艷,越小顏色越灰。S有個通俗的名字,叫飽和度。
V是個亮度參數(shù),越小越黑
RGB到HSV色彩空間的轉(zhuǎn)換代碼如下:
float rgb2h(int B, int G, int R)
{
float H;
int max = max(max(R, G), B);
int min = min(min(R, G), B);
if (R == max)
H = (G - B)*60.0 / (max - min);
if (G == max)
H = 120+(B - R)*60.0 / (max - min);
if (B == max)
H = 240+(R - G)*60.0 / (max - min);
if (H < 0)H = H + 360;
return H;
}
我們先找一張色彩分布的圖來試驗一下?lián)笀D
藍色附近的區(qū)域就是H在240度附近。下面我們寫個小程序把240度正負(fù)50度的區(qū)域摳掉。
void mytest()
{
Mat frame_t = imread("a3.jpg", CV_LOAD_IMAGE_UNCHANGED);
int WW, HH;//圖像寬度和高度 單位:像素
HH = frame_t.rows;WW = frame_t.cols;int row2, col2;//循環(huán)時候計數(shù)第幾行和第幾列的
for (row2 = 0; row2 < HH; row2++)
{
for (col2 = 0; col2 < WW; col2++)
{
if (fabsf(rgb2h(frame_t.at(row2, col2)[0], frame_t.at(row2, col2)[1], frame_t.at(row2, col2)[2]) - cut)<5)
{
frame_t.at(row2, col2)[0] = 0;
frame_t.at(row2, col2)[1] = 0;
frame_t.at(row2, col2)[2] = 0;
}
}
}
imshow("hsvcut", frame_t);
}
運行效果如圖
在上圖中,我們發(fā)現(xiàn)這個算法可以準(zhǔn)確地扣出藍色區(qū)域,而且即使藍色亮一點暗一點或是灰一點鮮艷一點,也沒有影響。
接下來,我們找兩個圖片來摳圖和合成圖像。
首先是藍幕原圖
然后是背景
我們來寫一下?lián)赋{色部分以后與背景疊加的代碼
Mat frame_orig;//采集的原始圖像
frame_orig = imread("my2.jpg", CV_LOAD_IMAGE_UNCHANGED);
Mat frame_back;//采集的原始圖像
frame_back = imread("my1.jpg", CV_LOAD_IMAGE_UNCHANGED);
imshow("orig", frame_orig);
imshow("back", frame_back);
Mat frame_c;//測試圖像
frame_c = frame_orig;
int W, H;//圖像寬度和高度 單位:像素
H = frame_orig.rows;
W = frame_orig.cols;
int row, col;//循環(huán)時候計數(shù)第幾行和第幾列的
for (row = 0; row < H; row++)
{
for (col = 0; col < W; col++)
{
if (fabsf(rgb2h(frame_orig.at(row, col)[0], frame_orig.at(row, col)[1], frame_orig.at(row, col)[2])-cut)
{
frame_c.at(row, col)[0] = frame_back.at(row, col)[0];
frame_c.at(row, col)[1] = frame_back.at(row, col)[1];
frame_c.at(row, col)[2] = frame_back.at(row, col)[2];
}
}
}
imshow("MyPic", frame_c);
合成以后的圖像見下圖右下。
接下來,我們再換個圖片做一次。為了讓圖片增加些戲劇效果,我找來了一個熱氣球的藍幕原圖和一段樹枝的背景。
藍幕原圖
背景
最后合成的圖像見下圖右上。
這種基于OpenCV的藍幕摳圖算法可以自動地對每一幀圖像進行處理和合成,特別適合用于視頻的實時摳圖,也許可以用在自動換背景等應(yīng)用上。
評論
查看更多