Ask Your Question
0

Saving the image

asked 2017-11-22 07:33:15 -0600

Digital Design gravatar image

updated 2017-11-22 08:10:40 -0600

Hi there, A very easy question. I´m trying to load an image and save it to a new variable/file.

int main()
{
    Mat host, dest;
    register unsigned long int i1, j1;
    vector<int> JPEG_param;
    host = imread("E://PO//2//Amir_3_0_0__0_16x16-des22_L1xL2_300x300_NxM_1000x1000_centrox10_centroy46.jpg", CV_LOAD_IMAGE_ANYCOLOR);
    dest = Mat::zeros(host.rows, host.cols, CV_8UC3);
    if (!(host.size() == dest.size()))
        cout << "Unequal Size" << endl;
    for (i1 = 0; i1 < host.rows* host.cols; i1++)
        host.data[i1] = dest.data[i1];

    namedWindow("The Host Image", WINDOW_AUTOSIZE);
    imshow("The Host Image", host);
    waitKey(0);
    destroyWindow("The Host Image");
    namedWindow("The dest Image", WINDOW_AUTOSIZE);
    imshow("The dest Image", dest);
    waitKey(0);
    destroyWindow("The dest Image");
    JPEG_param.push_back(CV_IMWRITE_JPEG_QUALITY);
    JPEG_param.push_back(100);
    imwrite("E://PO//123.jpg", dest, JPEG_param);
    getchar();
    return 0;
}

But when I display the image, it´s entirely black. What´s wrong???!!!

edit retag flag offensive close merge delete

Comments

int main() { Mat host, dest; register unsigned long int i1, j1; vector<int> JPEG_param; host = imread("E://PhD//Adrian//PO//2//Amir_3_0_0__0_16x16-des22_L1xL2_300x300_NxM_1000x1000_centrox10_centroy46.jpg", CV_LOAD_IMAGE_ANYCOLOR); dest = Mat::zeros(host.rows, host.cols, CV_8UC3); if (!(host.size() == dest.size())) cout << "Unequal Size" << endl; for (i1 = 0; i1 < host.rows* host.cols; i1++) host.data[i1] = dest.data[i1];

namedWindow("The Host Image", WINDOW_AUTOSIZE);
imshow("The Host Image", host);
waitKey(0);
destroyWindow("The Host Image");
namedWindow("The dest Image", WINDOW_AUTOSIZE);
imshow("The dest Image", dest);
waitKey(0);
destroyWindow("The dest Image");
JPEG_param.push_back(CV_IMWRITE_JPEG_QUALITY);
JPEG_param.push_back(100);
imwrite("E://PhD//Matlab Pr
Digital Design gravatar imageDigital Design ( 2017-11-22 07:42:28 -0600 )edit

1 answer

Sort by » oldest newest most voted
3

answered 2017-11-22 08:53:11 -0600

updated 2017-11-23 12:51:58 -0600

The reason why you're getting a black image is because of your iteration.

By doing dst = Mat::zeros(host.rows, host.cols, CV_8UC3), you just created a black image with the same dimensions as host with three channels.

Matrices are 2D containers i.e. they have rows and columns. With your current loop, you are just iterating from 0 to the product of the rows and cols. You're actually lucky that this iteration hasn't resulted in some sort of segmentation fault. My guess is that your rows is large enough to accommodate the iteration of rows * columns

How to resolve this?

General Case:

You need two loops. One for iterating over the rows and one for each column.

vector<vector<int>> 2dContainer;

for(size_t row = 0; row < 2dContainer.size(); ++row)
{
    for(size_t col = 0; col < 2dContainer[row].size(); ++col)
    {
       cout << 2dContainer[row][col];
    }
}

This is generally how you iterate over a 2D container.

OpenCV Case:

Unfortunately the Mat class does not have the subscript operator; [], to allow us to access elements as shown above. Instead they have at. And to add to the complexity, your image has three channels so we need to take that into account as well.

This can be done as shown below

for(int row = 0; row < host.rows; ++row)
    for(int col = 0; col < host.cols; ++col)
    {
        dst.at<Vec3b>(row, col)[0] = host.at<Vec3b>(row, col)[0]; // copy first channel
        dst.at<Vec3b>(row, col)[1] = host.at<Vec3b>(row, col)[1]; // copy second channel
        dst.at<Vec3b>(row, col)[2] = host.at<Vec3b>(row, col)[2]; // copy third channel
    }

Simple Alternative:

OpenCV already has an API called copyTo() which does exactly this for you. All you have to is host.copyTo(dst) and voila, world peace is attained! :). Here's the documentation about this.

Code Review:

  1. Why do you have so many waitKeys? Generally speaking a single one is more than enough. Display your stuff then add a single waitKey before your return.

  2. You do not need the getchar() anymore to leave your windows open. That's exactly what waitKey is doing already.

  3. You do not need to use namedWindow() for your case. A straight shot imshow() would suffice.

  4. No need to call destroyWindow() for each and every newly created window. Display your stuff with imshow() then call destroyAllWindows().

  5. If OpenCV version < 3, please update. OpenCV is shying away from using the CV prefix. But if an update is out of the question, then its all good.

Should you choose to adapt the above recommendations, your display code can be trimmed down to just this

imshow("The Host Image", host);
imshow("The dest Image", dest);
JPEG_param.push_back(IMWRITE_JPEG_QUALITY);
JPEG_param.push_back(100);
imwrite("E://PO//123.jpg", dest, JPEG_param);
waitKey(0);
destroyAllWindows();

return 0;

Happy coding!

edit flag offensive delete link more

Comments

Many thanks for your comprehensive explanations. Thank youuuuuuuuuuuuuuuuuuuuu :)

Digital Design gravatar imageDigital Design ( 2017-11-23 08:39:58 -0600 )edit
1

@Digital Design You're welcome. Do not forget to mark as answer and upvote responses which resolve your questions. This allows for your question to be cleared from the queue.

eshirima gravatar imageeshirima ( 2017-11-23 12:49:29 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2017-11-22 07:33:15 -0600

Seen: 437 times

Last updated: Nov 23 '17