如何检查OpenCV中两个矩阵是否相同

时间:2012-03-28 09:54:19

标签: c++ opencv

我有两个cv :: Mat实例:m1和m2。它们具有相同的数字类型和大小。 OpenCV中是否有任何函数返回矩阵是否相同(具有所有相同的值)?

8 个答案:

答案 0 :(得分:44)

正如Acme所提到的,你可以使用cv::compare,尽管它并不像你希望的那样干净 在以下示例中,使用!= operator

调用cv::compare
// Get a matrix with non-zero values at points where the 
// two matrices have different values
cv::Mat diff = a != b;
// Equal if no elements disagree
bool eq = cv::countNonZero(diff) == 0;

据推测,通过比较元素迭代会更快吗?如果您知道类型,则可以使用STL equal函数:

bool eq = std::equal(a.begin<uchar>(), a.end<uchar>(), b.begin<uchar>());

答案 1 :(得分:12)

以下内容也适用于多通道矩阵:

bool isEqual = (sum(img1 != img2) == Scalar(0,0,0,0));

由于sum接受具有1到4个通道的矩阵,并返回Scalar,其中[0]处的元素是第一个通道的总和的结果,依此类推。

答案 2 :(得分:7)

cv::comparecv::countNonZero结合使用。

一个可以帮助您进一步帮助您的问题OpenCV compare two images and get different pixels

答案 3 :(得分:3)

我用这个:

bool areEqual(const cv::Mat& a, const cv::Mat& b) {
    cv::Mat temp;
    cv::bitwise_xor(a,b,temp); //It vectorizes well with SSE/NEON
    return !(cv::countNonZero(temp) );
}

如果您必须多次执行此操作,可以将其设置为一个类,将temp作为成员,并防止每次都分配图像。详细信息:使temp变为可变,以便areEqual可以是const方法。

请注意cv::countNonZero only works with cv::Mat of one channel。它有点矫枉过正,但在这种情况下,可以使用cv::split将每个频道拆分为单独的图片并对其进行cv::countNonZero

答案 4 :(得分:3)

使用单一功能的另一种方法是使用:

bool areIdentical = !cv::norm(img1,img2,NORM_L1);

由于L1范数计算为∑I|img1(I)−img2(I)|

参考:OpenCV norm

答案 5 :(得分:1)

这是我用来比较通用的代码(不依赖于元素的维度或类型)cv::Mat实例:

bool matIsEqual(const cv::Mat Mat1, const cv::Mat Mat2)
{
  if( Mat1.dims == Mat2.dims && 
    Mat1.size == Mat2.size && 
    Mat1.elemSize() == Mat2.elemSize())
  {
    if( Mat1.isContinuous() && Mat2.isContinuous())
    {
      return 0==memcmp( Mat1.ptr(), Mat2.ptr(), Mat1.total()*Mat1.elemSize());
    }
    else
    {
      const cv::Mat* arrays[] = {&Mat1, &Mat2, 0};
      uchar* ptrs[2];
      cv::NAryMatIterator it( arrays, ptrs, 2);
      for(unsigned int p = 0; p < it.nplanes; p++, ++it)
        if( 0!=memcmp( it.ptrs[0], it.ptrs[1], it.size*Mat1.elemSize()) )
          return false;

      return true;
    }
  }

  return false;
}

我不明白,为什么cv::Mat根据此实现没有运算符==

答案 6 :(得分:0)

使用cv::countNonZero的问题在于此功能仅适用于单通道图像。如果要使用多通道图像,则必须分别照顾每个通道。第一步是将图像分成多个通道。正如Antonio所解释的,您可以为此使用cv::split函数。拆分后,您可以为每个通道使用cv::countNonZero,并使用迭代对所有通道的结果求和。 cv::Mat::channels为您提供了频道数。

这是我用来检查两个矩阵是否相同的代码。

bool isEqual(cv::Mat firstImage, cv::Mat secondImage){
    cv::Mat dst;
    std::vector<cv::Mat>channels;
    int count = 0;
    cv::bitwise_xor(firstImage, secondImage, dst);
    cv::split(dst, channels);
    for (int ch = 0; ch<dst.channels();ch++){
        count += cv::countNonZero(channels[ch]);
    }
    return count == 0 ? true : false;
}

答案 7 :(得分:0)

对于多通道图像,您可以使用cv::Mat::reshape创建单个通道图像,而不会产生任何额外开销。

将更新Antonio's answer

bool areEqual(const cv::Mat& a, const cv::Mat& b)
{
    cv::Mat temp;
    cv::bitwise_xor(a,b,temp);
    return !(cv::countNonZero(temp.reshape(1)));
}