OpenCV比较两张图片并获取不同的像素

4

由于某些原因,下面的代码无法正常工作。我有两个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个回答

10
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!

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


你可能是对的。但我一直得到相同的数字:3626。我认为在存储上一个图像的lastFIplImageHeader方面存在问题。 - Richard Knop
我会在晚上尝试并告诉你结果。我现在没有太多时间(我正在工作)。 - Richard Knop

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接