How are these PGM files encoded? [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I exported a grayscale image as PGM using MATLAB (and OpenCV) and got this file as an output.
im = imread(src);
im = rgb2gray(im);
imwrite(im, dst);
According to the PGM Specification the header contains the "magic number", the width, the height, and the max value of the image.
But below the header, there should be a matrix of grayscale intensity values written in plaintext. But as you can see in the pasted file, I just get some kind of junk out (although it's a completely valid, viewable image)
I want to be able to read in the PGM files and access the individual intensity values as integers using a C/C++ program but I don't know how to interpret this output since it doesn't follow the spec. Perhaps the text encoding is different?
Thanks for any assistance.

You're misreading the spec.
Each gray value is represented in pure binary by either 1 or 2 bytes. If the Maxval is less than 256, it is 1 byte. Otherwise, it is 2 bytes. The most significant byte is first.
So each pixel is either one or two bytes (depending on the Maxval) and in binary, not ASCII.

I think you're reading the definition of the "plain" format (magic number P2), but you have a "raw" PBM file (magic number P5). You might want to pipe through pnmtopnm -plain to access ASCII-format encoding.

Related

Basic C++ / Thresholding and Filtering an image [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
Good day to everyone!
I started learning C++ by myself a couple of weeks ago. I am now hoping to take on a small project; using my Ubuntu machine id like to run a code that can threshold an RGB image and then filter it according to certain values that I'll input myself.
How should I proceed? What should i keep in my mind when trying? And how long do you reckon should it take? Keep in mind that i have 0 prior experience in coding.
Thank you!
For first experiments, I suggest you consider only grayscale images or just the intensity channel of an RGB image.
Anyway, if you have some image data:
Read the image (libjpeg etc)
You should have the data in a big array. If the image is really, really big, you should do the following thing chunk-based.
Apply the threshold: You enter a threshold, if the image value is below the threshold, you keep it and set all other values to zero. Maybe the other way around, as you please.
For point 1, try starting with pgm images as they are really easy to read (cf. Wikipedia).
For most managable pgm images, you might not need chunk realization, just load the entire thing into one big array of fitting type.
Edit: Some code, consider the concrete assembly to runnable C++ code as an exercise ;)
std::ifstream file("your-filename.pgm", std::ifstream::binary);
// Read header information:
// Check out wikipedia article and the C++ documentation for ifstream.
char magic[2]; // magic number, P2 or P5
file.read(magic, 2);
if (magic[0] != 'P' || magic[1] < '1' || magic[1] > '5') {
throw std::exception("Invalid magic number");
}
int width, height, maxValue;
file >> width >> height >> maxValue;
if (maxValue <= 0 || maxValue >= (1 << 16)) {
throw std::exception("Max value must be resonable");
}
file.ignore(1);
std::unique_ptr<unsigned char> data(new unsigned char[width * height * sizeof(unsigned char)]);
file.read(reinterpret_cast<char*>(data.get()), width * height * sizeof(unsigned char));
// Now, the smart pointer 'data' contains your image grayscale data.
Be cautious: Some pgm files use unsigned short instead of unsigned char, but this information is inside the file header (you can identify that by the maxValue field).
After you loaded the data like above, you can just iterate over that array, do your processing (thresholding) and write the processed file to disk again.

Bluring an image in C++/C [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
So I'm staring a project about image processing with C++.
The thing is that everything I find online about this matter (blurring an image in C++) comes either with CUDA or with OpenCV.
Is there a way to blur an image with C++ only? (for starters)
If yes, can somebody please share the code or explain?
Thanks!
Firstly you need the image in memory.
Then you need a second buffer to use as a workspace.
Then you need a filter. A common filter would be
1 4 1
4 -20 4
1 4 1
For each pixel, we apply the filter. So we're setting the image to a weighted average of the pixels around it, then subtracting to avoid the overall image going lighter or darker.
Applying a small filter is very simple.
for(y=0;y<height;y++)
for(x=0;x<width;x++)
{
total = image[(y+1)*width+x+1];
for(fy=0; fy < 3; fy++)
for(fx = 0; fx < 3; fx++)
total += image[(y+fy)*width+x+fx] * filter[fy*3+x];
output[(y+1)*width+x+1] = clamp(total, 0, 255);
}
You need to special case the edges, which is just fiddly but doesn't add any theoretical complexity.
When we use faster algorithms that the naive one it becomes important to set up edges correctly. You then do the calculations in the frequency domain and it's a lot faster with a big filter.
If you would like to implement the blurring on your own, you have to somehow store the image in memory. If you have a black and white image, an
unsigned char[width*height]
might be sufficient to store the image; if it is a colour image, perhaps you will have the same array, but three or four times the size (one for each colour channel and one for the so-called alpha-value which describes the opacity).
For the black and white case, you would have to sum up the neighbours of each pixel and calculate its average; this approach transfers to colour images by applying the operation to each colour channel.
The operation described above is a special case of the so-called kernel filter, which can also be used to implement different operations.

cannot read correct pgm pixel values

I have a really weird error,
so I'm trying to read a pgm image by loading its pixel values into an array, I was able to correctly read in its version, height, width, and maximum possible pixel value. However, when I start reading the pixel values, I always get 0. (I know it's not zero because I can read it using imread in matlab, but have to implement it in c++, plus I couldn't use the opencv library so..)
And besides, when I read the pgm file in like NotePad++, the first few lines are good representing the information about this image ,how ever, the actual pixel values are not readable. I'm wondering if I need some sort of parsing to read a pgm image? Its version is p5.
Thanks!
You must have an assignment to solve as there is no sane reason implementing a PGM reader otherwise.
There are two different PGM formats: ASCII and binary. You seem to expect an ASCII PGM but the one you have is binary.
Have a look at the specs: http://netpbm.sourceforge.net/doc/pgm.html
It says:
/1. A "magic number" for identifying the file type. A pgm image's
magic number is the two characters "P5".
[…]
/9. A raster of Height rows, in order from top to bottom. Each row
consists of Width gray values, in order from left to right. Each gray
value is a number from 0 through Maxval, with 0 being black and Maxval
being white. Each gray value is represented in pure binary by either
1 or 2 bytes. If the Maxval is less than 256, it is 1 byte.
Otherwise, it is 2 bytes. The most significant byte is first.
The format you are expecting is described further down below as the Plain PGM format. Its magic number is "P2".

RGB color to HSL bytes

I've seen some implementations for converting RGB to HSL. Most are accurate and work in both directions.
To me its not important that it will work in 2 directions (no need to put back to RGB)
But i want code that returns values from 0 to 255 max, also for the Hue channel.
And I wouldnt like to do devisions like Hue/360*250 i am searching for integer based math no Dwords (its for another system), nice would be some kind of boolean logix (and/or/xor)
It should not do any integer or real number based math, the goal is code
working only using byte math.
Maybe someone already has found such math when he used code like
c++ or
c# or
python
Which i would be able to translate to c++
Checkout the colorsys module, it has methods like:
colorsys.rgb_to_hls(r,g,b)
colorsys.hls_to_rgb(h,l,s)
The easyrgb site has many code snippets for color space conversion. Here's the rgb->hsl code.

save pixel array to jpeg image file c++

i have a pixel array containing the values from 0 to 255 ...
i have passed it to my c++ function ...
this pixel array i want to save it to jpeg image file...
how to do it with correct encoding ??
i have converted the array to binary string
and saved it into the file in the below code but it just saves an empty image of 4 byte size ...
FILE *file = fopen("/media/internal/wallpapers/04.jpeg", "w+");
fwrite(binaryStr , 1 , sizeof(binaryStr) ,file );
fclose(file);
thnks
Use libjpeg. Don't try to reimplement jpeg encoding yourself, there are too many ways it can go wrong.
I think you need a JPEG library, like libjpeg.
Independent JPEG Group: http://www.ijg.org/
Info: http://en.wikipedia.org/wiki/Libjpeg
From your description it looks like you have YUV-data that you need to convert to jpeg. Correct? Imagemagick is a very powerful tool that can handle this.
From wikipedias entry on YUV:
Y' values are conventionally shifted and scaled to the range [16, 235] rather than using the full range of [0, 255]. This confusing practice derives from the MPEG standards and explains why 16 is added to Y' and why the Y' coefficients in the basic transform sum to 220 instead of 255. U and V values, which may be positive or negative, are summed with 128 to make them always positive
I.e. 0-255 is not a valid range for YUV-data
It seems that sizeof(binaryStr) is 4. So, you'll need to get a length of the binaryStr, not the sizeof(pointer). And it's more simply to use something already cooked like libjpeg.