Confused about libjpeg: jpeg_read_scanlines - c++

I'm confused about the way libjpeg jpeg_read_scanlines works. It's my understanding that it decompresses a JPEG, row by row, and creates a decompressed pixel buffer.
Typical usage is something like:
jpeg_decompress_struct cinfo;
...
unsigned char* image = new unsigned char[cinfo.image_width * cinfo.image_height];
unsigned char* ptr = image;
int row_stride = cinfo.image_width;
while (cinfo.output_scanline < cinfo.image_height)
{
jpeg_read_scanlines(&cinfo, &ptr, 1);
ptr += row_stride;
}
Question: I'm confused about the output buffer size. In all example code I see which uses jpeg_read_scanlines, the size of the output buffer is width X height, where width and height refer to the dimensions of the JPEG file. So for a 10x10 JPEG file we'd have a 100 byte output buffer.
But... isn't the size of each RGB pixel 3 bytes (24-bit)? So shouldn't the uncompressed data actually be width X height X 3 bytes?
Why isn't it?
I notice that with code which uses jpeg_write_scanlines, the buffer to be compressed IS width X height X 3. So why is the buffer used with jpeg_read_scanlines only width X height?

You are only reading 1 line at a time with the line
jpeg_read_scanlines(&cinfo, &ptr, 1);
so you only needed the line
unsigned char* image = new unsigned char[cinfo.image_width * cinfo.image_height];
to be
unsigned char* image = new unsigned char[cinfo.image_width * cinfo.image_components];
The start of the buffer is being re-used for every scanline. Most of your current buffer is actually unused.

For RGB data, output_components will be 3 (R,G,B).
Here's some related documentation from libjpeg.txt:
output_width image width and height, as scaled
output_height
out_color_components # of color components in out_color_space
output_components # of color components returned per pixel
colormap the selected colormap, if any
actual_number_of_colors number of entries in colormap
output_components is 1 (a colormap index) when quantizing colors; otherwise it
equals out_color_components. It is the number of JSAMPLE values that will be
emitted per pixel in the output arrays.
Typically you will need to allocate data buffers to hold the incoming image.
You will need output_width * output_components JSAMPLEs per scanline in your
output buffer, and a total of output_height scanlines will be returned.

Related

Loading RAW grayscale image with FreeImage

How can I load RAW 16-bit grayscale image with FreeImage?
I have unsigned char* buffer with raw data. I know its dimensions in pixels and I know it is 16bit grayscale.
I'm trying to load it with
FIBITMAP* bmp = FreeImage_ConvertFromRawBits(buffer, 1000, 1506, 2000, 16, 0, 0, 0);
and get broken RGB888 image. It is unclear what color masks I should use for grayscale as it has only one channel.
After many experiments I found partially working solution with FreeImage_ConvertFromRawBitsEx:
FIBITMAP* bmp = FreeImage_ConvertFromRawBitsEx(true, buffer, FIT_UINT16, 1000, 1506, 2000, 16, 0xFFFF, 0xFFFF, 0xFFFF);
(thanks #1201ProgramAlarm for hint with masks).
In this way, FreeImage loads the data, but in some semi-custom format. Most of conversion and saving functions (tried: JPG, PNG, BMP, TIF) fail.
As I can't load data in native 16bit format, I preferred to convert it into 8bit grayscale
unsigned short* buffer = new unsigned short[1000 * 1506];
// load data
unsigned char* buffer2 = new unsigned char[1000 * 1506];
for (int i = 0; i < 1000 * 1506; i++)
buffer2[i] = (unsigned char)(buffer[i] / 256.f);
FIBITMAP* bmp = FreeImage_ConvertFromRawBits(buffer2, 1000, 1506, 1000, 8, 0xFF, 0xFF, 0xFF, true);
This is really not the best solution, I even don't want to mark it as right answer (will wait for something better). But after this the format will be convenient for FreeImage and it could save/convert data to whatever.
Concerning your issue: I have read this from their PDF documentation FreeImage1370.pdf:
FreeImage_ConvertFromRawBits
1 4 8 16 24 32
DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertFromRawBits(BYTE *bits, int width, int
height, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned
blue_mask, BOOL topdown FI_DEFAULT(FALSE));
Converts a raw bitmap somewhere in memory to a FIBITMAP. The parameters in this
function are used to describe the raw bitmap. The first parameter is a pointer to the start of
the raw bits. The width and height parameter describe the size of the bitmap. The pitch
defines the total width of a scanline in the source bitmap, including padding bytes that may be
applied. The bpp parameter tells FreeImage what the bit depth of the bitmap is. The
red_mask, green_mask and blue_mask parameters tell FreeImage the bit-layout of the color
components in the bitmap. The last parameter, topdown, will store the bitmap top-left pixel
first when it is TRUE or bottom-left pixel first when it is FALSE.
When the source bitmap uses a 32-bit padding, you can calculate the pitch using the
following formula:
int pitch = ((((bpp * width) + 31) / 32) * 4);
In the code you are showing:
FIBITMAP* bmp = FreeImage_ConvertFromRawBits(buffer, 1000, 1506, 2000, 16, 0, 0, 0);
You have the appropriate FIBTMAP* return type, you pass in your buffer of raw bits. From there the 2nd & 3rd parameters which are the width & height: width = 1000, height = 1506 and the 4th parameter which is the pitch: pitch = 2000 (if the bitmap is using 32bit padding refer to the last note above), the 5th parameter will be the bit depth measured in bpp you have as bpp = 16, the next 3 parameters are for your RGB color masks. Here you label them all as being 0. The last parameter is a bool flag for the orientation of the image :
if (topdown == true ) {
stores top-left pixel first )
else {
bottom left pixel is stored first
}
in which you omit the value.
Without more code of how you are reading in the file, parsing the header information etc. to prepare your buffer it is hard to tell where else there may be an error or an issue, but from what you provided; I think you need to check the color channel masks for grayscale images.
EDIT - I found another PDF for FreeImage from standford.edu here that refers to an older version 3.13.1 however the function declaration - definition doesn't look like it has changed any and they provide examples for b FreeImage_ConvertToRawBits & Free_Image_ConvertFromRawBits:
// this code assumes there is a bitmap loaded and
// present in a variable called ‘dib’
// convert a bitmap to a 32-bit raw buffer (top-left pixel first)
// --------------------------------------------------------------
FIBITMAP *src = FreeImage_ConvertTo32Bits(dib);
FreeImage_Unload(dib);
// Allocate a raw buffer
int width = FreeImage_GetWidth(src);
int height = FreeImage_GetHeight(src);
int scan_width = FreeImage_GetPitch(src);
BYTE *bits = (BYTE*)malloc(height * scan_width);
// convert the bitmap to raw bits (top-left pixel first)
FreeImage_ConvertToRawBits(bits, src, scan_width, 32,
FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK,
TRUE);
FreeImage_Unload(src);
// convert a 32-bit raw buffer (top-left pixel first) to a FIBITMAP
// ----------------------------------------------------------------
FIBITMAP *dst = FreeImage_ConvertFromRawBits(bits, width, height, scan_width,
32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, FALSE);
I think this should help you with your question about the bit masks for the color channels in a grayscale image.
You already mentioned the FreeImage_ConvertFromRawBitsEx() function, which was added at some point between FreeImage v3.8 and v3.17, but are you calling it correctly? I was able to use this function with 16-bit grayscale data:
int nBytesPerRow = nWidth * 2;
int nBitsPerPixel = 16;
FIBITMAP* pFIB = FreeImage_ConvertFromRawBitsEx(TRUE, pImageData, FIT_UINT16, nWidth, nHeight, nBytesPerRow, nBitsPerPixel, 0, 0, 0, TRUE);
Note that nBytesPerRow and nBitsPerPixel have to be specified correctly for the 16-bit data. Also, I believe the color mask parameters are irrelevant for this data, since it is monochrome.
EDIT: I noticed that you said that saving the 16-bit data did not work correctly. That may be due to the file formats themselves. The only file format that I have found to be compatible with 16-bit grayscale data is TIFF. So, if you have 16-bit grayscale data, you can save a TIFF with FreeImage_Save() but you cannot save a BMP.

How to convert Mat data(OpenCV, data format for image) into unity3d texutre

I know Mat data save each pixel data(RGB data in a column) as a unsigned char. And texture data in unity3d is byte[]. I try to do the following thing, but the result is not right, the image capture from the camera displayed in the hwind is not right.
Mat src_frame;//this is every frame that captured from the current camera
D3DLOCKED_RECT d3d_rect;
byte *pSrc = src_frame.data;
byte *pDest = (byte *)d3d_rect.pBits;
int stride = d3d_rect.Pitch;
int pixel_w_size = src_frame.cols;
for (unsigned long i = 0; i < src_frame.rows; i++){
memcpy(pDest, pSrc, pixel_w_size);
pDest += stride;
pSrc += pixel_w_size;
}
Only gray image shows, I don't know why this happens. Does the Mat data sequence is different from the texture data? Their data both contain the RGB information.
pixel_w_size should be src_frame.cols multiplied with the bytes per pixel (3 in case of RGB) or even better use elemSize().
So use:
int pixel_w_size = src_frame.cols * src_frame.elemSize();

how to acces colour of individual pixels using SOIL in cpp

I would like to access the RGB valuas from individual pixels. I know I can get an unsigned char array by calling
unsigned char* pixels = SOIL_load_image(picturename.c_str(), &_w, &_h, 0, SOIL_LOAD_RGB);
However I dont understand what these chars mean. The documentation says:
// The return value from an image loader is an 'unsigned char *' which points
// to the pixel data. The pixel data consists of *y scanlines of *x pixels,
// with each pixel consisting of N interleaved 8-bit components; the first
// pixel pointed to is top-left-most in the image. There is no padding between
// image scanlines or between pixels, regardless of format. The number of
// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise.
// If req_comp is non-zero, *comp has the number of components that _would_
// have been output otherwise. E.g. if you set req_comp to 4, you will always
// get RGBA output, but you can check *comp to easily see if it's opaque.
However when I load an 10 by 10 pixels image to test it i get an huge ammound of chars in the array (almost 54000) this seems way too much. How do i get the individual pixel colour that I can do something like this:
int colourvalue = pixel[y*width+x];
i cant seem to find this

Going from PNG data to tesseract

I am trying to move image data from Magick++ to tesseract.
I have the PNG data and some info about it.
And the signature for the tesseract method is:
void SetImage(const unsigned char* imagedata, int width, int height, int bytes_per_pixel, int bytes_per_line);
The first three arguments I can supply just fine. But bytes_per_pixel and bytes_per_line I'm not so sure about. The image itself has 11564 pixels but the length of the data is only 356 bytes... It's mostly a white image with some text. 11564/356 = 32.48 which obviously is not the correct bytes per pixel. How can I get the right bytes / pixel information? It's ok to just get that for one image on my desktop or something and set it as a constant, all the images I'm processing will have the same format.
Then as far as bytes per line, would that just be image width in pixels * bytes per pixel?
bytes_per_pixel can be obtained from PNG data. They are usually 8, 24 or 32.
bytes_per_line too, but you can compute it doing: bytes_per_pixel * width / 8

How to read an 8bit bitmap's pixel colour and postion from byte array

I currently have my 8bit bitmap's pixel data stored in an array of bytes: BYTE* pixelData.
How would I now go about coding my own function to return a pixel's colour by it's position? I've done a fair amount of searching and haven't found anything that covers this using C++.
BYTE GetPixelColor(BYTE* src, int x, int y, int srcWidth)
{
return src[y * srcWidth + x];
}
...
//suppose you have a 800 x 600 bmp, to get the color for pixel at x 30, y 200
BYTE color = GetPixelColor(src, 30, 200, 800);
You can't, not enough data. Almost all 8bpp pixel formats are indexed formats. They use a color table that stores the actual RGB color, the byte at the pixel location is an index into that table. The table contains 256 entries.
You'll also need a pointer to the color table.