如何在 OpenCV 中处理 JPEG 二进制数据?

How to process a JPEG binary data in OpenCV?

我正在尝试在 OpenCV 中处理 JPEG 二进制数据。当我这样做时,我得到 Segmentation fault (core dumped).

我通过 fread 命令读取 JPEG 文件并存储在缓冲区中。

读取后,我将缓冲区数据复制到一个Mat变量中, 当我尝试使用 cvtColor OpenCV 函数对复制的数据进行灰度转换时。我得到分段错误。

int main( int argc, char** argv )
{

    Mat threshold_output;
    Mat gray_image;

    unsigned char *pre_image;
    FILE *read_image;
    FILE *write_image;
    int filesize;
    size_t data, write;

    read_image = fopen(argv[1] , "rb"); //Read Jpeg as Binary
    write_image = fopen("output11.jpg", "wb"); //Write JPEG

    if(read_image == NULL)
    {
        printf("Image Not Found\r\n");
    }
    fseek(read_image, 0, SEEK_END);
    int fileLen = ftell(read_image);
    fseek(read_image, 0, SEEK_SET);

    pre_image = (unsigned char *)malloc(fileLen);
    data = fread(pre_image, 1, fileLen, read_image);
    write = fwrite(pre_image, 1, fileLen, write_image);

    // Printed and verify the values
    printf("File Size %d\r\n", fileLen);
    printf("Read bytes %zu\r\n", data);
    printf("Write bytes %zu\r\n", data);

    fclose(read_image);
    fclose(write_image);

    /* Copy the Jpeg Binary buffer to a MAt Variable*/  
    cv::Mat image(Size(640, 480), CV_8UC3, pre_image); //Seg Fault comes here
    /* Convert Grayscale */
    cvtColor( image, gray_image, CV_BGR2GRAY);
    /* Threshold conversion */
    threshold( gray_image, threshold_output, 80, 255, THRESH_BINARY );

    namedWindow( "Thresholded", CV_WINDOW_AUTOSIZE );
    imshow( "Thresholded", image );

    waitKey(0);
    return 0;
}

我已附上代码以供参考。我已经验证 freadfwrite 都可以正常工作。 但是当我执行 cvtColor 时,只有我得到了错误。

OpenCV 使用 BGR 等通道,无法对编码图像执行计算机视觉操作,因为编码图像不包含像素数据,而是一些可以转换为像素的编码数据。 OpenCV 假定图像已经解码,因此它可以处理像素数据。

但是:您可以使用二进制图像缓冲区(就像您的 pre_image)并让 openCV 对其进行解码。

使用 cv::imdecode 完成此操作,然后您将获得合法的 cv::Mat 图像。 http://docs.opencv.org/modules/highgui/doc/reading_and_writing_images_and_video.html#imdecode

正如@Micka 已经指出的那样,您应该使用 cv::imdecode

您可以将它与您的 FILE* 一起使用。如果您使用的是 C++,您可能希望使用 fstreams。您也可以直接依赖 OpenCV 功能来读取文件。

下面的代码将向您展示这些用于读取文件的选项。编写代码类似(需要的话我可以补充)

记住,如果你想写二进制流,你应该使用imencode

#include <opencv2\opencv.hpp>
#include <fstream>
#include <stdio.h>

using namespace std;
using namespace cv;

int main()
{

    ////////////////////////////////
    // Method 1: using FILE*
    ////////////////////////////////

    FILE* read_image = fopen("path_to_image", "rb");
    if (read_image == NULL)
    {
        printf("Image Not Found\n");
    }

    fseek(read_image, 0, SEEK_END);
    int fileLen = ftell(read_image);
    fseek(read_image, 0, SEEK_SET);

    unsigned char* pre_image = (unsigned char *)malloc(fileLen);
    size_t data = fread(pre_image, 1, fileLen, read_image);

    // Printed and verify the values
    printf("File Size %d\n", fileLen);
    printf("Read bytes %d\n", data);

    fclose(read_image);

    vector<unsigned char> buffer(pre_image, pre_image + data);
    Mat img = imdecode(buffer, IMREAD_ANYCOLOR);

    ////////////////////////////////
    //// Method 2: using fstreams
    ////////////////////////////////

    //ifstream ifs("path_to_image", iostream::binary);
    //filebuf* pbuf = ifs.rdbuf();
    //size_t size = pbuf->pubseekoff(0, ifs.end, ifs.in);
    //pbuf->pubseekpos(0, ifs.in);
    //vector<char> buffer(size);
    //pbuf->sgetn(buffer.data(), size);
    //ifs.close();
    //Mat img = imdecode(buffer, IMREAD_ANYCOLOR);


    ////////////////////////////////
    //// Method 3: using imread
    ////////////////////////////////

    //Mat img = imread("path_to_image", IMREAD_ANYCOLOR);


    // Work with img as you want

    imshow("img", img);
    waitKey();


    return 0;
}