Подтвердить что ты не робот

Как проверить, идентичны ли две матрицы в OpenCV

У меня есть два экземпляра cv:: Mat: m1 и m2. Они имеют один и тот же числовой тип и размеры. Есть ли какая-либо функция в OpenCV, которая возвращает, идентичны ли матрицы (имеют все одинаковые значения)?

4b9b3361

Ответ 1

Как уже упоминалось в 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) == 0;

Предположительно, было бы быстрее просто пройтись по сравнению элементов, хотя? Если вы знаете тип, вы можете использовать функцию равенства STL:

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

Ответ 2

Следующее будет работать и для многоканальных матриц:

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

Так как sum принимает матрицы с 1 по 4 канала и возвращает a Scalar, где элемент в [0] является результатом суммы для первый канал и т.д.

Ответ 4

Как упоминалось Acme и Tim, вы можете использовать cv::compare. Это код, который я использую для сравнения my 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);

где InputMat1 и InputMat2 - это cv::Mat, которые вы хотите сравнить. После этого вы можете вызвать функцию:

bool equal = matsEqual(gray1, gray2);

Я взял этот код этого сайта: OpenCV: сравните, совпадает ли два Mat

Надеюсь, это поможет вам.

Ответ 5

Я использую это:

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 на них.

Ответ 6

Другим способом, использующим одну функцию, будет использование:

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

Так как норма L1 вычисляется как ∑I|img1(I)−img2(I)|

ссылка: норма OpenCV

Ответ 7

Это код, который я использую для сравнения общего (не зависит от размеров или типа элементов) 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 не имеет оператора == в соответствии с этой реализацией.