10

画面の一部をつかみ、特定の色範囲のピクセルをスキャンしています。

MSDN の Capturing an Image の例を見て、関数の使用方法を知っています。

ビットを配列に入れることはできますが、画像のようにループできるようにする方法がわかりません。疑似例(これはかなり外れていると確信しています):

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

それが基本的に私がやりたいことなので、赤、青、緑が特定の色である場合、画像の (x, y) の座標がわかります。

そのような方法で GetDIBits を使用する方法と、これを達成できるように配列を適切にセットアップする方法がわかりません。

4

5 に答える 5

15

すでに与えられた良い答えとは別に、単純な配列構造を取得する方法の例を次に示します。(反復には、たとえばGoz のコードを使用できます。)

GetDIBits リファレンス @ MSDN

DIB_RGB_COLORSフラグとして選択し、構造とそれに含まれる構造uUsageを設定する必要があります。とを 0 に設定すると、カラー テーブルが「存在しない」ため、取得したビットマップのピクセルをRGB 値のシーケンスとして読み取ることができます。as bit count ( )を使用すると、MSDN に従ってデータ構造がセットアップされます。BITMAPINFOBITMAPINFOHEADERbiClrUsedbiClrImportantGetDIBits32biBitCount

ビットマップには最大 2^32 色があります。biCompressionのメンバーが の場合、のメンバーBITMAPINFOHEADERはです。ビットマップ配列のそれぞれは、ピクセルの青、緑、赤の相対強度をそれぞれ表します。それぞれの上位バイトは使用されません。BI_RGBbmiColorsBITMAPINFONULLDWORDDWORD

MSLONGは正確に 32 ビットの長さ ( のサイズDWORD) であるため、パディングに注意を払う必要はありません (「備考」セクションで説明されているように)。

コード:

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
于 2010-09-10T22:02:36.910 に答える
10

GetDIBits値の 1 次元配列を返します。幅 M ピクセル、高さ N ピクセルで 24 ビット色を使用するビットマップの場合、最初の (M*3) バイトがピクセルの最初の行になります。その後に、いくつかのパディング バイトが続く場合があります。BITMAPINFOHEADER に依存します。通常、幅を 4 バイトの倍数にするためのパディングがあります。したがって、ビットマップの幅が 33 ピクセルの場合、実際には行ごとに (36*3) バイトになります。

この「ピクセルとパディング」を「ストライド」と呼びます。RGB ビットマップの場合、以下を使用してストライドを計算できます。stride = (biWidth * (biBitCount / 8) + 3) & ~3ここで、biWidthbiBitCountは BITMAPINFOHEADER から取得されます。

配列をどのようにトラバースしたいのかわかりません。左上から右下にピクセルごとに移動する場合 (これがトップダウン ビットマップであると仮定します):

for (row = 0; row < Image.Height; ++row)
{
    int rowBase = row*stride;
    for (col = 0; col < Image.Width; ++col)
    {
        red = lpPixels[rowBase + col];
        // etc.
    }
}
于 2010-09-10T21:41:15.063 に答える
3

投稿したリンクでは、32 ビットのビットマップを作成しているため、32 ビットのビットマップから読み取っていると仮定します (この仮定は正しくない可能性があります)。

したがって、ループを次のように変更すると機能するはずです。

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

注意事項:

1. C/C++ では、配列は 0 ベース
です。つまり、すべてのピクセルにアクセスしているわけではありません。
3. 通常、ビットマップは、「幅」ピクセルの「高さ」スパンがあるように編成されます。したがって、スパン内の各ピクセルをステップスルーしてから、次のスパンに移動する必要があります。
4. すでに指摘したように、ピクセルを正しく読み取っていることを確認してください。16ビットモードではより複雑

于 2010-09-10T21:41:56.677 に答える
2

それほど簡単ではありません。アルゴリズムは、画像の色深度によって異なります。256 以下の場合、ピクセルの色はありませんが、色のパレットにインデックスを付けます。16 ビット ピクセルは RGB555 または RGB565、24 ビット イメージは RGB888、32 ビット イメージは RGBA または ARGB になります。調べるには BITMAPINFOHEADER が必要です。

見つけたら、ピクセルデータはサイズ幅 * 高さ * (BitsPerPixel / 8) の配列になります。

于 2010-09-10T21:25:42.347 に答える
2

MSDN からのいくつかの驚き:

このテーブルは、RGBQUAD データ構造の配列で構成されています。(BITMAPCOREINFO 形式のテーブルは、RGBTRIPLE データ構造を使用して作成されます。) 赤、緑、および青のバイトは、Windows の規則とは逆の順序(赤と青の位置が入れ替わる) です。

したがって、色は GetDIBits() の後にメモリ内で BGR の順序になります。

于 2014-11-02T16:21:00.757 に答える