12

I have a jpeg image in buffer jpegBuffer. I'm trying to pass it to cv::imdecode function:

Mat matrixJprg = imdecode(Mat(jpegBuffer), 1);

I get this error:

/home/richard/Desktop/richard/client/src/main.cc:108: error: no matching function for call to ‘cv::Mat::Mat(char*&)’

This is how I fill jpegBuffer:

FILE* pFile;
long lSize;
char * jpegBuffer;
pFile = fopen ("img.jpg", "rb");
if (pFile == NULL)
{
    exit (1);
}

// obtain file size.
fseek (pFile , 0 , SEEK_END);
lSize = ftell (pFile);
rewind (pFile);

// allocate memory to contain the whole file.
jpegBuffer = (char*) malloc (lSize);
if (jpegBuffer == NULL)
{
    exit (2);
}

// copy the file into the buffer.
fread (jpegBuffer, 1, lSize, pFile);

// terminate
fclose (pFile);
vsz
  • 4,637
  • 6
  • 37
  • 73
Richard Knop
  • 77,193
  • 144
  • 386
  • 546
  • This is a question more than a comment. Can you not use `stat` to find the file size? What's the advantage of doing it like you have? – Noufal Ibrahim Mar 19 '18 at 11:29

2 Answers2

23

I had to do the-same thing and my image data was already in char array format and was arriving from a network and a plugin source. The current answer shows how to do this but it requires copying the data into a vector first which is a waste of time and resources.

This is possible to do directly without creating a copy of it. You were so close with your imdecode(Mat(jpegBuffer), 1); code in your question.

You need to use the constructor overload for the Mat class below:

Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP);

To create this Mat, pass 1 to the rows, the size of the array to the cols, CV_8UC1 to the type and the char array itself to the data param. Pass this Mat to the cv::imdecode function with the mat as the first param and CV_LOAD_IMAGE_UNCHANGED as the second param.

Basic example:

char *buffer = dataFromNetwork;
int bufferLength = sizeOfDataFromNetwork;

cv::Mat matImg;
matImg = cv::imdecode(cv::Mat(1, bufferLength, CV_8UC1, buffer), CV_LOAD_IMAGE_UNCHANGED);

Complete Example (Reads file named "test.jpg" into char array and uses imdecode to decode the data from the char array then displays it):

int main() {

    //Open image file to read from
    char imgPath[] = "./test.jpg";
    ifstream fileImg(imgPath, ios::binary);
    fileImg.seekg(0, std::ios::end);
    int bufferLength = fileImg.tellg();
    fileImg.seekg(0, std::ios::beg);

    if (fileImg.fail())
    {
        cout << "Failed to read image" << endl;
        cin.get();
        return -1;
    }

    //Read image data into char array
    char *buffer = new char[bufferLength];
    fileImg.read(buffer, bufferLength);

    //Decode data into Mat 
    cv::Mat matImg;
    matImg = cv::imdecode(cv::Mat(1, bufferLength, CV_8UC1, buffer), CV_LOAD_IMAGE_UNCHANGED);

    //Create Window and display it
    namedWindow("Image from Char Array", CV_WINDOW_AUTOSIZE);
    if (!(matImg.empty()))
    {
        imshow("Image from Char Array", matImg);
    }
    waitKey(0);

    delete[] buffer;

    return 0;
}
Programmer
  • 114,125
  • 20
  • 214
  • 306
  • `error: no member named 'CV_LOAD_IMAGE_UNCHANGED' in namespace 'cv'` with latest OpenCV – Erik Nov 14 '21 at 10:55
15

Mat has no constructor that takes a char* argument. Try this instead:

std::ifstream file("img.jpg");
std::vector<char> data;

file >> std::noskipws;
std::copy(std::istream_iterator<char>(file), std::istream_iterator<char>(), std::back_inserter(data));

Mat matrixJprg = imdecode(Mat(data), 1);

EDIT:

You should also take a look at LoadImageM.

If you have your data already in a char* buffer one way is to copy the data into an std::vector.

std::vector<char> data(buf, buf + size);
ronag
  • 46,551
  • 23
  • 119
  • 210
  • 2
    Thanks very much. But what if I have the image just in buffer (for example char* jpegBuffer) in memory and it's not saved as a file on the disk? How would I send the buffer to imdecode then? The code above is just a little test but later I will be just reading jpg images from wifi connection to buffer without saving them to files. – Richard Knop Nov 24 '10 at 22:35
  • Generally you should avoid char* buffers and usually this is possible, when you read your images from the wifi connection read them into a std::vector instead of a char* buffer. – ronag Nov 24 '10 at 22:54