2014-05-17 6 views
1

Je souhaite convertir un graphique SVG en objet OpenCV Mat. Par conséquent, le graphique SVG est chargé dans un objet QSvgRenderer et transformé ensuite en un objet QImage dont j'utilise ses données brutes pour créer mon objet final Mat:Conversion de QImage en cv :: Mat en utilisant des données brutes

void scaleSvg(const cv::Mat &in, QSvgRenderer &svg, cv::Mat &out) 
{ 
    if (!svg.isValid()) 
    { 
      return; 
    } 

    QImage image(in.cols, in.rows, QImage::Format_ARGB32); 

    // Get QPainter that paints to the image 
    QPainter painter(&image); 
    svg.render(&painter); 

    std::cout << "Image byte count: " << image.byteCount() << std::endl; 
    std::cout << "Image bits: " << (int*)image.constBits() << std::endl; 
    std::cout << "Image depth: " << image.depth() << std::endl; 

    uchar *data = new uchar[image.byteCount()]; 
    memcpy(data, image.constBits(), image.byteCount()); 

    out = cv::Mat(image.height(), image.width(), CV_8UC4, data, CV_AUTOSTEP); 
    std::cout << "New byte count: " << out.size() << std::endl; 
    std::cout << "New depth: " << out.depth() << std::endl; 
    std::cout << "First bit: " << out.data[0] << std::endl; 
} 

Malheureusement, je reçois une erreur « violation d'accès mémoire » lorsque l'écriture de mon objet résultant dans un fichier:

std::cout << (int*)out.data << std::endl; // pointer can still be accessed without errors 
cv::imwrite("scaled.png", out); // memory access error 

Le fichier qui est en cours d'écriture arrive à à la taille de 33 octets non plus (données d'en-tête seulement ??). Sur Internet, il y a quelques explications sur la propriété du pointeur dans cv :: Mat et je pensais qu'il serait publié après la dernière référence à la publication, ce qui ne devrait pas être le cas puisque "out" est une référence. Btw. une autre façon de convertir un SVG en un cv :: Mat est toujours la bienvenue. Comme OpenCV semble ne pas supporter les SVG, cela a semblé être un moyen simple de le faire.

Répondre

2

Comme constBits ne fonctionne pas bien et il est pas toujours sûr de supposer que le nombre d'octets par ligne sera le même (il provoque une erreur de segmentation pour moi). J'ai trouvé la suggestion suivante dans StereoMatching's anwser:

cv::Mat(img.height(), img.width(), CV_8UC4, img.bits(), img.bytesPerLine()).clone() 

préoccupation de Barade sur l'utilisation des bits est valide, mais parce que vous cloner le résultat le Mat copie les données à partir de bits, donc il ne sera pas un problème.

0

habituellement, cv :: Mat est refcounted, mais ce cas est spécial. si vous utilisez un pointeur de données externe/emprunté, vous devrez cloner() le mat, pour vous assurer qu'il possède sa propre copie des pixels, sinon, dès que vous quittez la portée de 'scaleSvg()', le Mat 'out' contient un 'pointeur qui pend.'

vous avez essayé de 'nouveau' les données à copier, malheureusement, cela ne le résout pas (vous y avez seulement ajouté un autre problème). Vous devrez également supprimer [] les pixels de données uchar * sur vous-même, et vous ne le faites pas, donc votre code combine actuellement le pire de tous les mondes.

Essayez plutôt:

out = cv::Mat(image.height(), image.width(), CV_8UC4, image.constBits(), CV_AUTOSTEP).clone(); 
+0

merci pour la réponse, mais cela ne fonctionne pas de cette façon. constBits() ne peut pas être utilisé car il renvoie un pointeur const. Quand j'utilise bits() qui me semble incorrect puisque la destruction de cv :: Mat libérera probablement bits() si elle utilise un mécanisme de comptage de référence (peut-être que je me trompe), l'erreur de mappage mémoire se produit même dans l'instruction pas après. –

Questions connexes