rikitikitavi
rikitikitavi

Reputation: 159

Attempting to display image using pixel values in OpenCV. Only 1/3rd of Image shows

I'm attempting to read the pixels in an image and convert them into another format by iterating through the pixels.

After my conversion I only seem to be getting 1/3rd of the image and I'm certain it's because of the way I'm accessing the pixels using the .at() function.

I'm reading in the following image:

camera man image

Mat image = imread("cameraman.jpg");

I then iterate through the images rows and columns:

for (int i = 0; i < image.rows; i++)
{
   for (int j = 0; j < image.cols; j++)
   {
      placeGrayValue((double)image.at<uchar>(i, j));
   }
}

Note: placedGrayValue() is just a placeholder here so that I can share only the code that is relevant.

The resulting image is only the first third of the image:

cropped camera man image with only first 1/3rd vertical strip showing

Upvotes: 0

Views: 320

Answers (2)

Miki
Miki

Reputation: 41776

You're loading your image with cv::imread, which with default value (cv::IMREAD_COLOR) will load it as a 3 channel image of type CV_8UC3 (aka cv::Mat3b).

If your original image is grayscale, when loading as a 3 channel image you have the same intensity value for each channel.

So when you scan the image you should access pixels with .at<cv::Vec3b>(...). If you want to copy only the first channel to the placeGrayValue matrix you should do it as:

placeGrayValue((double)image.at<cv::Vec3b>(i, j)[0]);
                                ^^^^^^^^^       ^^^
                                3 channel       first channel

If your input is not a grayscale image, then you shouldn't just copy the first channel, since the grayscale value is a linear combination of the three R,G,B channels. So it's better to first convert to grayscale, and then copy:

cv::Mat grayscale;
cv::cvtColor(image, grayscale, cv::COLOR_BGR2GRAY);
...
    placeGrayValue((double)grayscale.at<uchar>(i, j));
                                        ^^^^^
                                       1 channel

Or you can load the image already as a grayscale image:

Mat grayscale = imread("cameraman.jpg", cv::IMREAD_GRAYSCALE);

At the end, you want to have placeGrayValue with the grayscale values as double. You should not scan the image for this kind of easy operations. You can just:

cv::Mat placeGrayValue;
grayscale.convertTo(placeGrayValue, CV_64F);
                                    ^^^^^^ 
                                   to double type

Summing up:

cv::Mat grayscale = cv::imread("cameraman.jpg", cv::IMREAD_GRAYSCALE);
cv::Mat placeGrayValue;
grayscale.convertTo(placeGrayValue, CV_64F);

Upvotes: 2

rikitikitavi
rikitikitavi

Reputation: 159

I'll post what ended up working as an answer, though it makes little sense to me and I'd still like to understand why.

The image has 3 channels. When iterate through an image using a for loop and extract pixel data with (double)image.at<uchar>(i, j) it goes through each channel as if they were individual pixels.

The solution (at least with this grayscale image) is to iterate and multiply by 3. In other words, (double)image.at<uchar>(i*3, j) ended up giving me the full image.

Upvotes: 0

Related Questions