原文地址:http://blog.csdn.net/u011630458/article/details/50506473
简介
最近在继续看《数字图像处理》,发现上面一个分割运动图像的案例,用简单的代码实现,并整理了出来。
原理介绍
该方式主要是用在监控上面,用来处理在监控画面中运动的物体。原理可以大致为比较同一位置拍摄的两张图片之间各个像素像素差,根据像素差
大小来判断是否该位置为移动物体:
具体公式如下:
书中的具体效果如下:
注意:该方式局限性比较大,被处理的拍摄图像最好是保持相对光照恒定和做了图像配准的。
实现
具体代码
[cpp]
view plain
copy
#include <opencv2/opencv.hpp> #include <stdio.h> #include "opencv2/video/background_segm.hpp" #include "opencv2/core/core.hpp" #include "opencv2/video/background_segm.hpp" #include "opencv2/imgproc/imgproc_c.h" #include "opencv2/highgui/highgui.hpp" #include "opencv2/legacy/legacy.hpp" using namespace cv; using namespace std; Mat src1, src2, src3; Mat picMask1, picMask2, dst; int width, height; int curThreshold = 10; int cutSport(void){ int i, j; IplImage ipI1, ipI2, ipI3, ipImask1, ipImask2, ipIdst; CvScalar s1, s2, s3; picMask1 = Mat(width, height, CV_8UC1, cv::Scalar(0,0,0)); picMask2 = Mat(width, height, CV_8UC1, cv::Scalar(0,0,0)); dst = Mat(width, height, CV_8UC1, cv::Scalar(0,0,0)); ipI1 = src1; ipI2 = src2; ipI3 = src3; ipIdst = dst; ipImask1 = picMask1; ipImask2 = picMask2; for(i=1; i<width-1; i++){ for(j=1; j<height-1; j++){ s1 = cvGet2D(&ipI1, i, j); s2 = cvGet2D(&ipI2, i, j); s3 = cvGet2D(&ipI3, i, j); if(abs(s1.val[0] - s3.val[0]) > curThreshold){ s1.val[0] = 255; cvSet2D(&ipImask1, i, j, s1); } if(abs(s2.val[0] - s3.val[0]) > curThreshold){ s1.val[0] = 255; cvSet2D(&ipImask2, i, j, s1); } } } cvSegmentFGMask(&ipImask1); cvSegmentFGMask(&ipImask2); for(i=1; i<width-1; i++){ for(j=1; j<height-1; j++){ s1 = cvGet2D(&ipImask1, i, j); s3 = cvGet2D(&ipI1, i, j); if(s1.val[0] == 255){ s1.val[0] = s3.val[0]; cvSet2D(&ipIdst, i, j, s1); } s2 = cvGet2D(&ipImask2, i, j); s3 = cvGet2D(&ipI2, i, j); if(s2.val[0] == 255){ s2.val[0] = s3.val[0]; cvSet2D(&ipIdst, i, j, s2); } if((s1.val[0] == 0) && (s2.val[0] == 0)){ s1 = cvGet2D(&ipI3, i, j); cvSet2D(&ipIdst, i, j, s1); } } } return 0; } int main(int argc, char* argv[]){ if(argc < 4){ printf("Please input pic1 / pic2 / pic3!\n"); return -1; } src1 = imread(argv[1], 0); src2 = imread(argv[2], 0); src3 = imread(argv[3], 0); height = src1.cols; width = src1.rows; cutSport(); imshow("src1", src1); imshow("src2", src2); imshow("src3", src3); imshow("dst", dst); imshow("mask1", picMask1); imshow("mask2", picMask2); waitKey(0); return 0; }
代码讲解
1、准备三张图片,一张没有运动物体的模板图片,两张运动物体位置不一样的图片。
打开三张图片,并调用函数cutSport处理,最后将原图片,结果图片和两张掩码图片都显示出来。
[cpp]
view plain
copy
src1 = imread(argv[1], 0); src2 = imread(argv[2], 0); src3 = imread(argv[3], 0); height = src1.cols; width = src1.rows; cutSport(); imshow(
"src1", src1); imshow(
"src2", src2); imshow(
"src3", src3); imshow(
"dst", dst); imshow(
"mask1", picMask1); imshow(
"mask2", picMask2);
2、在cutSport函数中,首先创建两张一样大小的掩码图片,像素全部设置为0。然后根据之前公式,分别对比两张运动图像和模板图像的差异,并将结果保存在两张掩码图片中。
[cpp]
view plain
copy
picMask1 = Mat(width, height, CV_8UC1, cv::Scalar(0,0,0)); picMask2 = Mat(width, height, CV_8UC1, cv::Scalar(0,0,0));
for(i=1; i<width-1; i++){
for(j=1; j<height-1; j++){ s1 = cvGet2D(&ipI1, i, j); s2 = cvGet2D(&ipI2, i, j); s3 = cvGet2D(&ipI3, i, j);
if(abs(s1.val[0] - s3.val[0]) > curThreshold){ s1.val[0] = 255; cvSet2D(&ipImask1, i, j, s1); }
if(abs(s2.val[0] - s3.val[0]) > curThreshold){ s1.val[0] = 255; cvSet2D(&ipImask2, i, j, s1); } } }
3、对两个掩码结果做连通域分割处理。
[cpp]
view plain
copy
cvSegmentFGMask(&ipImask1); cvSegmentFGMask(&ipImask2);
4、利用处理后的掩码图像,分别将两张运动图像的运动物体,都复制到模板图片中去,形成结果图像。
[cpp]
view plain
copy
for(i=1; i<width-1; i++){
for(j=1; j<height-1; j++){ s1 = cvGet2D(&ipImask1, i, j); s3 = cvGet2D(&ipI1, i, j);
if(s1.val[0] == 255){ s1.val[0] = s3.val[0]; cvSet2D(&ipIdst, i, j, s1); } s2 = cvGet2D(&ipImask2, i, j); s3 = cvGet2D(&ipI2, i, j);
if(s2.val[0] == 255){ s2.val[0] = s3.val[0]; cvSet2D(&ipIdst, i, j, s2); }
if((s1.val[0] == 0) && (s2.val[0] == 0)){ s1 = cvGet2D(&ipI3, i, j); cvSet2D(&ipIdst, i, j, s1); } } }
结果显示
显示的结果如下:
模板图像 运动图像1 运动图像2
掩码图像1 掩码图像2 结果图像
转载请注明原文地址: https://ju.6miu.com/read-1307540.html