您的位置:首页 > 其它

运动图像分割

2016-01-12 20:11 381 查看


简介

  最近在继续看《数字图像处理》,发现上面一个分割运动图像的案例,用简单的代码实现,并整理了出来。


原理介绍

  该方式主要是用在监控上面,用来处理在监控画面中运动的物体。原理可以大致为比较同一位置拍摄的两张图片之间各个像素像素差,根据像素差
大小来判断是否该位置为移动物体:
  具体公式如下:


  书中的具体效果如下:


  注意:该方式局限性比较大,被处理的拍摄图像最好是保持相对光照恒定和做了图像配准的。


实现


具体代码


#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处理,最后将原图片,结果图片和两张掩码图片都显示出来。

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。然后根据之前公式,分别对比两张运动图像和模板图像的差异,并将结果保存在两张掩码图片中。

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、对两个掩码结果做连通域分割处理。

cvSegmentFGMask(&ipImask1);
cvSegmentFGMask(&ipImask2);

  4、利用处理后的掩码图像,分别将两张运动图像的运动物体,都复制到模板图片中去,形成结果图像。

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                      结果图像
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: