玩opencv時(shí)候,肯定會接觸色彩空間。最常用的是RGB色彩空間,用0~255表示每個(gè)通道。
攝影投效里有個(gè)技術(shù),叫做藍(lán)幕,也有綠幕。后期把藍(lán)色區(qū)域扣掉,然后換成別的背景。
在上圖中,細(xì)心的小伙伴會發(fā)現(xiàn),實(shí)際這個(gè)藍(lán)色并不一定是純藍(lán)(0,0,255)
有腦洞大的小朋友想到了一個(gè)方法,只提取藍(lán)色通道,然后把值接近255的都扣掉。
但是有個(gè)問題,這樣會扣到高光區(qū)域(RGB三個(gè)值都很高的區(qū)域)
另外,如果這個(gè)藍(lán)色偏亮偏暗或偏綠,或者攝像機(jī)有偏色,用(0,0,255)這個(gè)參數(shù)當(dāng)特征來匹配是很困難的事。
這兒我給大家推薦一個(gè)好用的色彩空間,叫HSV色彩空間。
H是個(gè)色相參數(shù),用0到360度表示了顏色。
S是個(gè)色彩鮮艷度的參數(shù),越大顏色越鮮艷,越小顏色越灰。S有個(gè)通俗的名字,叫飽和度。
V是個(gè)亮度參數(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;
}
我們先找一張色彩分布的圖來試驗(yàn)一下?lián)笀D
藍(lán)色附近的區(qū)域就是H在240度附近。下面我們寫個(gè)小程序把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í)候計(jì)數(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);
}
運(yùn)行效果如圖
在上圖中,我們發(fā)現(xiàn)這個(gè)算法可以準(zhǔn)確地扣出藍(lán)色區(qū)域,而且即使藍(lán)色亮一點(diǎn)暗一點(diǎn)或是灰一點(diǎn)鮮艷一點(diǎn),也沒有影響。
接下來,我們找兩個(gè)圖片來摳圖和合成圖像。
首先是藍(lán)幕原圖
然后是背景
我們來寫一下?lián)赋{(lá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í)候計(jì)數(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);
合成以后的圖像見下圖右下。
接下來,我們再換個(gè)圖片做一次。為了讓圖片增加些戲劇效果,我找來了一個(gè)熱氣球的藍(lán)幕原圖和一段樹枝的背景。
藍(lán)幕原圖
背景
最后合成的圖像見下圖右上。
這種基于OpenCV的藍(lán)幕摳圖算法可以自動地對每一幀圖像進(jìn)行處理和合成,特別適合用于視頻的實(shí)時(shí)摳圖,也許可以用在自動換背景等應(yīng)用上。
評論
查看更多