OpenCV utilisant cvImageCreate () avec une image en niveaux de gris échoue et le redimensionnement échoue généralement

J’ai un tel code qui charge une image en niveaux de gris depuis un tampon de 1 octet, bitmap 8 bits. Ensuite, il redimensionne cette image.

int resizeBitmap(const unsigned char *inData, const size_t inDataLength, const size_t inWidth, const size_t inHeight, const int bitDepth, const int noOfChannels, unsigned char **outData, size_t *outDataLength, const size_t outWidth, const size_t outHeight) { // create input image IplImage *inImage = cvCreateImage(cvSize(inWidth, inHeight), bitDepth, noOfChannels); cvSetData(inImage, inData, inImage->widthStep); // show input image cvNamedWindow("OpenCV Input Image", CV_WINDOW_FREERATIO); cvShowImage("OpenCV Input Image", inImage); cvWaitKey(0); cvDestroyWindow("OpenCV Input Image"); /* */ // create output image IplImage *outImage = cvCreateImage(cvSize(outWidth, outHeight), inImage->depth, inImage->nChannels); // select interpolation type double scaleFactor = (((double) outWidth)/inWidth + ((double) outHeight)/inHeight)/2; int interpolation = (scaleFactor > 1.0) ? CV_INTER_LINEAR : CV_INTER_AREA; // resize from input image to output image cvResize(inImage, outImage, interpolation); /* // show output image cvNamedWindow("OpenCV Output Image", CV_WINDOW_FREERATIO); cvShowImage("OpenCV Output Image", outImage); cvWaitKey(0); cvDestroyWindow("OpenCV Output Image"); */ // get raw data from output image int step = 0; CvSize size; cvGetRawData(outImage, outData, &step, &size); *outDataLength = step*size.height; cvReleaseImage(&inImage); cvReleaseImage(&outImage); return 0; } 

J’utilise ici bitDepth = 8 et noOfChannels = 1. L’image chargée est: entrez la description de l'image ici

et le résultat est: entrez la description de l'image ici

cette sortie n’est pas toujours écrite car le programme échoue généralement avec l’erreur:

 OpenCV Error: Bad number of channels (Source image must have 1, 3 or 4 channels) in cvConvertImage, file /tmp/opencv-20160915-26910-go28a5/opencv-2.4.13/modules/highgui/src/utils.cpp, line 611 libc++abi.dylib: terminating with uncaught exception of type cv::Exception: /tmp/opencv-20160915-26910-go28a5/opencv-2.4.13/modules/highgui/src/utils.cpp:611: error: (-15) Source image must have 1, 3 or 4 channels in function cvConvertImage 

J’attache la sortie du débogueur car il y a une situation intéressante car je passe du tampon en niveaux de gris de taille 528480, ce qui équivaut à 1 octet * 1101 * 480, mais après cvCreateImage, il y a à l’intérieur imageSize 529920 et widthStep est 1104! Peut-être que le problème de cette image existe, mais pourquoi?

entrez la description de l'image ici

Ce problème est lié à widthstep et width of IplImage. Opencv remplit l’image pour avoir une largeur de pas multiple de 4 octets. Ici, opencv utilise une largeur de 1101 et une largeur de 1104. Cependant, lorsque vous écrivez des images bitmap sur IplImage, peu de pixels supplémentaires sont écrits par ligne (notez la diagonale de haut en bas à droite).

Notez que l’image n’est pas inclinée. C’est juste que chaque ligne suivante est décalée légèrement vers la gauche (de 3 pixels), donnant ainsi l’idée d’une transformation en cisaillement.

Il est également possible que vous donniez une largeur inférieure à celle de Bitmap.

Voir docs ici et rechercher un rembourrage. Vous pouvez essayer de copier toutes les données de colonne rangées.

Pourquoi planter: Parfois, opencv finira par lire au-delà de la mémoire tampon Bitmap et risque de bash des adresses de mémoire intouchables, provoquant une exception.

Remarque: Bitmap comporte probablement aussi un remplissage à partir duquel vous avez reçu la ligne diagonale noire.

Sur la base de la réponse saurabheights, j’ai écrit la procédure pour faire en sorte que chaque ligne de bitmap soit complétée à n’importe quelle multiplicité d’octets dans la ligne.

 int padBitmap(const unsigned char *data, const size_t dataLength, const size_t width, const size_t height, const int bitDepth, const int noOfChannels, unsigned char **paddedData, size_t *paddedDataLength, const size_t row_multiple) { size_t row_length = (width*noOfChannels*bitDepth)/CHAR_BIT; size_t row_padding_size = row_multiple - row_length % row_multiple; if(row_padding_size == 0) return 0; size_t new_row_length = row_length + row_padding_size; size_t newDataLength = height * new_row_length; unsigned char *newData = malloc(sizeof(unsigned char) *newDataLength); unsigned char padding[3] = {0, 0, 0}; for(int i=0; i 

Maintenant, avant de passer bitmap à resizeBitmap (), je fais ce remplissage:

 unsigned char *paddedData = 0; size_t paddedDataLength = 0; int padding = padBitmap(gData, gDataLength, width, height, PNG_BIT_DEPTH_8, GRAYSCALE_COMPONENTS_PER_PIXEL, &paddedData, &paddedDataLength, 4); width += padding; 

Et j'utilise comme bitmap paddedData . Cela semble fonctionner correctement