使用带有灰度图像的cvImageCreate()的OpenCV失败,并且调整大小通常会失败

时间:2016-10-07 19:23:12

标签: c opencv

我有这样的代码从缓冲区1byte,8bits位图加载灰度图像。然后它调整此图像的大小。

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

我在这里使用bitDepth = 8和noOfChannels = 1。 加载的图像是: enter image description here

,输出为: enter image description here

此输出并不总是写入,因为程序通常会因错误而失败:

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

我正在附加调试器输出,因为我正在传递大小为528480的灰度缓冲区,它等于1字节* 1101 * 480,但是在cvCreateImage之后有imageSize 529920和widthStep是1104!也许这是这张图片的问题,但为什么呢?

enter image description here

2 个答案:

答案 0 :(得分:1)

此问题与宽度步长和IplImage的宽度有关。 Opencv将图像填充为宽度为4个字节的倍数。这里opencv使用宽度1101和宽度步长1104.但是当从位图写入IplImage时,每行写入几个额外的像素(注意从左上角到右下角的对角线)。

请注意,图像不会倾斜。只是每一行都会向左移动一点(按3个像素),从而产生剪切变换的想法。

也有可能你给出的宽度小于Bitmap的宽度。

请在此处查看docs并搜索填充。您可以尝试逐行复制所有列数据。

为什么会崩溃:有时opencv会在Bitmap缓冲区之外读取并触及不可触及的内存地址,从而导致异常。

注意:位图可能还有填充,您从中获得了黑色对角线。

答案 1 :(得分:1)

根据回答 saurabheights ,我编写了一个程序,将每个位图行的填充填充到行中任意给定的多个字节。

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<height; i++) {
        memcpy(newData + i*new_row_length, data + i*row_length, row_length);
        memcpy(newData + i*new_row_length + row_length, padding, row_padding_size);
    }

    *paddedData = newData;
    *paddedDataLength = newDataLength;

    return row_padding_size;
}

现在在将位图传递给resizeBitmap()之前,我正在做这个填充:

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;

我使用的是位图paddedData。它似乎工作正常