У меня есть два экземпляра cv:: Mat: m1 и m2. Они имеют один и тот же числовой тип и размеры. Есть ли какая-либо функция в OpenCV, которая возвращает, идентичны ли матрицы (имеют все одинаковые значения)?
Как проверить, идентичны ли две матрицы в OpenCV
Ответ 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] является результатом суммы для первый канал и т.д.
Ответ 3
Используйте cv:: compare в сочетании с cv:: countNonZero.
Вопрос SO, который может помочь вам в дальнейшем OpenCV сравнить два изображения и получить разные пиксели
Ответ 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
не имеет оператора ==
в соответствии с этой реализацией.