Copie intégrale du cv OpenCV:: Mat

le comportement de la copie cv::Mat est source de confusion pour moi.

ce que je comprends de la documentation Mat::copyTo() copie en profondeur alors que l'opérateur d'affectation n'est pas. Mes questions:

  1. que dois-je faire pour retourner un cv::Mat à partir d'une fonction, par exemple: <!--5?

  2. d'Après la documentation, si je retourne un cv::Mat il n'aura pas d'utilité, car après que la fonction renvoie la copie locale du cv::Mat dans cette fonction sera détruit et donc celui qui accepte la valeur retournée en dehors de la fonction devrait pointer vers une adresse aléatoire. La chose étrange est que (la plupart du temps), il fonctionne correctement. Par exemple, les ouvrages suivants:

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

Mais pourquoi? Ce n'est pas une copie en profondeur.

Question 3. Et aussi parfois l'opérateur de tâche semble être copie profonde, aussi:

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

puis les deux affichages montrent la même image, a.jpg. Pourquoi? Et certains d'autres fois, il ne fonctionne pas. (Le code original est trop long mais il peut aussi être simplifié au cas ci-dessus). En ces temps-là, l'opérateur de tâche semble être en fait une copie "superficielle". Pourquoi?

Merci beaucoup!

19
demandé sur flyinggip 2014-02-09 17:18:22

3 réponses

je pense que l'utilisation de assignations n'est pas la meilleure façon de copier matrix. Si vous voulez de nouvelles copie complète de la matrice, utilisation:

Mat a=b.clone(); 

si vous voulez copier la matrice pour remplacer les données d'une autre matrice (pour éviter la réallocation de la mémoire) utilisez:

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

lorsque vous assignez une matrice à enother, le compteur de références du pointeur intelligent vers les données de matrice augmente de un, lorsque vous libérez matrix (cela peut être fait implicitement lorsque vous laissez le bloc de code) il diminue de un. Quand il devient égal zéro la mémoire allouée désalacée.

si vous voulez obtenir le résultat de la fonction utiliser des références, il est plus rapide:

void Func(Mat& input,Mat& output)
{
 somefunc(input,output);
}

int main(void)
{
...
  Mat a=Mat(.....);
  Mat b=Mat(.....);
  Func(a,b);
...
}
18
répondu Andrey Smorodov 2014-02-09 14:05:53

J'utilise OpenCV depuis un moment maintenant et le cv:: Mat m'a embrouillé aussi, donc j'ai fait un peu de lecture.

cv:: Mat est un en-tête qui pointe vers un pointeur de données *qui contient les données réelles de l'image. Il met également en œuvre le comptage de référence. il contient le nombre de cv::Mat headers pointant actuellement vers ce *pointeur de données. Ainsi, lorsque vous faites une copie régulière comme:

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

a point b sera décrémenté (et la mémoire sera libérée si elle est de 0 après décrémentation).

Question 1: Cela dépend de votre programme. Veuillez vous référer à cette question pour plus de détails: est-cvmat-classe-imparfait de par sa conception

Question 2: la fonction retourne par valeur. Que signifie return image va copier le tapis et augmenter le nombre de références(maintenant ref_count = 2) et retourner le nouveau tapis. Lorsque l' fin de la fonction, l'image sera détruite et ref_count sera réduit d'un. Mais la mémoire ne sera pas libérée puisque le ref_count n'est pas 0. Donc le cv retourné:: Mat ne pointe pas vers un emplacement de mémoire aléatoire.

Question 3: une chose semblable se produit. Quand vous dites orgImage2.copyTo(aCopy); Le ref_count pour les données pointées par aCopy sera diminué. Puis de nouveau la mémoire est allouée pour stocker les nouvelles données seront copiées. C'est pourquoi copyCopy1 n'a pas modifié lorsque vous avez fait cela.

4
répondu Indika Pathi 2017-05-23 12:09:44

jetez un coup d'oeil à c++11 std:: shared_ptr fonctionne effectivement de la même manière, en utilisant un compteur de référence cv::Mat se souvient habilement de chaque fois que le pointeur est référencé, une fois que le nombre atteint 0 Il est automatiquement libéré, c'est-à-dire que la mémoire est désallocée et cv::Mat n'est plus disponible. C'est effectivement une "copie" et permet d'économiser des ressources dans l'allocation/désallocation de grandes quantités de mémoire.

d'un autre côté cv:: Mat:: clone fournira une "copie profonde" que affecte un nouveau bloc de mémoire pour que la matrice réside, cela peut être utile si vous faites des transformations à une image que vous pourriez vouloir défaire cependant, plus de mémoire allouant/désalloquant augmente la quantité de ressources nécessaires.

Espérons que cela aide quelqu'un.

2
répondu user3102241 2015-08-04 17:42:06