2011-04-22 10 views
5

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.¿Cómo puedo leer los valores de píxel BMP en una matriz?

¡Gracias de antemano!

Respuesta

5

Lea el archivo en la memoria. Habrá un pequeño encabezado en la parte frontal, y el resto 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á BITMAPINFOHEADER. Esto será útil para determinar el formato de los píxeles.

Esto irá seguido de una paleta, si la profundidad de bits lo requiere.

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 se rellenará hasta el siguiente múltiplo de 4.

Casi se me olvida mencionar que es posible codificar un archivo JPEG o PNG como un BMP, pero esto es 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.

2

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

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

(He estado fuera de Win32 durante unos años, pero la función LoadImage se puede obtener un HBITMAP de un archivo BMP No estoy seguro de cómo convertir esto en. una matriz de píxeles directamente, pero me imagino que hay alguna contorsión con una CD que le permiten agarrar los valores http://support.microsoft.com/kb/158898

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

2

Usted tiene 2 buenas opciones:

  1. cargar y analizar el archivo BMP 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. Llamada LoadImage() API 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 mapa de bits, formato, puntero a datos de píxeles, etc.

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

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

+0

¡Gracias por la información! –

12

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

#pragma pack(1) 

#include <iostream> 
#include <fstream> 
#include <vector> 

using namespace std; 

#include "bmp.h" 

vector<char> 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 han definido:

#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; 
+0

#include "bmp.h"? No es un archivo de inclusión estándar. –

+0

@Alexey Frunze, bmp.h added – Yola

+1

También creo que OP desea una matriz de colores de píxeles, no una matriz de todos los bytes de archivos. –

4

si la codificación en Estudios Visuales , antes de declarar las estructuras tagBITMAPFILEHEADER y tagBITMAPINFOHEADER (mostradas 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

2

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

#include <iostream> 
#include <unistd.h> 
#include <fstream> 

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; 
} 
Cuestiones relacionadas