2010-09-10 32 views
7

kullanarak pikseller arasında geçiş yapın Ekranın bir bölümünü kapıyorum ve belirli bir renk aralığı için pikselleri tarayacağım.GetDIBits ve X, Y

MSDN's Capturing an Image örneğine baktım ve işlevleri nasıl kullanacağımı biliyorum.

Bitleri bir diziye dönüştürebilirim, ancak bunu bir resim gibi dönebilmem için nasıl yapacağımı bilmiyorum. Bir sözde örnek (eminim yolu kapalı):

yapmak istediğim, bu nedenle kırmızı, mavi ve yeşil belli bir renk ise, ben öyle koordinat bilebilirsiniz temelde ne
for (x = 1; x <= Image.Width; x += 3) 
{ 
    for (y = 1; y <= Image.Height; y += 3) 
    { 
     red = lpPixels[x]; 
     green = lpPixels[x + 1]; 
     blue = lpPixels[x + 2]; 
    } 
} 

Resimdeki (x, y).

Sadece GetDIBits'i nasıl kullanacağımı ve bunu gerçekleştirebilmek için diziyi uygun şekilde nasıl ayarlayacağımı bilmiyorum.

cevap

11

Apart, daha karmaşık 16 bit modunda, burada basit Dizi yapısı üzerinde yürümeyi nasıl bir örnek.(Sen yineleme için örneğin Goz' code kullanabilirsiniz.)

GetDIBits reference @ MSDN

Sen uUsage için bayrak olarak DIB_RGB_COLORS seçip BITMAPINFO structure ve içerdiği BITMAPINFOHEADER structure kurmak zorunda. biClrUsed ve biClrImportant'u sıfır olarak ayarladığınızda, "hayır" renk tablosu vardır, böylece GetDIBits'dan aldığınız bitmap'in piksellerini RGB değerleri dizisi olarak okuyabilirsiniz. bit sayısı (biBitCount) halinde 32 kullanılması MSDN'ye uygun veri yapısı oluşturur:

bit eşlem 2^32 renk bir maksimum vardır. BITMAPINFOHEADER'un biCompression üyesi, BI_RGB ise, BITMAPINFO'un bmiColors üyesi, NULL'dur. Bitmap dizisindeki her DWORD, bir piksel için sırasıyla mavi, yeşil ve kırmızı göreceli yoğunlukları temsil eder. Her DWORD'daki yüksek bayt kullanılmaz. MS LONG yana

, siz (anlatıldığı gibi) dolgu dikkat etmek gerekmez (a DWORD büyüklüğünde) tam 32 bitlik uzun.

Kodu:

HDC hdcSource = NULL; // the source device context 
HBITMAP hSource = NULL; // the bitmap selected into the device context 

BITMAPINFO MyBMInfo = {0}; 
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader); 

// Get the BITMAPINFO structure from the bitmap 
if(0 == GetDIBits(hdcSource, hSource, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS)) 
{ 
    // error handling 
} 

// create the pixel buffer 
BYTE* lpPixels = new BYTE[MyBMInfo.bmiHeader.biSizeImage]; 

// We'll change the received BITMAPINFOHEADER to request the data in a 
// 32 bit RGB format (and not upside-down) so that we can iterate over 
// the pixels easily. 

// requesting a 32 bit image means that no stride/padding will be necessary, 
// although it always contains an (possibly unused) alpha channel 
MyBMInfo.bmiHeader.biBitCount = 32; 
MyBMInfo.bmiHeader.biCompression = BI_RGB; // no compression -> easier to use 
// correct the bottom-up ordering of lines (abs is in cstdblib and stdlib.h) 
MyBMInfo.bmiHeader.biHeight = abs(MyBMInfo.bmiHeader.biHeight); 

// Call GetDIBits a second time, this time to (format and) store the actual 
// bitmap data (the "pixels") in the buffer lpPixels 
if(0 == GetDIBits(hdcSource, hSource, 0, MyBMInfo.bmiHeader.biHeight, 
        lpPixels, &MyBMInfo, DIB_RGB_COLORS)) 
{ 
    // error handling 
} 
// clean up: deselect bitmap from device context, close handles, delete buffer 
+0

Kodda MyBMInfo .bmiHeader.biSize = sizeof (MyBMInfo); – xMRi

+0

@xMRi Haklısınız, hatayı tespit ettiğiniz için teşekkür ederiz. Şimdi sabit olduğunu düşünüyorum, ilk çağrısından önce başlatma işlemini GetDIBits'e taşıdım; AFAIK, ilk görüşmeden sonra yeniden başlatmak için gerekli değildir. – dyp

+0

Hmmm. Ben bu konuda emin değilim. Bunu kodumda denedim ve eğer GetDIBits'e ikinci çağrıyı yaparsam yerel yapının arabellek üzerine bir taşma hatası aldığını anladım ... Sonunda bir çözüme geri döndüm ve yapıyı manuel olarak başlattım. Bazı durumlarda sıkıştırma yapmak istemezsiniz. Bilgilendirmek, sıkıştırmayı yeniden kullanacak ... Bu doğru gelip gelmediğinden emin değilim. Ama bunu daha fazla kontrol etmek için zamanım olmadı. – xMRi

2

Bu kadar kolay değil. Algoritmanız, görüntünün renk derinliğine bağlı olacaktır. 256 veya daha azsa piksel renklerine sahip olmazsınız, ancak renk paletine girer. 16 bit pikseller RGB555 veya RGB565 olabilir, 24 bit görüntüler RGB888, 32 bit görüntüler RGBA veya ARGB olacaktır. Öğrenmek için BITMAPINFOHEADER'a ihtiyacınız olacak. öğrenmek kez

, piksel verileri sadece boyut genişlik bir dizi olacaktır * yükseklik * (BitsPerPixel/8)

+0

+ 1 içindedir. Alternatif olarak, sabit/bilinen renk derinliğine sahip bir bitmap'e kopyala/karıştırmayı deneyebilirsiniz. –

+0

OP'nin DeviceContext'e bitmap'i seçtiğini, bu yüzden bitmap üzerinde tam kontrol sahibi olduğunu düşünüyorum. 24 bit ve hiç sıkıştırma kullanılmadan kolayca RGB888 olarak okunabilir. – dyp

9

GetDIBits değerleri, tek boyutlu bir dizi döner. N piksel uzunluğundaki M piksel genişliğinde ve 24 bit renk kullanan bir bitmap için, ilk (M * 3) bayt, piksellerin ilk satırı olacaktır. Bu, bazı doldurma baytları tarafından takip edilebilir. Bu BITMAPINFOHEADER bağlıdır. Genişliği 4 byte'lık bir kat yapmak için genellikle dolgu vardır. Yani bitmap'iniz 33 piksel genişliğinde ise, aslında her satırda (36 * 3) bayt olacaktır.

Bu "piksel artı dolgu", "adım" olarak adlandırılır. RGB bitmap'leri için, adımı stride = (biWidth * (biBitCount/8) + 3) & ~3 ile hesaplayabilirsiniz, burada biWidth ve biBitCount, BITMAPINFOHEADER'dan alınır.

Dizinin geçişini nasıl yapmak istediğinizden emin değilim. Yayınladığınız linkte

for (row = 0; row < Image.Height; ++row) 
{ 
    int rowBase = row*stride; 
    for (col = 0; col < Image.Width; ++col) 
    { 
     red = lpPixels[rowBase + col]; 
     // etc. 
    } 
} 
+0

ha bu berbat stride = (biWidth * (biBitCount/8) + 3) & ~3 - anlaması biraz zaman aldı (bir sonraki UZUN = 4 [bayt] kadar yuvarlar). Ancak gerektiğinde dolguya dikkat etmenin kolay bir yolu. – dyp

+1

nihayet bir örnek 32 bit ilk önce bir dönüşüm gerektirme yerine göz önünde bulundurarak dikkate alır ... – rogerdpack

2

ben olacak bu yüzden 32 bit bitmap oluşturmak: Eğer gitmek isterseniz piksel-piksel üstten (bu yukarıdan aşağıya bitmaptir varsayarak) sağ alt sol 32 bitlik bir bitmap'ten okuduğunuzu varsayalım (Bu varsayım yanlış olabilir).

nedenle sizin döngü değiştirerek çalışmalıdır:

char* pCurrPixel = (char*)lpPixels; 
for (y = 0; y < Image.Height; y++) 
{ 
    for (x = 0; x < Image.Width; x++) 
    { 
     red = pCurrPixel[0]; 
     green = pCurrPixel[1]; 
     blue = pCurrPixel[2]; 

     pCurrPixel += 4; 
    } 
} 

şeyler akılda tutulması:

1.Arrays olan 0 C merkezli/C++
2. 3 piksel adım edildi her seferinde yatay ve dikey olarak. Yani her pikseli ziyaret etmiyorsun.
3. Bir bitmap genellikle "genişlik" piksellerinin "yükseklik" açıklıkları olacak şekilde düzenlenir. Bu nedenle, her piksele bir aralıkta geçmeli ve ardından bir sonraki aralığa geçmelisiniz.
4. Daha önce de işaret ettiğimiz gibi, pikselleri doğru okuduğunuzdan emin olun. Zaten verilen iyi cevaplardan

0

MSDN'den bazı sürpriz:

tablo RGBQUAD veri yapılarının bir dizi oluşur. (BITMAPCOREINFO biçimi için tablosu, RGBTRIPLE verisi yapısıyla oluşturulur.) Kırmızı, yeşil ve mavi baytlar , Windows sözleşmesindeki (kırmızı takas konumu) ters sıradadır.

yüzden, renk GetDIBits sonra bellekte BGR için()

İlgili konular