OpenCV比较两个图像并获得不同的像素

时间:2010-12-28 23:53:43

标签: c++ opencv

出于某种原因,下面的代码不起作用。我有两张640 * 480的图像非常相似但不一样(至少几百/千像素应该不同)。

这是我比较它们和计算不同像素的方式:

unsigned char* row;
unsigned char* row2;
int count = 0;

// this happens in a loop
// fIplImageHeader is current image
// lastFIplImageHeader is image from previous iteration
if ( NULL != lastFIplImageHeader->imageData ) {
for( int y = 0; y < fIplImageHeader->height; y++ )
{
    row = &CV_IMAGE_ELEM( fIplImageHeader, unsigned char, y, 0 );
    row2 = &CV_IMAGE_ELEM( lastFIplImageHeader, unsigned char, y, 0 );
    for( int x = 0; x < fIplImageHeader->width*fIplImageHeader->nChannels; x += fIplImageHeader->nChannels )
    {
        if(row[x] != row2[x] || row[x+1] != row2[x+1] || row[x+2] != row2[x+2])
            count++;
        }
    }
}
}

现在最后我得到了3626号,这似乎没问题。

但是,我尝试打开MS Paint中的一个图像并在其上绘制粗红线,这应该会大幅增加不同像素的数量。我又得到了相同的号码:3626。

显然我在这里做错了。

我正在循环比较这些图像。

这一行在循环之前:

IplImage* lastFIplImageHeader = cvCreateImageHeader(cvSize(640, 480), 8, 3);

然后在循环中我加载这样的图像:

IplImage* fIplImageHeader = cvLoadImage( filePath.c_str() );

// here I compare the pixels (the first code snippet)

lastFIplImageHeader->imageData = fIplImageHeader->imageData;

所以lastFIplImageHeader存储上一次迭代的图像,fIplImageHeader存储当前图像。

2 个答案:

答案 0 :(得分:9)

int count_diff_pixels(cv::Mat in1, cv::Mat in2) {
    cv::Mat diff;
    cv::compare(in1, in2, diff, cv::CMP_NE);
    return cv::countNonZero(diff);
}

可能需要一些调整,但这是关于你如何做到的。另外,如果你真的使用c ++,你不应该搞乱cv *。使用新的c ++界面,不用担心释放图像。阅读图像,记住前一个图像就像

一样简单
cv::Mat prev;
while (...) {
    cv::Mat current = cv::imread(fn); // or whereever your image comes from
    // ... do something ...
    prev = current;
} // automatic memory management!

答案 1 :(得分:5)

在我看来,你不计算不同的像素,甚至根本不计算像素 您正在计算第一个图像中一个像素的颜色通道与另一个图像中相应像素的通道匹配的频率。

你可能打算按照以下方式做点什么:

...
//in the inner for loop
if(row[x] != row2[x] || row[x+1] != row2[x+1] || row[x+2] != row2[x+2])
  count++;
...

然而,这将不考虑alpha通道(如果存在),并且将在灰度图像上失败,因为您可能读出数据数组的边界。

修改 只要你不释放旧图像就应该没问题。但是,做一些类似的事情可能会更好:

//make sure size and channels are correct.
//If unsure, load the image first and then create with the parameters taken from the loaded image.
cvCreateImage(cvSize(640, 480), 8, 3);

//use cvCopy to copy the contents and proceed as normal
cvCopy(fIplImageHeader , lastFIplImageHeader);

或者,您可以只握住指向旧图像的指针,而不是复制,只要您不释放它。

lastFIplImageHeader = fIplImageHeader;
fIplImageHeader = cvLoadImage( filePath.c_str() );

EDIT2 :如果您想要的只是差异,可以查看cvSub(两个图片都加载为灰度),然后是cvCountNonZero