摄影领域的OpenCV教程之“蓝幕抠图”

嵌入式技术

1333人已加入

描述

玩opencv时候,肯定会接触色彩空间。最常用的是RGB色彩空间,用0~255表示每个通道。

摄影投效里有个技术,叫做蓝幕,也有绿幕。后期把蓝色区域扣掉,然后换成别的背景。

在上图中,细心的小伙伴会发现,实际这个蓝色并不一定是纯蓝(0,0,255)

有脑洞大的小朋友想到了一个方法,只提取蓝色通道,然后把值接近255的都扣掉。

但是有个问题,这样会扣到高光区域(RGB三个值都很高的区域)

另外,如果这个蓝色偏亮偏暗或偏绿,或者摄像机有偏色,用(0,0,255)这个参数当特征来匹配是很困难的事。

这儿我给大家推荐一个好用的色彩空间,叫HSV色彩空间。

OpenCV

H是个色相参数,用0到360度表示了颜色。

S是个色彩鲜艳度的参数,越大颜色越鲜艳,越小颜色越灰。S有个通俗的名字,叫饱和度。

V是个亮度参数,越小越黑

RGB到HSV色彩空间的转换代码如下:

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;

}

我们先找一张色彩分布的图来试验一下抠图

OpenCV

蓝色附近的区域就是H在240度附近。下面我们写个小程序把240度正负50度的区域抠掉。

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;//循环时候计数第几行和第几列的

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);

}

运行效果如图

OpenCV

在上图中,我们发现这个算法可以准确地扣出蓝色区域,而且即使蓝色亮一点暗一点或是灰一点鲜艳一点,也没有影响。

接下来,我们找两个图片来抠图和合成图像。

首先是蓝幕原图

然后是背景

我们来写一下抠除蓝色部分以后与背景叠加的代码

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;//循环时候计数第几行和第几列的

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的蓝幕抠图算法可以自动地对每一帧图像进行处理和合成,特别适合用于视频的实时抠图,也许可以用在自动换背景等应用上。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分