Reputation: 159
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:
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:
Upvotes: 0
Views: 320
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
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