2011-04-22 21 views
5

C++ (Windows'ta) kod yazıyorum ve gri tonlama bmp'nin piksel değerlerini ayıklamaya çalışıyorum. Meta verilerinin hiçbirini tutmama umurumda değil ve sadece piksel değerlerini bir char dizisinde saklamak istiyorum. Bunu el ile yapmanın standart veya "tipik" bir yolunu bulamadım, bu yüzden insanların belleğe bitmapler yüklemek için kullandıkları basit bir kütüphane olup olmadığını merak ediyorum.BMP piksel değerlerini bir diziye nasıl okuyabilirim?

Şimdiden teşekkürler!

cevap

5

belleğe dosyanın tamamını okuyun. Ön tarafta küçük bir başlık olacak ve geri kalanı piksel değerleri olacak.

İlk bölüm, BITMAPFILEHEADER yapısı olacaktır. Önemsediğiniz tek kısım, dosyanın başlangıcından piksel değerlerine bayt sayısı veren bfOffBits'dir.

BITMAPFILEHEADER sonraki bölümü BITMAPINFOHEADER olacaktır. Bu, piksellerin formatını belirlemek için yararlı olacaktır.

Bit derinliği bir tane gerektiriyorsa, bunu bir palet takip edecektir.

Piksel değerleriyle bir çift yakalama var. Birincisi, emrin (mavi, yeşil, kırmızı), herkesin yaptığı yolun tam tersidir. İkincisi, satırların görüntünün alttan üstüne, yine herkesten geriye doğru gitmesidir. Son olarak, bir satırdaki bayt sayısı her zaman bir sonraki çoklu öğeye kadar doldurulacaktır. 4.

Neredeyse bahsetmeyi unuttum, bir JPEG veya PNG dosyasının BMP olarak kodlanması mümkündür, ancak bu Yaygın değil. BITMAPINFOHEADER'un biCompression alanına bir göz atın, eğer BI_RGB'den başka bir şey varsa biraz daha yardıma ihtiyacınız olacak.

2

Orada kesinlikle (diğer cevaplar bakın) orada kütüphaneler, ancak bir anda, bu oldukça kolay kendinizi ayrıştırmak bir beyin ölümü basit dosya biçimi açıkçası bu. Detaylar burada:

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

(Birkaç yıldır Win32 dışına oldum, ama bir BMP dosyası size bir HBITMAP alabilirsiniz LoadImage işlevi ben dönüştürmeye nasıl emin değilim. bir piksel dizisi doğrudan, ama değerlerini yakalamak izin verecek bir DC ile bazı contortion olmadığını hayal ediyorum http://support.microsoft.com/kb/158898

Daha ipuçları:. http://alexkr.com/source-code/26/accessing-bitmap-pixels-in-gdi/)

2

Sen 2 iyi seçenek vardır:

  1. Yük ve BMP dosyasını kendiniz ayrıştırmak. BMP dosyaları bir BITMAPFILEHADER ile başlar, bunu BITMAPINFOHEADER takip eder, ardından 0 veya daha fazla RGBQUAD (palet girişi) takip eder. Piksel verisine ofset BITMAPFILEHADER'dadır, ancak görüntü formatının beklediğiniz/desteklediğinizden emin olmak için BITMAPINFOHEADER öğesini işaretlemelisiniz. LR_CREATEDIBSECTION bayrağıyla

  2. Çağrı LOADIMAGE() API, bir DIB bölümüne bir kolu dönecektir. Ardından, döndürülen tanıtıcıda GetObject() yöntemini ve bir DIBSECTION yapısının işaretçisini çağırırsınız. Daha sonra bitmap boyutu, format, piksel verisine işaretçi vb. Için DIBSECTION yapısını okursunuz.Windows üzerinde iseniz muhtemelen LOADIMAGE() sizin için geçersiz dosya biçimleri için denetler ve sadece BMP dosyaları daha yükleyebilirsiniz çünkü

Seçenek 2, daha iyidir. , Windows BMP piksel erişirken

, çizgiler hep DWORD hizalı olduğunu unutmayın.

+0

teşekkürler! –

12

ve kodu, g ile test gitmeye hazır ++ (Windows, ancak yardımcı olabilir birisi): bmp.hi olarak

#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; 
} 

tanımladık yapılar:

#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"? Standart bir dosya değil. –

+0

@Alexey Frunze, bmp.h ben de OP piksel renk dizisi, tüm dosya bayt değil bir dizi istediğini düşünüyorum – Yola

+1

eklendi. –

4

eğer Görsel Studios kodlama (Yola tepki gösterilen) sizin tagBITMAPFILEHEADER ve tagBITMAPINFOHEADER yapılar "# Pragma paketi (2)" eklemeyi unutmayın ilan etmeden önce. Ohterwise yapı, sonraki 2 bayt sınırı yerine sonraki 4 bayt sınırına kadar doldurulur ve veriler çöp olacaktır.

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

2

Yola yazdıklarına şekilde anlatıldığı bu dosyayı okumak ve çıkış mümkün olmalıdır. İyi test edilmiyor, ama işe yarıyor gibi görünüyor. Çıktığında okuduğu dosyanın formatını kullanır. bilgi için

#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; 
} 
İlgili konular