Enregistrer une image avec imwrite dans opencv écrit tous les noirs mais imshow montre correctement

Question originale

Cet exemple de code affichera l’image créée correctement, mais enregistrera un png avec uniquement des pixels noirs. Le tapis est au format CV_32FC3, donc 3 canaux de flotteurs.

Les réponses aux questions que j’ai trouvées portent sur des problèmes de manipulation d’image, de conversion incorrecte ou d’enregistrement au format JPEG avec diverses compressions.

#include "opencv2/highgui/highgui.hpp" #include  using namespace std; using namespace cv; int main() { int i = 0; int j = 0; Vec3f intensity; cv::Mat imageF; imageF= cv::Mat::zeros(36,36,CV_32FC3); for(j=0;j<imageF.cols;++j){ for(i=0;i<imageF.rows;++i){ intensity = imageF.at(j, i); intensity.val[2] = 0.789347; intensity.val[1] = 0.772673; intensity.val[0] = 0.692689; imageF.at(j, i) = intensity; }} imshow("Output", imageF); imwrite("test.png", imageF); waitKey(0); return 0; } 

Quels changements faut-il apporter pour le sauvegarder comme prévu?

La solution de Berriel

 #include "opencv2/highgui/highgui.hpp" #include  using namespace std; using namespace cv; int main() { int i = 0; int j = 0; Vec3f intensity; cv::Mat imageF; cv::Mat image; imageF= cv::Mat::zeros(36,36,CV_32FC3); for(j=0; j<imageF.cols; ++j) { for(i=0; i<imageF.rows; ++i) { intensity = imageF.at(j, i); intensity.val[2] = 0.789347; intensity.val[1] = 0.772673; intensity.val[0] = 0.692689; imageF.at(j, i) = intensity; } } imshow("Output", imageF); Mat3b imageF_8UC3; imageF.convertTo(imageF_8UC3, CV_8UC3, 255); imwrite("test.png", imageF_8UC3); waitKey(0); return 0; } 

Comme vous pouvez le lire dans la documentation :

La fonction imwrite enregistre l’image dans le fichier spécifié. Le format de l’image est choisi en fonction de l’extension du nom de fichier (voir imread () pour la liste des extensions). Seules les images à un canal ou à trois canaux (avec l’ordre de canal ‘BGR’) de 8 bits (ou de 16 bits non signés (CV_16U) en cas de format PNG, JPEG 2000 et TIFF) peuvent être enregistrées à l’aide de cette fonction. Si le format, la profondeur ou l’ordre des canaux est différent, utilisez Mat :: convertTo () et cvtColor () pour le convertir avant de l’enregistrer.

Vous devriez utiliser convertTo pour convertir de CV_32FC3 en CV_8UC3 pour obtenir le même résultat:

 Mat3b imageF_8UC3; imageF.convertTo(imageF_8UC3, CV_8UC3, 255); imwrite("test.png", imageF_8UC3); 

Au fait, imshow() s’affiche correctement car …

  • Si l’image est non signée sur 8 bits, elle est affichée telle quelle.
  • Si l’image est un entier non signé de 16 bits ou un entier de 32 bits, les pixels sont divisés par 256. En d’autres termes, la plage de valeurs [0,255 * 256] est mappée à [0,255].
  • Si l’image est une virgule flottante de 32 bits, les valeurs de pixel sont multipliées par 255. En d’autres termes, la plage de valeurs [0,1] est mappée sur [0,255].

Fondamentalement, le même truc est ce que vous devez faire avant d’écrire.