C++ 机器视觉—前景检测

2022-07-31 20:16
11
0
添加收藏

什么是机器视觉?什么是前景检测?
机器视觉就是一门研究如何使机器“看”的学科(PS:大而空的话放到前面,来自维基百科)。

要理解前景检测这个词就需要从它的反义词“背景”理解,背景很好理解,我站到一个海蓝色的墙前面,我的背景就是墙,也可以说是海蓝色,那前景就是我了;前景检测就是找到我和背景不一样的地方。人一眼就可以看出来我站到墙前面,计算机可看不出来。

视觉
机器的视觉一般就是摄像机或视频文件,我们首先要从摄像拿到摄像机的画面,然后去对摄像机的画面进行处理。一般就是摄像机的帧率为21帧,就是一秒钟有多少张图,即21张图。

机器“眼中”的画面
机器眼中 所以东西都是01010101010101010这种东西,哈哈。经过一系列封装(如操作系统,文件格式、C++类库等等)最后可能我们可以在计算机内看到一个矩阵,以三通道BGR为例可能如下表(PS我猜的):
————————————————
0xff(B) 0xff(G) 0xff(R) 0xff(B) 0xff(G) 0xff(R) 0xff(B) 0xff(G) 0xff(R) 0xff(B) 0xff(G) 0xff(R)
0xff(B) 0xff(G) 0xff(R) 0xff(B) 0xff(G) 0xff(R) 0xff(B) 0xff(G) 0xff(R) 0xff(B) 0xff(G) 0xff(R)
0xff(B) 0xff(G) 0xff(R) 0xff(B) 0xff(G) 0xff(R) 0xff(B) 0xff(G) 0xff(R) 0xff(B) 0xff(G) 0xff(R)
0xff(B) 0xff(G) 0xff(R) 0xff(B) 0xff(G) 0xff(R) 0xff(B) 0xff(G) 0xff(R) 0xff(B) 0xff(G) 0xff(R)
————————————————
4*4的像素矩阵可能就是这样子的啦,这里也科普一下1920*1280就是有1920列1280行个这样的像素矩阵,计算机里面是什么样子的呢?先将16进制转成2进制

11111111(B) 11111111(G) 11111111(R) 11111111(B) 11111111(G) 11111111(R) 11111111(B) 11111111(G) 11111111(R) 11111111(B) 11111111(G) 11111111(R)
11111111(B) 11111111(G) 11111111(R) 11111111(B) 11111111(G) 11111111(R) 11111111(B) 11111111(G) 11111111(R) 11111111(B) 11111111(G) 11111111(R)
11111111(B) 11111111(G) 11111111(R) 11111111(B) 11111111(G) 11111111(R) 11111111(B) 11111111(G) 11111111(R) 11111111(B) 11111111(G) 11111111(R)
11111111(B) 11111111(G) 11111111(R) 11111111(B) 11111111(G) 11111111(R) 11111111(B) 11111111(G) 11111111(R) 11111111(B) 11111111(G) 11111111(R)
前景
假设我们的背景是白色的一个区域,我们前景是一个黑色到的点。那么这个矩阵会是什么样子的呢?

11111111(B) 11111111(G) 11111111(R) 11111111(B) 11111111(G) 11111111(R) 11111111(B) 11111111(G) 11111111(R) 11111111(B) 11111111(G) 11111111(R)
11111111(B) 11111111(G) 11111111(R) 00000000(B) 00000000(G) 00000000(R) 11111111(B) 11111111(G) 11111111(R) 11111111(B) 11111111(G) 11111111(R)
11111111(B) 11111111(G) 11111111(R) 00000000(B) 00000000(G) 00000000(R) 11111111(B) 11111111(G) 11111111(R) 11111111(B) 11111111(G) 11111111(R)
11111111(B) 11111111(G) 11111111(R) 11111111(B) 11111111(G) 11111111(R) 11111111(B) 11111111(G) 11111111(R) 11111111(B) 11111111(G) 11111111(R)
————————————————
如何从背景中找到黑色的点呢?可能说循环一下找到三个0x00就不是一个黑点吗?那如果这个矩阵背景不是全部是1呢?如果我们不知道前景是黑色呢?这里就需要检测出前景了。

样本
如果背景是固定不变的,我们可以找到一张背景图做样本,如果背景会有变化,可以从码流选择一个我们认为可行的背景,来作为样本。例如后一帧和前一帧比较的前景是什么?或者后30帧和前一帧比较前景是什么。这样我们就可以在动态的码流中找到一些变化。

帧差法检测前景
因为最近项目用到了,我就写下来记录一下过程,其中用到的类库是Opencv,编程语言则是C++。

前面解释了那么多,好了直接上代码吧
————————————————
cv::Mat src1,src2; //假设这两个是两个合适时段的原图片
      //我们要从这两个原图中找到前景
cv::Mat dst1,dst2;

//首先做一个灰度处理
cv::cvtColor(src1,dst1,CV_BGR2GRAY);
cv::cvtColor(src2,dst2,CV_BGR2GRAY);

//高斯滤波
cv::GaussianBlur(dst1,dst1,cv::Size(3,3),0);
cv::GaussianBlur(dst2,dst2,cv::Size(3,3),0);

//两张图做差
cv::Mat diff_image;
cv::absdiff(dst1,dst2,diff_image);

//给帧差后的图做一个阈值限定,如下超过35阈值的即R+G+B>35的像素改为255,其他改为0
//这一操作为最后一个参数控制 cv::THRESH_BINART
cv::threshold(diff_image,diff_image,35,255,cv::THRESH_BINARY);

//创建一个28*28的核 
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE,cv::Size(28,28));
cv::erode(diff_image,diff_image,(3,3),cv::Point(-1,-1),2); //腐蚀
cv::dilate(diff_image,diff_image,kernel,cv::Pint(-1,-1),2); //膨胀

//将我们处理好的图片的边界找到,会形成多个不规则的点集
std::vector<std::vector<cv::Point>> contours;
cv::findContours(roi_diff,contours,cv::RETR_EXTERNAL,cv::CHAIN_APPROX_SIMPLE);

//其实这里已经找到了前景的区域了,只需要你去区分一下这些点集围成的区域哪个是前景。
//可以使用boundingRect来将点集使用一个最小矩型来框出来
cv::Rect rect = cv::boundingRect(contours[0]);
版权声明:本文为CSDN博主「要努力闪光的人」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/tayuC/article/details/90515760

全部评论