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

how to check whether two matrices are identical in OpenCV

本文关键字:两个 是否 OpenCV 检查      更新时间:2023-10-16

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

正如Acme所提到的,您可以使用cv::compare,尽管它并不像您希望的那样干净
在以下示例中,使用!=运算符调用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) == Scalar(0,0,0,0);

如果你知道类型,你可以使用STL相等函数。Mat迭代器处理数据不连续的情况,并且可以为多通道矩阵使用向量类型。

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

编辑:已更新以处理多通道案例

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

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

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

使用单个函数的另一种方法是使用:

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

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

参考:OpenCV规范

这是我用来比较通用(不取决于元素的维度或类型)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根据这个实现没有运算符==

将cv::compare与cv::countNonZero结合使用。

一个SO问题可能有助于您进一步OpenCV比较两个图像并获得不同的像素

正如Acme和Tim所提到的,您可以使用cv::compare。这是我用来比较cv::Mat:的代码

 bool matIsEqual(const cv::Mat mat1, const cv::Mat mat2){
    // treat two empty mat as identical as well
    if (mat1.empty() && mat2.empty()) {
        return true;
    }
    // if dimensionality of two mat is not identical, these two mat is not identical
    if (mat1.cols != mat2.cols || mat1.rows != mat2.rows || mat1.dims != mat2.dims) {
        return false;
    }
    cv::Mat diff;
    cv::compare(mat1, mat2, diff, cv::CMP_NE);
    int nz = cv::countNonZero(diff);
    return nz==0;
}

需要注意的是,函数cv::countNonZero仅适用于一个通道的cv::Mat,因此,如果您需要比较两个cv::Mat图像,您需要首先以这种方式转换cv::Mat

Mat gray1, gray2;
cvtColor(InputMat1, gray1, CV_BGR2GRAY);
cvtColor(InputMat2, gray2, CV_BGR2GRAY);

其中InputMat1InputMat2是要比较的cv::Mat。之后,您可以调用函数:

bool equal = matsEqual(gray1, gray2);

我拿了这个网站的代码:OpenCV:比较两个Mat是否相同

我希望这对你有帮助。

我使用这个:

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仅与一个信道的cv::Mat一起工作。这太夸张了,但在这种情况下,可以使用cv::split将每个通道分割成单独的图像,并对其执行cv::countNonZero

对于多通道图像,您可以使用cv::Mat::整形来创建单个通道图像,而无需任何额外开销。

安东尼奥的答案更新为

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)));
}

使用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;
}
bool matIsEqual(const cv::Mat &m1, const cv::Mat &m2)
{
    if(m1.type() != m2.type())
        return false;
    if(m1.size() != m2.size())
        return false;
    return std::equal(m1.begin<uchar>(), m1.end<uchar>(), m2.begin<uchar>());
}
相关文章: