Reading pixel value in bmp file

How can I find out the color value of 24-bit BMP images on all pixels [h * w] in C or C ++ on Windows [better without any third-party library]. I got Dev-C ++
The working code will be really appreciated since I never worked on reading images and came to SO after Googling [if you can google better than me, plz provide a link].

+10
source share
8 answers

You can try the following:

unsigned char* readBMP(char* filename) { int i; FILE* f = fopen(filename, "rb"); unsigned char info[54]; fread(info, sizeof(unsigned char), 54, f); // read the 54-byte header // extract image height and width from header int width = *(int*)&info[18]; int height = *(int*)&info[22]; int size = 3 * width * height; unsigned char* data = new unsigned char[size]; // allocate 3 bytes per pixel fread(data, sizeof(unsigned char), size, f); // read the rest of the data at once fclose(f); for(i = 0; i < size; i += 3) { unsigned char tmp = data[i]; data[i] = data[i+2]; data[i+2] = tmp; } return data; } 

data should now contain (R, G, B) pixel values. The pixel color (i, j) is stored in data[3 * (i * width + j)] , data[3 * (i * width + j) + 1] and data[3 * (i * width + j) + 2] .

In the last part, a swap between each first and third pixel is performed because the windows store the color values ​​as (B, G, R), and not (R, G, B).

+40
source

ReadBMP function code after correction:

 unsigned char* ReadBMP(char* filename) { int i; FILE* f = fopen(filename, "rb"); if(f == NULL) throw "Argument Exception"; unsigned char info[54]; fread(info, sizeof(unsigned char), 54, f); // read the 54-byte header // extract image height and width from header int width = *(int*)&info[18]; int height = *(int*)&info[22]; cout << endl; cout << " Name: " << filename << endl; cout << " Width: " << width << endl; cout << "Height: " << height << endl; int row_padded = (width*3 + 3) & (~3); unsigned char* data = new unsigned char[row_padded]; unsigned char tmp; for(int i = 0; i < height; i++) { fread(data, sizeof(unsigned char), row_padded, f); for(int j = 0; j < width*3; j += 3) { // Convert (B, G, R) to (R, G, B) tmp = data[j]; data[j] = data[j+2]; data[j+2] = tmp; cout << "R: "<< (int)data[j] << " G: " << (int)data[j+1]<< " B: " << (int)data[j+2]<< endl; } } fclose(f); return data; } 
+16
source

Here is the working version of the answer in C ++:

 #include <fstream> #include <iostream> #include <string> #include <array> #include <vector> #include <iterator> std::vector<char> readBMP(const std::string &file) { static constexpr size_t HEADER_SIZE = 54; std::ifstream bmp(file, std::ios::binary); std::array<char, HEADER_SIZE> header; bmp.read(header.data(), header.size()); auto fileSize = *reinterpret_cast<uint32_t *>(&header[2]); auto dataOffset = *reinterpret_cast<uint32_t *>(&header[10]); auto width = *reinterpret_cast<uint32_t *>(&header[18]); auto height = *reinterpret_cast<uint32_t *>(&header[22]); auto depth = *reinterpret_cast<uint16_t *>(&header[28]); std::cout << "fileSize: " << fileSize << std::endl; std::cout << "dataOffset: " << dataOffset << std::endl; std::cout << "width: " << width << std::endl; std::cout << "height: " << height << std::endl; std::cout << "depth: " << depth << "-bit" << std::endl; std::vector<char> img(dataOffset - HEADER_SIZE); bmp.read(img.data(), img.size()); auto dataSize = ((width * 3 + 3) & (~3)) * height; img.resize(dataSize); bmp.read(img.data(), img.size()); char temp = 0; for (auto i = dataSize - 4; i >= 0; i -= 3) { temp = img[i]; img[i] = img[i+2]; img[i+2] = temp; std::cout << "R: " << int(img[i] & 0xff) << " G: " << int(img[i+1] & 0xff) << " B: " << int(img[i+2] & 0xff) << std::endl; } return img; } 
+5
source

I cannot comment on the top-level answer, because I do not have enough stackoverflow representatives yet, but I just wanted to point out one very important error in this implementation.

Some bitmaps may be recorded at negative heights, so when you try to allocate an image data buffer, your std::bad_alloc crashes with std::bad_alloc . Negative height bitmaps mean that image data is stored top-down instead of traditional bottom-up. Thus, a slightly better version of the top-level answer (still not including portability for systems with different byte order and byte size):

 unsigned char* readBMP(char* filename) { int i; FILE* f = fopen(filename, "rb"); unsigned char info[54]; fread(info, sizeof(unsigned char), 54, f); // read the 54-byte header // extract image height and width from header int width, height; memcpy(&width, info + 18, sizeof(int)); memcpy(&height, info + 22, sizeof(int)); int heightSign = 1; if (height < 0){ heightSign = -1; } int size = 3 * width * abs(height); unsigned char* data = new unsigned char[size]; // allocate 3 bytes per pixel fread(data, sizeof(unsigned char), size, f); // read the rest of the data at once fclose(f); if(heightSign == 1){ for(i = 0; i < size; i += 3) { //code to flip the image data here.... } } return data; } 
+4
source

I created a BitMap class that works for bmp files that have 24 bits per pixel. If bmp is not compatible, you should get the corresponding error.

This almost exactly matches the Wikipedia article . (One problem is that it does not work with files with a pixel array offset greater than 255. This is noted in the code and should be easily fixed.)

I used this with bmp files created by mspaint.

Here is a usage example

example.cpp

 #include "bmp.h" int main() { // load the file. The constructor now does most of the work BitMap example_bmp("examplefile.bmp"); // get the vector <R,G,B> for the pixel at (1,1) std::vector<unsigned int> example_vector = example_bmp.getPixel(1,1); } 

example_vector now contains the rgb values ​​(in that order) of the pixel at coordinate (1,1), indexed from the top of the image, down. Indexes start from zero. See Examples on Wikipedia.

Here is the header file:

 #ifndef BMP_H #define BMP_H #include <iostream> #include <vector> #include <fstream> class BitMap { private: unsigned char m_bmpFileHeader[14]; unsigned int m_pixelArrayOffset; unsigned char m_bmpInfoHeader[40]; int m_height; int m_width; int m_bitsPerPixel; int m_rowSize; int m_pixelArraySize; unsigned char* m_pixelData; char * m_copyname; const char * m_filename; public: BitMap(const char * filename); ~BitMap(); std::vector<unsigned int> getPixel(int i,int j); void makeCopy(char * filename); void writePixel(int i,int j, int R, int G, int B); void swapPixel(int i, int j, int i2, int j2); void dispPixelData(); int width() {return m_width;} int height() {return m_height;} int vd(int i, int j); int hd(int i, int j); bool isSorted(); }; BitMap::BitMap( const char * filename) { using namespace std; m_filename = filename; ifstream inf(filename); if(!inf) { cerr<<"Unable to open file: "<<filename<<"\n"; } //unsigned char m_bmpFileHeader[14]; unsigned char a; for(int i =0;i<14;i++) { inf>>hex>>a; m_bmpFileHeader[i] = a; } if(m_bmpFileHeader[0]!='B' || m_bmpFileHeader[1]!='M') { cerr<<"Your info header might be different!\nIt should start with 'BM'.\n"; } /* THE FOLLOWING LINE ONLY WORKS IF THE OFFSET IS 1 BYTE!!!!! (it can be 4 bytes max) That should be fixed now. old line was m_pixelArrayOffset = m_bmpFileHeader[10]; */ unsigned int * array_offset_ptr = (unsigned int *)(m_bmpFileHeader + 10); m_pixelArrayOffset = *array_offset_ptr; if( m_bmpFileHeader[11] != 0 || m_bmpFileHeader[12] !=0 || m_bmpFileHeader[13] !=0 ) { std::cerr<< "You probably need to fix something. bmp.h("<<__LINE__<<")\n"; } //unsigned char m_bmpInfoHeader[40]; for(int i=0;i<40;i++) { inf>>hex>>a; m_bmpInfoHeader[i]=a; } int * width_ptr = (int*)(m_bmpInfoHeader+4); int * height_ptr = (int*)(m_bmpInfoHeader+8); m_width = *width_ptr; m_height = *height_ptr; printf("W: %i, H: %i", m_width, m_height); m_bitsPerPixel = m_bmpInfoHeader[14]; if(m_bitsPerPixel!=24) { cerr<<"This program is for 24bpp files. Your bmp is not that\n"; } int compressionMethod = m_bmpInfoHeader[16]; if(compressionMethod!=0) { cerr<<"There some compression stuff going on that we might not be able to deal with.\n"; cerr<<"Comment out offending lines to continue anyways. bpm.h line: "<<__LINE__<<"\n"; } m_rowSize = int( floor( (m_bitsPerPixel*m_width + 31.)/32 ) ) *4; m_pixelArraySize = m_rowSize* abs(m_height); m_pixelData = new unsigned char [m_pixelArraySize]; inf.seekg(m_pixelArrayOffset,ios::beg); for(int i=0;i<m_pixelArraySize;i++) { inf>>hex>>a; m_pixelData[i]=a; } } BitMap::~BitMap() { delete[] m_pixelData; } void BitMap::dispPixelData() { for(int i=0;i<m_pixelArraySize;i++) { std::cout<<(unsigned int)m_pixelData[i]<<" "; } std::cout<<"\n"; } // output is in rgb order. std::vector<unsigned int> BitMap::getPixel(int x, int y) { if(x<m_width && y<m_height) { std::vector<unsigned int> v; v.push_back(0); v.push_back(0); v.push_back(0); y = m_height -1- y; //to flip things //std::cout<<"y: "<<y<<" x: "<<x<<"\n"; v[0] = (unsigned int) ( m_pixelData[ m_rowSize*y+3*x+2 ] ); //red v[1] = (unsigned int) ( m_pixelData[ m_rowSize*y+3*x+1 ] ); //greed v[2] = (unsigned int) ( m_pixelData[ m_rowSize*y+3*x+0 ] ); //blue return v; } else {std::cerr<<"BAD INDEX\n";std::cerr<<"X: "<<x<<" Y: "<<y<<"\n";} } void BitMap::makeCopy(char * filename) { std::ofstream copyfile(filename); std::ifstream infile(m_filename); m_copyname = filename; unsigned char c; while(infile) { infile>>c; copyfile<<c; } } // changes the file void BitMap::writePixel(int x,int y, int R, int G, int B) { std::fstream file(m_filename); y = m_height -1- y; // to flip things. int blueOffset = m_pixelArrayOffset+m_rowSize*y+3*x+0; // writes to the file file.seekg(blueOffset,std::ios::beg); file<< (unsigned char)B; file.seekg(blueOffset+1,std::ios::beg); file<< (unsigned char)G; file.seekg(blueOffset+2,std::ios::beg); file<< (unsigned char)R; // edits data in pixelData array m_pixelData[m_rowSize*y+3*x+2] = (unsigned char)R; m_pixelData[m_rowSize*y+3*x+1] = (unsigned char)G; m_pixelData[m_rowSize*y+3*x+0] = (unsigned char)B; } // changes the file void BitMap::swapPixel(int i, int j, int i2, int j2) { std::vector<unsigned int> p1 = (*this).getPixel(i,j); std::vector<unsigned int> p2 = (*this).getPixel(i2,j2); (*this).writePixel(i,j,p2[0],p2[1],p2[2]); (*this).writePixel(i2,j2,p1[0],p1[1],p1[2]); } #endif 
+3
source

You must read the bitmap title first. Having received the data offset that you will find in the headers of the bitmap images, and read the pixels line by line, pay attention to the filling in the BMP format.

take a look at msdn http://msdn.microsoft.com/en-us/library/aa452883.aspx

http://msdn.microsoft.com/en-us/library/windows/desktop/dd318229(v=vs.85).aspx

+2
source

A simple, OS-portable Python solution is provided in How can I read the RGB value of a given pixel in Python? . Adapts to several image formats, takes care of filling, etc.

+1
source

I tried the codes above and I quoted below as a link (sorry, I didn’t have a reputation to make a comment).

The code compiles OK, but crashes during the for loop. I think this has something to do with 'i' being uint32_t, instead of int. When the "i" reaches zero, the for loop remains valid, and the "i" decreases by 3, which becomes a negative value. Since "i" is uint32_t, its value becomes positive and greater than 0. As such, the for loop never ends and causes a run-time failure when "i" points to the limits of the img memory boundary.

 #include <fstream> #include <iostream> #include <string> #include <array> #include <vector> #include <iterator> std::vector<char> readBMP(const std::string &file) { static constexpr size_t HEADER_SIZE = 54; std::ifstream bmp(file, std::ios::binary); std::array<char, HEADER_SIZE> header; bmp.read(header.data(), header.size()); auto fileSize = *reinterpret_cast<uint32_t *>(&header[2]); auto dataOffset = *reinterpret_cast<uint32_t *>(&header[10]); auto width = *reinterpret_cast<uint32_t *>(&header[18]); auto height = *reinterpret_cast<uint32_t *>(&header[22]); auto depth = *reinterpret_cast<uint16_t *>(&header[28]); std::cout << "fileSize: " << fileSize << std::endl; std::cout << "dataOffset: " << dataOffset << std::endl; std::cout << "width: " << width << std::endl; std::cout << "height: " << height << std::endl; std::cout << "depth: " << depth << "-bit" << std::endl; std::vector<char> img(dataOffset - HEADER_SIZE); bmp.read(img.data(), img.size()); auto dataSize = ((width * 3 + 3) & (~3)) * height; img.resize(dataSize); bmp.read(img.data(), img.size()); char temp = 0; for (auto i = dataSize - 4; i >= 0; i -= 3) { temp = img[i]; img[i] = img[i+2]; img[i+2] = temp; std::cout << "R: " << int(img[i] & 0xff) << " G: " << int(img[i+1] & 0xff) << " B: " << int(img[i+2] & 0xff) << std::endl; } return img; } 
-3
source

All Articles