Как обрабатывать двоичные данные JPEG в OpenCV?

Я пытаюсь обработать двоичные данные JPEG в OpenCV. Когда я это делаю, я получаю сообщение Ошибка сегментации (дамп ядра).

Я читаю файл JPEG с помощью команды fread и сохраняю в буфере.

После прочтения я скопировал данные буфера в переменную 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;
}

Я приложил код для справки. Я убедился, что и fread, и fwrite работают правильно. Но когда я делаю только cvtColor, я получаю ошибку.


person Mohamed Sarjoondeen    schedule 05.08.2015    source источник


Ответы (2)


Как уже указывал @Micka, вы должны использовать cv::imdecode

Вы можете использовать его с вашим FILE*. Возможно, вы захотите использовать fstreams, если используете C++. Вы также можете напрямую полагаться на возможности 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;
}
person Miki    schedule 05.08.2015
comment
Большое спасибо за ваше время, Мики... Я могу декодировать, используя ваш код.. И спасибо за изменения, которые вы сделали. - person Mohamed Sarjoondeen; 06.08.2015

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

person Micka    schedule 05.08.2015
comment
Привет, спасибо за ваш ответ. Можете ли вы помочь мне использовать этот imdecode в моей программе. Я очень новичок в opencv. Я знаю, как использовать некоторые простые функции opencv. Я не так знаком с этим. - person Mohamed Sarjoondeen; 05.08.2015
comment
ответ @Miki предоставляет пример кода. Важные строки: vector<unsigned char> buffer(pre_image, pre_image + data); Mat img = imdecode(buffer, IMREAD_ANYCOLOR); - person Micka; 05.08.2015
comment
и, пожалуйста, если вы действительно получаете данные изображения из файлов (поэтому ваше изображение в формате jpeg еще не находится в буфере), используйте cv::Mat input = cv::imread(filename); (который также декодирует изображение/jpeg, если необходимо) напрямую и не беспокойтесь о чтении файла вручную и т. д. ! (как упоминал @Miki) - person Micka; 05.08.2015
comment
Спасибо, сэр... Я могу декодировать и использовать пиксели. - person Mohamed Sarjoondeen; 06.08.2015