convertto c++ opencv deep-copy

c++ - convertto - row opencv



Copia profunda de OpenCV cv:: Mat (3)

Creo que usar la asignación no es la mejor manera de copiar la matriz. Si quiere una nueva copia completa de la matriz, use:

Mat a=b.clone();

Si desea copiar la matriz para reemplazar los datos de otra matriz (para evitar la reasignación de memoria) use:

Mat a(b.size(),b.type()); b.copyTo(a);

Cuando asigna una matriz a enother, el contador de referencias de puntero inteligente a los datos de la matriz aumenta en uno, cuando suelta la matriz (se puede hacer implícitamente al dejar el bloque de código) disminuye en uno. Cuando se vuelve igual a cero, se asigna la memoria asignada.

Si desea obtener el resultado de la función usar referencias, es más rápido:

void Func(Mat& input,Mat& output) { somefunc(input,output); } int main(void) { ... Mat a=Mat(.....); Mat b=Mat(.....); Func(a,b); ... }

El comportamiento de copiar cv::Mat me confunde.

Mat::copyTo() la documentación, entiendo que Mat::copyTo() es una copia profunda, mientras que el operador de asignación no lo es. Mis preguntas:

  1. ¿Qué debo hacer para devolver un cv::Mat de una función, como por ejemplo: cv::Mat func() ?

  2. De acuerdo con la documentación, si devuelvo un cv::Mat no tendrá uso, porque después de que la función retorne se destruirá la copia local de cv::Mat en esa función y, por lo tanto, la que acepta el valor devuelto fuera del la función debería estar apuntando a alguna dirección aleatoria. Lo extraño es que (la mayoría de las veces) funciona correctamente. Por ejemplo, los siguientes trabajos:

    cv::Mat CopyOneImage(const cv::Mat& orgImage) { cv::Mat image; orgImage.copyTo(image); return image; } int main() { std::string orgImgName("a.jpg"); cv::Mat orgImage; orgImage = cv::imread(orgImgName); cv::Mat aCopy; aCopy = CopyOneImage(orgImage); return 1; }

¿Pero por qué? No es una copia profunda.

Pregunta 3. Y también a veces el operador de asignación parece ser una copia profunda también:

int main() { std::string orgImgName("a.jpg"); cv::Mat orgImage; orgImage = cv::imread(orgImgName); cv::Mat aCopy; orgImage.copyTo(aCopy); cv::Mat copyCopy1; copyCopy1 = aCopy; cv::namedWindow("smallTest", 1); cv::imshow("smallTest", copyCopy1); uchar key = (uchar)cv::waitKey(); cv::Mat orgImage2 = cv::imread("b.jpg"); orgImage2.copyTo(aCopy); cv::imshow("smallTest", copyCopy1); return 1; }

Luego, las dos pantallas muestran la misma imagen, a.jpg. ¿Por qué? Y otras veces no funciona. (El código original es demasiado largo, pero también se puede simplificar al caso anterior). En esos momentos, el operador de asignación parece ser en realidad una copia "poco profunda". ¿Por qué?

¡Muchas gracias!


Eche un vistazo a c ++ 11 std :: shared_ptr efectivamente funciona de la misma manera, usando un contador de referencias cv :: Mat recuerda ingeniosamente cada vez que se hace referencia al puntero, una vez que el conteo llega a 0 se libera automáticamente, es decir, la memoria se desasigna y cv :: Mat ya no está disponible. Esto es efectivamente una "copia superficial" y ahorra recursos en la asignación / desasignación de grandes cantidades de memoria.

Por otro lado, cv :: Mat :: clone proporcionará una "copia profunda" que asigna un nuevo bloque de memoria para que resida la matriz, esto puede ser útil si está realizando transformaciones en una imagen que puede querer deshacer, sin embargo, más asignación / desasignación de memoria aumenta la cantidad de recursos requeridos.

Espero que esto ayude a alguien.


He estado usando OpenCV por un tiempo y el cv :: Mat me confundió también, así que leí algo.

cv :: Mat es un encabezado que apunta a un * puntero de datos que contiene los datos de la imagen real. También implementa el recuento de referencias. contiene la cantidad de encabezados cv::Mat apuntando a ese * puntero de datos. Entonces cuando haces una copia regular como:

cv::Mat b; cv::Mat a = b;

a apuntará a los datos de b y se incrementará el recuento de referencia para él. Al mismo tiempo, el recuento de referencias para los datos apuntados anteriormente por b reducirá (y la memoria se liberará si es 0 después de decrementar).

Pregunta 1: Depende de tu programa. Consulte esta pregunta para obtener más información: is-cvmat-class-fault-by-design

Pregunta 2: la función regresa por valor. Eso significa que la return image copiará el Mat y aumentará el recuento de ref (ahora ref_count = 2) y devolverá el nuevo Mat. Cuando la función finaliza, la imagen se destruirá y ref_count se reducirá en uno. Pero la memoria no se liberará ya que ref_count no es 0. Entonces, el cv :: Mat devuelto no apunta a la ubicación de la memoria aleatoria.

Pregunta 3: sucede algo similar. Cuando dices orgImage2.copyTo(aCopy); El ref_count para los datos apuntados por aCopy disminuirá. A continuación, se asigna nueva memoria para almacenar los datos nuevos que se copiarán. Entonces, es por eso que copyCopy1 no se modificó cuando hiciste esto.