PPM wrong color display - c++

I get weird results when displaying a PPM:
pixeldisplay
(this is actually an upscaled PNG)
And here's what the file looks like:
textdisplay
The dimensions are fine (10 rows, 8 columns), just the colors are wrong (or am I wrong?).
As it says in the 3rd line of the file, I want to use a value from 0 to 255 per channel. Using an usual rgb color space like (255, 255, 255) for white, (0, 0, 0) for black, (255, 0, 0) for red and so on. But those colors in the image are apparently not the same as in the file.
Already at the first look, the image seems way to dark.
Do I misunderstand the format? Is the file not interpretated this way?

This document: http://netpbm.sourceforge.net/doc/ppm.html describes the PPM image format.
When the "magic" value P6 is found at the beginning of the file, the color of the pixels is stored as binary data. Quoting the previously mentioned document (emphasis mine):
[...] A raster of Height rows, in order from top to bottom. Each row consists of Width pixels, in order from left to right. Each pixel is a triplet of red, green, and blue samples, in that order. Each sample 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 file showed by the asker seems to contain their decimal textual representation instead.
So, the string "\n224 93 229..." (yes, I suspect the windows endline sequence "\r\n") is interpreted as (assuming that the file was saved in ASCII format) {10, 50, 50}, {50, 32, 32}, {57, 51, 32}, ....
Note the blackish pixel in the middle, which probably correspond to the end of the first line, it may be a {13, 10, 32} ("\r\n ").
If you change the magic value to P3, it should be interpreted correctly.

Related

Reduce Image bit C++

How can I reduce the number of bits from 24 bits to a number between 0 and 8 bits and distribute the bits for the three colors Red, Green and Blue
Any idea ?
This is called "Color Quantization". You have 16.777.216 colors and you want to map them to a smaller number (2 to 256).
Step 1: choose the colors you want to use. First their number, then the colors themselves. You need to chose if the colors are fixed for all images, or if they change based on the image (you will need to ship a palette of colors with every image).
Step 2: substitute the colors of your image with those in the selection.
If the colors are fixed and you want to stay very simple you can use 1 bit per channel (8 colors in total) or 2 bits per channel (64 colors in total).
Slightly more complex, use these values for each channel 0, 51, 102, 153, 204, 255, in any possible way, leading to 216 different color combinations. Make a table which associates every color combination with an index. That index requires 8 bits (with some spare). This is called a "web safe palette" (this brings me back to the late 1999). Now you are ready for substitution: take every pixel in your image and the quantized color can be found as x*6//256*51 (// is integer division).
If you want a better looking palette, look for the Median cut algorithm.
Keep only the most significant bits of the pixel's red channel. Do likewise for the green and blue channel. Then use C++'s bit manipulation operations to move those bits values into a single byte. There are multiple ways of doing so. For example, do an Internet search for "rgb332" for one example (where you keep 3 red bits, 3 green bits, and 2 blue bits).

is there any way to determine width and height of rgb values array?

I have RGB values array with raw size each time. I'm trying to determine which width/height it would be more suitable for it.
The idea is, I'm getting raw files and I want to display file data as BMP image (e.g Hex Workshop got that feature which called Data Visualizer)
Any suggestions?
Regards.
Find the divisors of the pixel array size.
For instance, if your array contains 243 pixels, divisors are 1, 3, 9, 27, 81 and 243. It means that your image is either 1x243, 3x81, 9x27, 27x9, 81x3 or 243x1.
You can only guess which is the good one by analyzing image content, vertical or horizontal features, recurring patterns, common aspect ratio, etc.

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".

Getting RGB from WIC image c++

I am using WIC to load in an image and then I want to be able to get the RGB values of each pixel. I have got as far as using getDataPointer() to create a byte buffer (which I cast to a COLORREF array) but after this things get strange.
I have a 10x10 24bit png that I'm testing with. If I look at the size value getDataPointer() gives me it says it's 300, which makes sense because 10 * 10 * 3 (for 3 bytes per pixel) = 300. If I do getStride() it gives me 30, which also makes sense.
So I create a loop to go through the COLORREF with an iterator and the condition is i < size/3 because I know there are only 100 pixels in the array. I then use the macros GetRValue(), GetGValue() and GetBValue() to get the rgb values out.
This is when things go weird - My small image is just a test image with solid red, green, blue and black pixels in, but my RGB values come out (255, 0, 0), (0, 255, 0), (27, 255, 36), (0, 0, 0) etc. it seems that some values don't come out properly and are corrupted somehow. Also, the last 20/30 pixels of the image are either loads of crazy colors or all black making me think there some sort of corruption.
I also tested it with a larger actual photograph and this comes out all grayscale and repeating the same pattern, making me think it's a stride issue but I don't understand how because when I call getPixelFormat() WIC says it's 24bppBGR or 24bppRGB depending on the images.
Does anyone have any idea what I am doing wrong? Shouldn't I be using COLORREF and the macros or something like that?
Thanks for your time.
EDIT
Hmm I've still got a problem here. I tried with another 24bit PNG that PixelFormat() was reporting as 24bppBGR but it seems like the stride is off or something because it is drawing as skewed (obligatory nyan cat test):
EDIT 2
Okay so now it seems I have some that work and some that don't. Some reporting themselves as 24bpp BGR work while others look like the image above and if I calculate the stride it gives me compared to what it should be they are different and also the size of the buffer is different too. I also have some 32bpp BGR images and some of those work and others don't. Am I missing something here? What could make up the extra bytes in the buffer?
Here is an example image:
24bppBGR JPEG:
width = 126
height = 79
buffer size = 30018
stride = 380
If I calculate this:
buffer size should be: width * height * 3 = 126 * 79 * 3 = 29862
difference between calculation and actual buffer size: 30018 - 29862 = 156 bytes
stride size should be: width * 3 = 378
difference between calculation and actual buffer size: 380 - 378 = 2 bytes
I was thinking that we had 2 extra bytes per line but 79 * 2 is 158 not 156 hmm.
If I do these calculations for the images that have worked so far I find no difference in the calculations and the values the code gives me...
Am I understanding what is happening here wrong? Should these calculations now work as I have thought?
Thanks again
You shouldn't be using COLORREF and related macros. COLORREF is a 4-byte type, and you have 3-byte pixels. Accessing the data as an array of COLORREF values won't work. Instead, you should access it as an array of bytes with each pixel located at ((x + y * width) * 3). The order of individual channels is indicated by the format name. So if it's 24bppBGR you'd do data[(x + y * width) * 3] to get the blue channel, data[(x + y * width) * 3 + 1] for green, and data[(x + y * width) * 3 + 2] for red.
If you really want an array of pixels, you can make a structure with 3 BYTE fields, but since the meaning of those fields depends on the pixel format, that may not be useful.
In fact, you can't assume an arbitrary image will load as a 24-bit format at all. The number of formats you could get is larger than you could reasonably be expected to support.
Instead, you should use WICConvertBitmapSource to convert the data to a format you can work with. If you prefer to work with a COLORREF array and related macros, use GUID_WICPixelFormat32bppBGR.

Load Images from memory (libharu) from Magick++ images

I am working on some pdf generation software in c++ based on libharu and I would like to be able to first manipulate images using Magick++ and then load them from memory using libharu function:
HPDF_LoadRawImageFromMem()
Which according to the documentation essentially load images from some void *buffer.
My goal is to be able to get this void* data out of a Magick::Image instance and load this image into my haru pdf based on this data.
I have tried writing to a void*or to a Magick::Blob but the only achievement I have had so far was some black rectangle instead of the image I am expecting.
Does anyone have any experience in converting Raw image data from one library into another one ?
The reason I am trying to do this from memory is because so far I am writing Magick::Image instances into a file and then reading from this file to load then in haru, which is a huge performance hit in the context of my Application.
I'm a little late to answer I guess, but here's a real-life answer.
I successfully added an itk::Image to my pdf using LibHaru so it should work about the same for you. First, you need to know if the library you use is row major or column major. LibHaru (and all the libraries I know) works in row major, so your library should too, or you will need to "transpose" your data.
// Black and white image (8 bits per pixel)
itk::Image<unsigned char, 2>::Pointer image = ...;
const unsigned char *imageData = image->GetBufferPointer();
const HPDF_Image image = HPDF_LoadRawImageFromMem(m_Document,
imageData, width, height, HPDF_CS_DEVICE_GRAY, 8);
// Or color image (24 bits per pixel, 8 bits per color component)
itk::Image<RGBPixel, 2>::Pointer image = ...;
const RGBPixel *imageData = image->GetBufferPointer();
const HPDF_Image image = HPDF_LoadRawImageFromMem(m_Document,
reinterpret_cast<const unsigned char *>(imageData),
width, height, HPDF_CS_DEVICE_RGB, 8);
// Usual LibHaru code. EndText, Position, Draw, StartText, etc.
// This code should not be dependant on the type
InsertImage(image);
I think the only complicated part is the reinterpret_cast. The black and white image don't need one because it's already defined as byte. For example, if you have this image
102 255 255
99 200 0
255 0 100
imageData == {102, 255, 255, 99, 200, 0, 255, 0, 100};
However, if you have this color image
( 0, 0, 255) (0, 255, 255) ( 42, 255, 242)
(200, 200, 255) (0, 199, 199) (190, 190, 190)
imageData == {0, 0, 255, 0, 255, 255, 42, 255, 242, 200, 200, 255, ... }
which LibHaru will inderstand because you tell him to use HPDF_CS_DEVICE_RGB, which means that it will group the data in (R, G, B).
Of course, using ImageMagick, you need to find how to access the first pixel. It's probably a method like data(), begin(), pointer(), etc.
Unfortunately I neither worked with ImageMagic nor libharu, however I have some experience with image processing and since nobody answered yet, maybe I can be of some help.
The problem is probably that there is a plethora of raw image formats and I'm quite sure that both libraries do not have the same understanding of these. What makes things worse is that the raw image interpretation of libharu is virtually not documented. However the conclusions that libharu handles raw data quite straightforward can be drawn from the parameters of: "HPDF_LoadRawImageFromMem".
Width and Height are pretty much self-explanatory, with the only question of the used (probably pixels). More interesting is: "bits_per_component". This parameter probably describes how many bits are used to define one pixel (common values are 8: indexed from a palette of 256 values, 16: indexed from a palette of 65535 values, 24: one byte for red, green, and blue respectivly [RGB], 32: as 24 but with alpha channel or 8 bits for cyan, magenta, yellow, and black [CMYK], 36: as 32 but with 9 bit per value for easier transpostion...). A problem is the lousy documentation of the type: HPDF_ColorSpace, since it probably describes how color values of with: "bits_per_component" are to be interpreted.
A totally different approach seems to be implemented by ImageMagic. An image object seems to have always an image format (JPEG, PNG, GIF), therefore an image object probably never has a "straightforward" memory representation but is encoded.
My recommendation would be to switch the ImagaMagic image to the TIFF format, since it condones compression and therefore has a similar approach to the assumed raw interpretation by libharu.
Hope this helped at least a bit...
Cheers
Mark.
It is never late to answer.
I have used a PNG blob as intermediate step:
Image image;
image.read("file.jpg");
Blob blob;
image.write(blob, "PNG");
HPDF_Image pdfImg = HPDF_LoadPngImageFromMem(doc, (const HPDF_BYTE*)blob.data(), blob.length());
HPDF_Page_DrawImage(doc, pdfImg, 0, 0, image.columns(), image.rows());
PDF document and page creation omitted for brevity.