Creating BMP File - c++

I've been working for a while on image processing and I've noticed weird things.
I'm reading a BMP file, using simple methods like ReadFile and stuff, and using Microsoft's BMP structures.
Here is the code:
ReadFile(_bmpFile,&bmpfh,sizeof(bfh),&data,NULL);
ReadFile(_bmpFile, &bmpih, sizeof(bih), &data, NULL);
imagesize = bih.biWidth*bih.biHeight;
image = new RGBQUAD[imagesize];
ReadFile(_bmpFile,image, imagesize*sizeof(RGBQUAD),&written,NULL);
That is how I read the file and then I'm turning it into gray scale using a simple for-loop.
for (int i = 0; i < imagesize; i++)
{
RED = image[i].rgbRed;
GREEN = image[i].rgbGreen;
BLUE = image[i].rgbBlue;
avg = (RED + GREEN + BLUE ) / 3;
image[i].rgbRed = avg;
image[i].rgbGreen = avg;
image[i].rgbBlue = avg;
}
Now when I write the file using this code:
#pragma pack(push, 1)
WriteFile(_bmpFile, &bmpfh, sizeof(bfh), &data, NULL);
WriteFile(_bmpFile, &bmpih, sizeof(bih), &data, NULL);
WriteFile(_bmpFile, image, imagesize*sizeof(RGBQUAD), &written, NULL);
#pragma pack(pop)
The file is getting much bigger(30MB -> 40MB).
The reason it happens is because I'm using RGBQUAD instead RGBTRIPLE, but if i'm using RGBTRIPLE I have a problem converting small pictures into
gray scale - can't open the picture after creating it(says it's not in the right structure).
Also the file size is missing one byte, (1174kb and after 1173kb)
Has anybody seen this before (it only occurs with small pictures)?

In a BMP file, every scan line has to be padded out so the next scan line starts on a 32-bit boundary. If you do 32 bits per pixel, that happens automatically, but if you use 24 bits per pixel, you'll need to add code to do it explicitly.

You are ignoring stride (Jerry's comment) and the pixel format of the bitmap. Which is 24bpp judging by the file size increase, you are writing it as though it is 32bpp. Your grayscale conversion is wrong, the human eye isn't equally sensitive to red, green and blue.
Consider using GDI+, you #include <gdiplus.h> in your code to use the Bitmap class. Its LockBits() method gives you access to the bitmap bits. The ColorMatrixEffect class lets you apply a color transformation in a single operation. Check this answer for the color matrix you need to get a grayscale image. The MSDN docs start here.

Each horizontal row in a BMP must be a multiple of 4 bytes long.
If the pixel data does not take up a multiple of 4 bytes, then 0x00 bytes are added at the end of the row. For a 24-bpp image, the number of bytes per row is (imageWidth*3 + 3) & ~3. The number of padding bytes is ((imageWidth*3 + 3) & ~3) - (imageWidth*3).
This was answered by immibis.
I would like to add that the size of array is ((imageWidth*3 + 3) & ~3)*imageHeight.
I hope this helps

Related

How to get a pixel array from TBitmap?

In a camera application bitmap pixel arrays are retrieved from a streaming camera.
The pixel arrays are captured by writing them to a named pipe, where on the other end of the pipe, ffmpeg retrieves them and creates an AVI file.
I will need to create one custom frame (with custom text on), and pipe its pixels as the first frame in the resulting movie.
The question is how can I use a TBitmap (for convenience) to
Create a X by Y monochrome (8 bit) bitmap from scratch, with
custom text on. I want the background to be white, and the text to
be black. (Mostly figured this step out, see below.)
Retrieve the pixel array that I can send/write to the pipe
Step 1: The following code creates a TBitmap and writes text on it:
int w = 658;
int h = 492;
TBitmap* bm = new TBitmap();
bm->Width = w;
bm->Height = h;
bm->HandleType = bmDIB;
bm->PixelFormat = pf8bit;
bm->Canvas->Font->Name = "Tahoma";
bm->Canvas->Font->Size = 8;
int textY = 10;
string info("some Text");
bm->Canvas->TextOut(10, textY, info.c_str());
The above basically concludes step 1.
The writing/piping code expects a byte array with the bitmaps pixels; e.g.
unsigned long numWritten;
WriteFile(mPipeHandle, pImage, size, &numWritten, NULL);
where pImage is a pointer to a unsigned char buffer (the bitmaps pixels), and the size is the length of this buffer.
Update:
Using the generated TBitmap and a TMemoryStream for transferring data to the ffmpeg pipeline does not generate the proper result. I get a distorted image with 3 diagonal lines on it.
The buffersize for the camera frame buffers that I receive are are exactly 323736, which is equal to the number of pixels in the image, i.e. 658x492.
NOTE I have concluded that this 'bitmap' is not padded. 658 is not divisible by four.
The buffersize I get after dumping my generated bitmap to a memory stream, however, has the size 325798, which is 2062 bytes larger than it is supposed to be. As #Spektre pointed out below, this discrepancy may be padding?
Using the following code for getting the pixel array;
ByteBuffer CustomBitmap::getPixArray()
{
// --- Local variables --- //
unsigned int iInfoHeaderSize=0;
unsigned int iImageSize=0;
BITMAPINFO *pBitmapInfoHeader;
unsigned char *pBitmapImageBits;
// First we call GetDIBSizes() to determine the amount of
// memory that must be allocated before calling GetDIB()
// NB: GetDIBSizes() is a part of the VCL.
GetDIBSizes(mTheBitmap->Handle,
iInfoHeaderSize,
iImageSize);
// Next we allocate memory according to the information
// returned by GetDIBSizes()
pBitmapInfoHeader = new BITMAPINFO[iInfoHeaderSize];
pBitmapImageBits = new unsigned char[iImageSize];
// Call GetDIB() to convert a device dependent bitmap into a
// Device Independent Bitmap (a DIB).
// NB: GetDIB() is a part of the VCL.
GetDIB(mTheBitmap->Handle,
mTheBitmap->Palette,
pBitmapInfoHeader,
pBitmapImageBits);
delete []pBitmapInfoHeader;
ByteBuffer buf;
buf.buffer = pBitmapImageBits;
buf.size = iImageSize;
return buf;
}
So final challenge seem to be to get a bytearray that has the same size as the ones coming from the camera. How to find and remove the padding bytes from the TBitmap code??
TBitmap has a PixelFormat property to set the bit depth.
TBitmap has a HandleType property to control whether a DDB or a DIB is created. DIB is the default.
Since you are passing BMPs around between different systems, you really should be using DIBs instead of DDBs, to avoid any corruption/misinterpretation of the pixel data.
Also, this line of code:
Image1->Picture->Bitmap->Handle = bm->Handle;
Should be changed to this instead:
Image1->Picture->Bitmap->Assign(bm);
// or:
// Image1->Picture->Bitmap = bm;
Or this:
Image1->Picture->Assign(bm);
Either way, don't forget to delete bm; afterwards, since the TPicture makes a copy of the input TBitmap, it does not take ownership.
To get the BMP data as a buffer of bytes, you can use the TBitmap::SaveToStream() method, saving to a TMemoryStream. Or, if you just want the pixel data, not the complete BMP data (ie, without BMP headers - see Bitmap Storage), you can use the Win32 GetDiBits() function, which outputs the pixels in DIB format. You can't obtain a byte buffer of the pixels for a DDB, since they depend on the device they are rendered to. DDBs are only usable in-memory in conjunction with HDCs, you can't pass them around. But you can convert a DIB to a DDB once you have a final device to render it to.
In other words, get the pixels from the camera, save them to a DIB, pass that around as needed (ie, over the pipe), and then do whatever you need with it - save to a file, convert to DDB to render onscreen, etc.
This is just an addon to existing answer (with additional info after the OP edit)
Bitmap file-format has align bytes on each row (so there usually are some bytes at the end of each line that are not pixels) up to some ByteLength (present in bmp header). Those create the skew and diagonal like lines. In your case the size discrepancy is 4 bytes per row:
(xs + align)*ys + header = size
(658+ 4)*492 + 94 = 325798
but beware the align size depends on image width and bmp header ...
Try this instead:
// create bmp
Graphics::TBitmap *bmp=new Graphics::TBitmap;
// bmp->Assign(???); // a) copy image from ???
bmp->SetSize(658,492); // b) in case you use Assign do not change resolution
bmp->HandleType=bmDIB;
bmp->PixelFormat=pf8bit;
// bmp->Canvas->Draw(0,0,???); // b) copy image from ???
// here render your text using
bmp->Canvas->Brush->Style=bsSolid;
bmp->Canvas->Brush->Color=clWhite;
bmp->Canvas->Font->Color=clBlack;
bmp->Canvas->Font->Name = "Tahoma";
bmp->Canvas->Font->Size = 8;
bmp->Canvas->TextOutA(5,5,"Text");
// Byte data
for (int y=0;y<bmp->Height;y++)
{
BYTE *p=(BYTE*)bmp->ScanLine[y]; // pf8bit -> BYTE*
// here send/write/store ... bmp->Width bytes from p[]
}
// Canvas->Draw(0,0,bmp); // just renfder it on Form
delete bmp; bmp=NULL;
mixing GDI winapi calls for pixel array access (bitblt etc...) with VCL bmDIB bitmap might cause problems and resource leaks (hence the error on exit) and its also slower then usage of ScanLine[] (if coded right) so I strongly advice to use native VCL functions (as I did in above example) instead of the GDI/winapi calls where you can.
for more info see:
#4. GDI Bitmap
Delphi / C++ builder Windows 10 1709 bitmap operations extremely slow
Draw tbitmap with scale and alpha channel faster
Also you mention your image source is camera. If you use pf8bit it mean its palette indexed color which is relatively slow and ugly if native GDI algo is used (to convert from true/hi color camera image) for better transform see:
Effective gif/image color quantization?
simple dithering

How to write 512x512 pixel array to a bmp file (256 colors and 8 bpp) in c++ using ofstream?

Let me start with an intro. I've been reading about bitmap file format (wiki, msdn, etc) and researching how to read and write bmp files in c++. I'm writing a program in c++, without the use of bmp libraries, that can extract data from a bmp and then create a new bmp using that data. The purpose of this is to see if the new image file is the same as the original. Then if it works I can move on to manipulating the extracted data in order to perform histogram equalization.
Currently, my program is able to successfully retrieve the Bitmap file header and Bitmap information header from the original bmp file then write it to a new bmp file. It then does the same thing with the Color Table. The problem occurs, or at least this is what I currently believe, with the Pixel data. It looks like it is being read correctly and even looks like it is being written correctly at first glance. When I open the new file in a hex editor and compare it to the original it can be seen that the values begin to differ at offset (h) 630. Also, the new image when opened doesn't look like the original.
Here is the updated structure:
#pragma pack(2) // Using pragma to force structure format
struct BMPFH // Bitmap file header
{
char HeaderField[2]; // Used to identify the BMP and DIB file is 0x42 0x4D in hexadecimal, same as BM in ASCII
unsigned int Size_of_BMP; // size of the BMP file in bytes
unsigned short Reserved1; // Reserved; actual value depends on the application that creates the image
unsigned short Reserved2; // " "
unsigned int StartAddress; // offset, i.e. starting address, of the byte where the bitmap image data (pixel array) can be found
};
#pragma pack()
struct DIBH // Bitmap information header
{
unsigned int Size_of_Header; // Size of this header (40 bytes)
signed int Width; // bitmap width in pixels (signed integer)
signed int Height; // bitmap height in pixels (signed integer)
unsigned short Num_of_Planes; // number of color planes (must be 1)
unsigned short Num_of_Bits; // number of bits per pixel, which is the color depth (1, 4, 8, 16, 24, 32)
unsigned int CompMethod; // compression method being used (0, 1, 2, 3)
unsigned int Size_of_Raw; // size of the raw bitmap data
signed int HRes; // horizontal resolution of the image. (pixel per meter, signed integer)
signed int VRes; // vertical resolution of the image. (pixel per meter, signed integer)
unsigned int Num_of_Col; // number of colors in the color palette, or 0 to default to 2^n
unsigned int Num_of_ICol; // number of important colors used, or 0 when every color is important; generally ignored
};
struct ColorTable
{
unsigned char data[1024];
};
struct Pixel
{
unsigned char pix[262144];
};
This is the updated relevant code to the question:
//write pixel data to new file
unsigned char p;
for (int j = 0; j < H; j++)
{
for (int i = 0; i < W; i++)
{
p = opx.pix[j*W + i];
outFile.write(reinterpret_cast<char*>(&p), sizeof(p));
}
}
This is what outputs to the screen:
Bitmap File Header
Header Field: BM
Size of BMP: 263222
Start Address: 1078
Bitmap Information Header
Header size: 40
Image width: 512
Image height: 512
Number of bits for pixel: 8
Used compression: 0
Image size: 0
Horizontal resolution: 2835
Vertical resolution: 2835
Number of colors in the color palette: 256
Number of important colors used: 256
---------------------------------------------------
Total number of bytes to store one row of pixels: 512
Total amount of bytes to store the array of pixels: 262144
The first three entries in color table: 0 0 0
The first three pixels (Blue, Green, Red): 98 96 91
The hex editor I'm using is HxD. The compiler I'm using is Qt Creator.
And this is the bmp image I'm using: https://drive.google.com/file/d/0B4emsCaxwnh5c3IxNWdsc1k2MGs/view?usp=sharing
Thank you to anyone who spent their valuable time looking over this wall of text. I'd appreciate feedback and definitely let me know if I missed something obvious.
Your final nested loops (the output loop) are writing the same row of pixel data over and over.
//write pixel data to new file
unsigned char p;
for (int j = 0; j < H; j++)
{
for (int i = 0; i < W; i++)
{
p = opx.pix[i];
outFile.write(reinterpret_cast<char*>(&p), sizeof(p));
}
}
The i in this line:
p = opx.pix[i];
is the column offset. It starts over for each row.
To fix it, you can change it to:
p = opx.pix[j*W + i];
There are more efficient ways to do this, but this will get your code working.
The 630 in your hex editor is the offset (in hex) from the beginning of your file, and your problem appears to start six bytes after that. Note that 636h would be the first bytes of the second row of pixel data. (File header is 14 bytes, DIB header is 40 bytes, color table is 1024 bytes, first row is 512 bytes.) This was the clue as to where to look for the problem.

Writing a tif pixel by pixel using LibTiff?

Is it possible to create a new tif by iterating pixel by pixel and setting the RGB values for each pixel?
Let me explain what I'm attempting to do. I'm trying to open an existing tif, read it using TIFFReadRGBAImage, take the RGB values given by TIFFGetR/TIFFGetG/TIFFGetB, subtract them from 255, take those new values and use them to write each pixel one by one. In the end I'd like to end up with the original image and a new "complement" image that would be like a negative of the original.
Is there a way to do this using LibTiff? I've gone over the documentation and searched around Google but I've only seen very short examples of TIFFWriteScanline which provide so little lines of code/context/comments that I cannot figure out how to implement it in the way that I'd like it to work.
I'm still fairly new to programming so if someone could please either point me to a thorough example with plenty of explanatory comments or help me out directly with my code, I would appreciate it greatly. Thank you for taking the time to read this and help me learn.
What I have so far:
// Other unrelated code here...
//Invert color values and write to new image file
for (e = height - 1; e != -1; e--)
{
for (c = 0; c < width; c++)
{
red = TIFFGetR(raster[c]);
newRed = 255 - red;
green = TIFFGetG(raster[c]);
newGreen = 255 - green;
blue = TIFFGetB(raster[c]);
newBlue = 255 - blue;
// What to do next? Is this feasible?
}
}
// Other unrelated code here...
Full code if you need it.
I went back and looked at my old code. It turns out that I didn't use libtiff. Nevertheless you are on the right track. You want something like;
lineBuffer = (char *)malloc(width * 3) // 3 bytes per pixel
for all lines
{
ptr = lineBuffer
// modify your line code above so that you make a new line
for all pixels in line
{
*ptr++ = newRed;
*ptr++ = newGreen;
*ptr++ = newBlue
}
// write the line using libtiff scanline write
write a line here
}
Remember to set the tags appropriately. This example assumes 3 byte pixels. TIFF also allows for separate planes of 1 byte per pixel in each plane.
Alternately you can also write the whole image into a new buffer instead of one line at a time.

Setting individual pixels of an RGB frame for ffmpeg encoding

I'm trying to change the test pattern of an ffmpeg streamer, Trouble syncing libavformat/ffmpeg with x264 and RTP , into familiar RGB format. My broader goal is to compute frames of a streamed video on the fly.
So I replaced its AV_PIX_FMT_MONOWHITE with AV_PIX_FMT_RGB24, which is "packed RGB 8:8:8, 24bpp, RGBRGB..." according to http://libav.org/doxygen/master/pixfmt_8h.html .
To stuff its pixel array called data, I've tried many variations on
for (int y=0; y<HEIGHT; ++y) {
for (int x=0; x<WIDTH; ++x) {
uint8_t* rgb = data + ((y*WIDTH + x) *3);
const double i = x/double(WIDTH);
// const double j = y/double(HEIGHT);
rgb[0] = 255*i;
rgb[1] = 0;
rgb[2] = 255*(1-i);
}
}
At HEIGHTxWIDTH= 80x60, this version yields
, when I expect a single blue-to-red horizontal gradient.
640x480 yields the same 4-column pattern, but with far more horizontal stripes.
640x640, 160x160, etc, yield three columns, cyan-ish / magenta-ish / yellow-ish, with the same kind of horizontal stripiness.
Vertical gradients behave even more weirdly.
Appearance was unaffected by an AV_PIX_FMT_RGBA attempt (4 not 3 bytes per pixel, alpha=255). Also unaffected by a port from C to C++.
The argument srcStrides passed to sws_scale() is a length-1 array, containing the single int HEIGHT.
Access each Pixel of AVFrame asks the same question in less detail, so far unanswered.
The streamer emits one warning, which I doubt affects appearance:
[rtp # 0x269c0a0] Encoder did not produce proper pts, making some up.
So. How do you set the RGB value of a pixel in a frame to be sent to sws_scale() (and then to x264_encoder_encode() and av_interleaved_write_frame())?
Use avpicture_fill() as described in Encoding a screenshot into a video using FFMPEG .
Instead of passing data directly to sws_scale(), do this:
AVFrame* pic = avcodec_alloc_frame();
avpicture_fill((AVPicture *)pic, data, AV_PIX_FMT_RGB24, WIDTH, HEIGHT);
and then replace the 2nd and 3rd args of sws_scale() with
pic->data, pic->linesize,
Then the gradients above work properly, at many resolutions.
The argument srcStrides passed to sws_scale() is a length-1 array, containing the single int HEIGHT.
Stride (AKA linesize) is the distance in bytes between two lines. For various reasons having mostly to do with optimization it is often larger than simply width in bytes, so there is padding on the end of each line.
In your case, without any padding, stride should be width * 3.

C++ memcpy and happy access violation

For some reason i can't figure i am getting access violation.
memcpy_s (buffer, bytes_per_line * height, image, bytes_per_line * height);
This is whole function:
int Flip_Bitmap(UCHAR *image, int bytes_per_line, int height)
{
// this function is used to flip bottom-up .BMP images
UCHAR *buffer; // used to perform the image processing
int index; // looping index
// allocate the temporary buffer
if (!(buffer = (UCHAR *) malloc (bytes_per_line * height)))
return(0);
// copy image to work area
//memcpy(buffer, image, bytes_per_line * height);
memcpy_s (buffer, bytes_per_line * height, image, bytes_per_line * height);
// flip vertically
for (index = 0; index < height; index++)
memcpy(&image[((height - 1) - index) * bytes_per_line], &buffer[index * bytes_per_line], bytes_per_line);
// release the memory
free(buffer);
// return success
return(1);
} // end Flip_Bitmap
Whole code:
http://pastebin.com/udRqgCfU
To run this you'll need 24-bit bitmap, in your source directory.
This is a part of a larger code, i am trying to make Load_Bitmap_File function to work...
So, any ideas?
You're getting an access violation because a lot of image programs don't set biSizeImage properly. The image you're using probably has biSizeImage set to 0, so you're not allocating any memory for the image data (in reality, you're probably allocating 4-16 bytes, since most malloc implementations will return a non-NULL value even when the requested allocation size is 0). So, when you go to copy the data, you're reading past the ends of that array, which results in the access violation.
Ignore the biSizeImage parameter and compute the image size yourself. Keep in mind that the size of each scan line must be a multiple of 4 bytes, so you need to round up:
// Pseudocode
#define ROUNDUP(value, power_of_2) (((value) + (power_of_2) - 1) & (~((power_of_2) - 1)))
bytes_per_line = ROUNDUP(width * bits_per_pixel/8, 4)
image_size = bytes_per_line * height;
Then just use the same image size for reading in the image data and for flipping it.
As the comments have said, the image data is not necessarily width*height*bytes_per_pixel
Memory access is generally faster on 32bit boundaries and when dealing with images speed generally matters. Because of this the rows of an image are often shifted to start on a 4byte (32bit) boundary
If the image pixels are 32bit (ie RGBA) this isn't a problem but if you have 3bytes per pixel (24bit colour) then for certain image widths, where the number of columns * 3 isn't a multiple of 4, then extra blank bytes will be inserted at the edn of each row.
The image format probably has a "stride" width or elemsize value to tell you this.
You allocate bitmap->bitmapinfoheader.biSizeImage for image but proceed to copy bitmap->bitmapinfoheader.biWidth * (bitmap->bitmapinfoheader.biBitCount / 8) * bitmap->bitmapinfoheader.biHeight bytes of data. I bet the two numbers aren't the same.