¿Cómo puedo leer los valores de píxel BMP en una matriz?

Estoy escribiendo código en C ++ (en Windows) y estoy tratando de extraer los valores de píxel de un bmp en escala de grises. No me importa guardar ninguno de los metadatos, y solo quiero almacenar los valores de píxel en una matriz de caracteres. No he podido encontrar una forma estándar o “típica” de hacerlo manualmente, así que me pregunto si es posible que haya una biblioteca simple que las personas usen para cargar mapas de bits en la memoria.

¡Gracias por adelantado!

Lea el archivo completo en la memoria. Habrá un pequeño encabezado en la parte frontal, y el rest serán los valores de píxel.

La primera parte será una estructura BITMAPFILEHEADER . La única parte que te importa es bfOffBits, que da la cantidad de bytes desde el inicio del archivo a los valores de píxel.

La siguiente parte después de BITMAPFILEHEADER será un BITMAPINFOHEADER . Esto será útil para determinar el formato de los píxeles.

Esto será seguido por una paleta, si la profundidad de bits requiere uno.

Hay un par de errores con los valores de píxel. Lo primero es que el orden es (azul, verde, rojo), justo al contrario de lo que hacen los demás. En segundo lugar, las filas van de abajo hacia arriba de la imagen, una vez más hacia atrás de todos los demás. Finalmente, el número de bytes en una fila siempre será rellenado hasta el próximo múltiplo de 4.

Casi me olvido de mencionar que es posible codificar un archivo JPEG o PNG como BMP, pero esto no es común. Eche un vistazo al campo biCompression del BITMAPINFOHEADER , si es cualquier cosa menos BI_RGB necesitará un poco más de ayuda.

y código listo para usar, probado con g ++ (no con Windows, pero puede ayudar a alguien):

 #pragma pack(1) #include  #include  #include  using namespace std; #include "bmp.h" vector buffer; PBITMAPFILEHEADER file_header; PBITMAPINFOHEADER info_header; void fill() { std::ifstream file("data.bmp"); if (file) { file.seekg(0,std::ios::end); streampos length = file.tellg(); file.seekg(0,std::ios::beg); buffer.resize(length); file.read(&buffer[0],length); file_header = (PBITMAPFILEHEADER)(&buffer[0]); info_header = (PBITMAPINFOHEADER)(&buffer[0] + sizeof(BITMAPFILEHEADER)); } } int main() { fill(); cout << buffer[0] << buffer[1] << endl; cout << file_header->bfSize << endl; cout << info_header->biWidth << " " << info_header->biHeight << endl; return 0; } 

En bmp.hi tenemos estructuras definidas:

 #pragma once typedef int LONG; typedef unsigned short WORD; typedef unsigned int DWORD; typedef struct tagBITMAPFILEHEADER { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER, *PBITMAPFILEHEADER; typedef struct tagBITMAPINFOHEADER { DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER, *PBITMAPINFOHEADER; 

si está codificando en Visual Studios, antes de declarar las estructuras tagBITMAPFILEHEADER y tagBITMAPINFOHEADER (que se muestran en la respuesta de Yola), asegúrese de incluir “#pragma pack (2)”. O bien, la estructura se rellenará con el siguiente límite de 4 bytes, en lugar del siguiente límite de 2 bytes, y los datos serán basura.

referencia http://tipsandtricks.runicsoft.com/Cpp/BitmapTutorial.html

Puedes probar MagicWand y una API de la biblioteca de ImageMagic .

Definitivamente hay bibliotecas por ahí (ver otras respuestas), pero en un santiamén, es francamente un formato de archivo simple con muerte cerebral que puedes analizar fácilmente. Los detalles están aquí:

http://www.fileformat.info/format/bmp/egff.htm

(He estado fuera de Win32 durante algunos años, pero la función LoadImage puede obtener un HBITMAP de un archivo BMP. No estoy seguro de cómo convertirlo en una matriz de píxeles directamente, pero me imagino que hay cierta contorsión con un DC que le permitiría captar los valores. http://support.microsoft.com/kb/158898

Más consejos: http://alexkr.com/source-code/26/accessing-bitmap-pixels-in-gdi/ )

Tienes 2 buenas opciones:

  1. Cargue y analice el archivo BMP usted mismo. Los archivos BMP comienzan con BITMAPFILEHADER, seguido de BITMAPINFOHEADER, seguido de 0 o más RGBQUAD (entrada de paleta). Los datos de desplazamiento a píxel están en BITMAPFILEHADER, pero debe verificar BITMAPINFOHEADER para asegurarse de que el formato de imagen sea el que espera / admite.

  2. Llame a la API de LoadImage () con el indicador LR_CREATEDIBSECTION, devolverá un identificador a una sección DIB. A continuación, llama a GetObject () pasando el identificador devuelto y un puntero a una estructura DIBSECTION. Luego, lee la estructura DIBSECTION para tamaño de bitmap, formato, puntero a datos de píxeles, etc.

La opción 2 es mejor si está en Windows, porque presumiblemente LoadImage () busca los formatos de archivo no válidos para usted y puede cargar más que solo archivos BMP.

Al acceder a los píxeles BMP de Windows, recuerde que las líneas siempre están alineadas con DWORD.

Ampliando lo que Yola escribió, esto debería ser capaz de leer y sacar un archivo. No está bien probado, pero parece funcionar. Utiliza el formato del archivo que lee cuando se genera.

 #include  #include  #include  using std::cout; using std::endl; using std::ofstream; using std::ifstream; #pragma pack(1) #pragma once typedef int LONG; typedef unsigned short WORD; typedef unsigned int DWORD; typedef struct tagBITMAPFILEHEADER { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER, *PBITMAPFILEHEADER; typedef struct tagBITMAPINFOHEADER { DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER, *PBITMAPINFOHEADER; unsigned char** reds; unsigned char** greens; unsigned char** blues; int rows; int cols; void ColorTest() { // Makes Red Rectangle in top left corner. Rectangle stretches to right alot for (int i = rows / 10; i < 3 * rows / 10; i++) for (int j = cols / 10; j < 7 * cols / 10; j++) reds[i][j] = 0xff; // Makes small green box in bottom right for (int i = 8 * rows / 10; i < rows; i++) for (int j = 8 * cols / 10; j < cols; j++) greens[i][j] = 0xff; // Makes White box in the middle of the screeene for (int i = rows * 4 / 10; i < rows * 6 / 10; i++) for (int j = cols * 4 / 10; j < cols * 6 / 10; j++) { greens[i][j] = 0xff; reds[i][j] = 0xff; blues[i][j] = 0xff; } // Blue verticle rectangle bottom left for (int i = rows * 6 / 10; i < rows; i++) for (int j = cols * 0; j < cols * 1 / 10; j++) blues[i][j] = 0xff; } void RGB_Allocate(unsigned char**& dude) { dude = new unsigned char*[rows]; for (int i = 0; i < rows; i++) dude[i] = new unsigned char[cols]; } bool FillAndAllocate(char*& buffer, const char* Picture, int& rows, int& cols, int& BufferSize) { //Returns 1 if executed sucessfully, 0 if not sucessfull std::ifstream file(Picture); if (file) { file.seekg(0, std::ios::end); std::streampos length = file.tellg(); file.seekg(0, std::ios::beg); buffer = new char[length]; file.read(&buffer[0], length); PBITMAPFILEHEADER file_header; PBITMAPINFOHEADER info_header; file_header = (PBITMAPFILEHEADER) (&buffer[0]); info_header = (PBITMAPINFOHEADER) (&buffer[0] + sizeof(BITMAPFILEHEADER)); rows = info_header->biHeight; cols = info_header->biWidth; BufferSize = file_header->bfSize; return 1; } else { cout << "File" << Picture << " don't Exist!" << endl; return 0; } } void GetPixlesFromBMP24(unsigned char** reds, unsigned char** greens, unsigned char** blues, int end, int rows, int cols, char* FileReadBuffer) { // end is BufferSize (total size of file) int count = 1; int extra = cols % 4; // The nubmer of bytes in a row (cols) will be a multiple of 4. for (int i = 0; i < rows; i++){ count += extra; for (int j = cols - 1; j >= 0; j--) for (int k = 0; k < 3; k++) { switch (k) { case 0: reds[i][j] = FileReadBuffer[end - count++]; break; case 1: greens[i][j] = FileReadBuffer[end - count++]; break; case 2: blues[i][j] = FileReadBuffer[end - count++]; break; } } } } void WriteOutBmp24(char* FileBuffer, const char* NameOfFileToCreate, int BufferSize) { std::ofstream write(NameOfFileToCreate); if (!write) { cout << "Failed to write " << NameOfFileToCreate << endl; return; } int count = 1; int extra = cols % 4; // The nubmer of bytes in a row (cols) will be a multiple of 4. for (int i = 0; i < rows; i++){ count += extra; for (int j = cols - 1; j >= 0; j--) for (int k = 0; k < 3; k++) { switch (k) { case 0: //reds FileBuffer[BufferSize - count] = reds[i][j]; break; case 1: //green FileBuffer[BufferSize - count] = greens[i][j]; break; case 2: //blue FileBuffer[BufferSize - count] = blues[i][j]; break; } count++; } } write.write(FileBuffer, BufferSize); } int main(int args, char** cat) { char* FileBuffer; int BufferSize; #define Picture "ReadInPicture.bmp" if (!FillAndAllocate(FileBuffer, Picture, rows, cols, BufferSize)){cout << "File read error" << endl; return 0;} cout << "Rows: " << rows << " Cols: " << cols << endl; RGB_Allocate(reds); RGB_Allocate(greens); RGB_Allocate(blues); GetPixlesFromBMP24( reds, greens, blues,BufferSize, rows, cols, FileBuffer); ColorTest(); #define WriteOutFile "OutputPicture.bmp" WriteOutBmp24(FileBuffer, WriteOutFile,BufferSize); return 1; } 
    Intereting Posts