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

Posted

技术标签:

【中文标题】OpenCV比较两个图像并获得不同的像素【英文标题】:OpenCV compare two images and get different pixels 【发布时间】:2010-12-28 23:53:43 【问题描述】:

由于某种原因,下面的代码不起作用。我有两张 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 存储的是当前图像。

【问题讨论】:

【参考方案1】:
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!

【讨论】:

【参考方案2】:

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

您可能打算按照以下方式做某事:

...
//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

【讨论】:

你可能是对的。但是我仍然一直得到相同的数字:3626。我认为我如何将上一个图像存储在 lastFIplImageHeader 中存在一些问题。 我会在晚上试一试,告诉你进展如何。我现在没有太多时间(我在工作)。

以上是关于OpenCV比较两个图像并获得不同的像素的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV与EmguCV中的图像轮廓提取

S0.2 灰度图

opencv标定板像素尺寸

如何使用opencv从图像中删除小的彩色像素

android opencv 如何获得特定像素点的颜色

【OPENCV】cv::Mat像素遍历方法比较