2012-03-28 14 views

Respuesta

41

Según lo mencionado por Acme, puede utilizar cv::compare aunque no es tan limpia como se podría esperar.
En el siguiente ejemplo, se llama cv::compare utilizando el != operator:

// 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; 

Es de suponer que sería más rápido para recorrer simplemente mediante la comparación de los elementos sin embargo? Si conoce el tipo que usted podría utilizar la función STL equal:

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

'bool eq = cv :: countNonZero (a! = B) == 0;'. Creo que esto es razonablemente limpio. Lo más molesto es que tienes que invertir el operador de comparación en comparación con lo que realmente quieres saber ('! =' En lugar de '==') ya que no hay función 'countZero()'. – nobar

+3

El cv :: Mat puede o no ser continuo, no estoy seguro de que el relleno de bytes por cada fila tenga el mismo valor. – StereoMatching

+3

Sí, pero creo que los iteradores Mat se encargan de esto por usted? http://docs.opencv.org/modules/core/doc/basic_structures.html#mat-begin –

1

Como se ha mencionado por Acme y Tim, puede utilizar cv::compare. Este es el código que utilizo para comparar mi 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; 
} 

Es importante resaltar que la función cv::countNonZero only works with cv::Mat of one channel, por lo que si es necesario comparar dos cv::Mat imágenes, primero se necesita para convertir su cv::Mat de esta manera:

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

donde InputMat1 y InputMat2 son el cv::Mat desea comparar. Después de que se puede llamar a la función:

bool equal = matsEqual(gray1, gray2); 

Tomé el código de este sitio: OpenCV: compare whether two Mat is identical

espero que esto ayude.

+2

Al convertir las imágenes a escala de grises, pierde información y es posible que cree imágenes idénticas de 2 colores originalmente diferentes. – Antonio

1

Este es el código que utilizo para comparar genérica (no en función de las dimensiones o tipo de elementos) cv::Mat casos:

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

No entiendo, ¿por qué cv::Mat no tiene un operador == de acuerdo con este implementación.

1

Puedo usar este:

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

Si usted tiene que hacer esta operación varias veces, usted puede hacer esto en una clase, tienen temp como miembro y evitar que la imagen que se asignarán cada vez. Detalle: make temp mutable para que areEqual pueda ser un método const.

Tenga en cuenta que cv::countNonZero only works with cv::Mat of one channel. Es exagerado, pero en ese caso uno podría usar cv::split para dividir cada canal en imágenes separadas y hacer cv::countNonZero en ellas.

8

El siguiente funcionará también para matrices de múltiples canales:

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

Desde sum acepta matrices con 1 a 4 canales, y devuelve un Scalar, donde el elemento en [0] es el resultado de la suma para el primer canal, y así sucesivamente.

0

Otra forma utilizando una única función sería utilizar:

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

Desde norma L1 se calcula como ∑I|img1(I)−img2(I)|

referencia: OpenCV norm

Cuestiones relacionadas