WindowsAPI GetPixelについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
@ZEROXE

WindowsAPI GetPixelについて

#1

投稿記事 by @ZEROXE » 11年前

こんばんは、この掲示板を何度か使用させていただいたことがあるものです。
OS Windows 7
コンパイラ Microsoft Visual Studio 2013
ライブラリ WindowsAPI
言語 C++
1・今回は、画像処理ソフトを作ろうと思いWindowsAPI C++ でプログラムを組もうと思い至りました。
最初は、DxLibで画像解析の方をしていたのですが、やはりゲームではないので操作面で不便があり、
WindowsAPIを使ってどうにかプログラミングできないものかと思い始めたのですが、
GetPixelが非常に遅く画像処理をする上で不便だと思い、
何日か調べてみたのですが、分からなかった為、こちらへ質問することとしました。

2・調べている中でネットに落ちているプログラムを見つけ、調べながら自分で足りないところを補強しながら作成しました。
  なるべく理解しようと心がけて検索したりして色々調べながらプログラムをしていますが、画像表示部分などネットに落ちてるものを
  調べながら書き写したものなので、丸写しになっている部分や少し改良を加えた部分などがあります。

コード:

extern TCHAR strFile[MAX_PATH];
extern HANDLE hMem, hMemInfo;
extern LONG wx, wy;
extern char *szBuffer;
extern DWORD dwFileSize, dwOffBits, dwSizeImage, dwClrUsed;
extern LPBITMAPINFO lpbmp_info;
extern BOOL bLoad;
extern WORD wBitCount;
extern HPALETTE hPalette;
extern HWND g_hDlg;
extern HWND g_hDlg2;
extern CCHAR str[256];
extern HINSTANCE g_hInst;

extern char *szBuffer2;

char rgb_RGB[4];

HBITMAP hBMP;

HPALETTE SetPalette(HWND hWnd, LPBITMAPINFOHEADER lpBi);

int MakeBMPInfo(LPBITMAPINFOHEADER lpBi);

int ReadDIB(HWND hWnd)
{
	DWORD dwResult;
	HANDLE hF,hMem1, hMem2;
	LPBITMAPFILEHEADER lpBf;
	LPBITMAPINFOHEADER lpBi;
	char szFType[3];//
	RECT rc;//RECT構造体
	int x, y;
	int my_x=0, my_y=0;

	bLoad = TRUE;
	hF = CreateFile(strFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
		NULL);

	//ファイル取得に失敗するとINVALID_HANDLE_VALUEが返る。 FFFFh
	//成功したらファイルハンドルを返す。
	if (hF == INVALID_HANDLE_VALUE)
	{
		MessageBox(hWnd, "ファイルのオープンに失敗しました", "Error", MB_OK);
		return -1;
	}

	//ヒープ領域:動的に確保可能なメモリの領域
	//指定されたバイト数のメモリを、ヒープ領域から確保します。
	//GHND:移動可能メモリを確保し、その内容を 0 で埋め尽くします。
	//成功:移動可能メモリを確保したときは、メモリオブジェクトのハンドルが返ります。
	//失敗:0が返る。
	hMem1 = GlobalAlloc(GHND, sizeof(BITMAPFILEHEADER));
	//メモリ オブジェクトをロックし、メモリ ブロックの先頭ポインタを取得します。移動可能メモリにのみ有効です。 
	//関数が成功すると、メモリ ブロックの先頭ポインタが返ります。失敗すると、0 が返ります。
	lpBf = (LPBITMAPFILEHEADER)GlobalLock(hMem1);

	//バッファ:情報を一時的に蓄える記憶領域 キューやスタック
	//(LPBI...)lpBf:ビットマップファイルハンドルのポインタのキャスト
	//ReadFile:ファイルからデータを読み取る
	//ファイルハンドル,データバッファ,読み取り対象のバイト数,読み取ったバイト数,オーバーラップ構造体のバッファ
	//&dwResult:1 個の変数へのポインタを指定します。関数から制御が返ると、この変数に、実際に読み取ったバイト数が格納されます。
	ReadFile(hF, (LPBITMAPFILEHEADER)lpBf, sizeof(BITMAPFILEHEADER), &dwResult, NULL);

	dwFileSize = lpBf->bfSize;		  //"BM"の2バイト
	szFType[0] = LOBYTE(lpBf->bfType);//ローバイト
	szFType[1] = HIBYTE(lpBf->bfType);//ハイバイト
	szFType[2] = '\0';				  //NULL
	dwOffBits = lpBf->bfOffBits;	  //ファイルの先頭からビット配列までのオフセット値

	GlobalUnlock(hMem1);

	if (strcmp(szFType, "BM") != 0) {
		MessageBox(hWnd, "ビットマップではありません", "Error", MB_OK);
		GlobalFree(hMem1);
		CloseHandle(hF);
		return -1;
	}

	//オフセット値:先頭から特定の要素までの距離を表す整数。
	hMem2 = GlobalAlloc(GHND, sizeof(BITMAPINFOHEADER));//上記参照
	lpBi = (LPBITMAPINFOHEADER)GlobalLock(hMem2);		//上記参照
	
	//上記参照
	ReadFile(hF, (LPBITMAPINFOHEADER)lpBi, sizeof(BITMAPINFOHEADER), &dwResult, NULL);

	wx = lpBi->biWidth;								//画像の幅
	wy = lpBi->biHeight;							//画像の高さ
	wBitCount = lpBi->biBitCount;					//ピクセルあたりの色数。
	dwClrUsed = lpBi->biClrUsed;					//イメージで使われている色数
	dwSizeImage = lpBf->bfSize - lpBf->bfOffBits;	//ファイルの先頭からビット配列までのオフセット値

	RECT rc1 = { 0, 0, wx, wy };//RECT構造体

	hMemInfo = GlobalAlloc(GHND, sizeof(BITMAPINFO)+dwClrUsed * sizeof(RGBQUAD));

	lpbmp_info = (LPBITMAPINFO)GlobalLock(hMemInfo);

	if (hMem)
	{
		//上記参照
		if (GlobalFree(hMem))
			MessageBox(hWnd, "GlobalFree失敗", "Error", MB_OK);
	}
	hMem = GlobalAlloc(GHND, dwFileSize - sizeof(BITMAPFILEHEADER));
	szBuffer = (char *)GlobalLock(hMem);

	//読みこむのはBITMAPINFOHEADER, RGBQUAD, ビットデータ
	SetFilePointer(hF, sizeof(BITMAPFILEHEADER), 0, FILE_BEGIN);

	ReadFile(hF, szBuffer,
		dwSizeImage + dwClrUsed * sizeof(RGBQUAD)+sizeof(BITMAPINFOHEADER),
		&dwResult, NULL);

	if (dwClrUsed != 0 || wBitCount != 24) {
		hPalette = SetPalette(hWnd, lpBi);
	}

	//BITMAPINFO構造体をセットする
	lpbmp_info->bmiHeader = *lpBi;
	MakeBMPInfo(lpBi);

	GetWindowRect(hWnd, &rc);

	x = rc.left;

	y = rc.top;	

	rc.right = x + wx;

	rc.bottom = y + wy;

	AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, TRUE);

	AdjustWindowRectEx(&rc1, WS_OVERLAPPEDWINDOW, FALSE, 0);

	SetWindowPos(g_hDlg, NULL, WINDOW_X, WINDOW_Y, rc1.right - rc1.left, rc1.bottom - rc1.top, (SWP_NOZORDER | SWP_NOOWNERZORDER));//ダイアログ1のサイズを画像サイズに変更

	SetWindowPos(g_hDlg2, NULL, WINDOW_X, WINDOW_Y, rc1.right - rc1.left, rc1.bottom - rc1.top, (SWP_NOZORDER | SWP_NOOWNERZORDER));//ダイアログ1のサイズを画像サイズに変更
	
	InvalidateRect(hWnd, NULL, TRUE);

	GlobalUnlock(hMemInfo);
	GlobalUnlock(hMem);
	if (GlobalFree(hMem1))
		MessageBox(hWnd, "GlobalFree(hMem1)失敗", "Error", MB_OK);
	GlobalUnlock(hMem2);
	if (GlobalFree(hMem2))
		MessageBox(hWnd, "GlobalFree(hMem2)失敗", "Error", MB_OK);
	CloseHandle(hF);
	return 0;
}

void RGB_V(HWND hWnd, int x, int y, int *my_R, int *my_G, int *my_B, int *Flag)
{
	//毎回この作業を行うのは重い
	HBITMAP hBMPOLD;//画像が読まれていない
	LPDWORD lpRGB;
	HDC hdcBMP;
	HDC	hDC;
	BITMAPINFO BmpInfo;

	/*自分で作成したDCには自分で作成したビットマップを
	SelectObjectしなければなりません。
	それぞれコピー元とコピー先に指定してBitBltなどを実行すると、
	デスクトップのビットマップイメージが自分で作成したビットマップに
	コピーされます*/


	switch (wx == NULL || wy == NULL ? *Flag = -1 : 0)
	{
	case 0:
		hDC = GetDC(hWnd);

		// ヘッダ情報の設定
		ZeroMemory(&BmpInfo, sizeof(BITMAPINFO));

		BmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
		BmpInfo.bmiHeader.biWidth = wx;//幅
		BmpInfo.bmiHeader.biHeight = -wy;//高さ
		BmpInfo.bmiHeader.biPlanes = 1;
		BmpInfo.bmiHeader.biBitCount = 32;
		BmpInfo.bmiHeader.biCompression = BI_RGB;
		
		//*************************************************

		hBMP = CreateDIBSection(hDC, &BmpInfo, DIB_RGB_COLORS, (LPVOID*)(&lpRGB), NULL, 0);

		hdcBMP = CreateCompatibleDC(hDC);

		hBMPOLD = (HBITMAP)SelectObject(hdcBMP, hBMP);

		SelectObject(hdcBMP, hBMPOLD);
//*************************************************************************
//問題の部分
		GetDIBits(hDC, hBMP, 0, wy,
			lpRGB, &BmpInfo, DIB_RGB_COLORS
			);
//**************************************************************************
		*my_R = (BYTE)(lpRGB[wx * y + x] >> 8 * 2);

		*my_G = (BYTE)(lpRGB[wx * y + x] >> 8 * 1);

		*my_B = (BYTE)(lpRGB[wx * y + x] >> 8 * 0);

		//*************************************************

		DeleteObject(hdcBMP);

		DeleteObject(hBMP);

		*Flag = 0;

		ReleaseDC(hWnd, hDC);
		break;
	}


}

HPALETTE SetPalette(HWND hWnd, LPBITMAPINFOHEADER lpBi)
{
	LPLOGPALETTE lpPal;
	LPRGBQUAD lpRGB;
	HANDLE hPal;
	WORD i;
	DWORD dwClrUsed;

	dwClrUsed = lpBi->biClrUsed;

	hPal = GlobalAlloc(GHND, sizeof(LOGPALETTE)+dwClrUsed * sizeof(PALETTEENTRY));
	lpPal = (LPLOGPALETTE)GlobalLock(hPal);

	lpPal->palVersion = 0x300;
	lpPal->palNumEntries = (WORD)dwClrUsed;

	lpRGB = (LPRGBQUAD)((LPSTR)lpBi + lpBi->biSize);

	for (i = 0; i < dwClrUsed; i++, lpRGB++) {
		lpPal->palPalEntry[i].peRed = lpRGB->rgbRed;
		lpPal->palPalEntry[i].peGreen = lpRGB->rgbGreen;
		lpPal->palPalEntry[i].peBlue = lpRGB->rgbBlue;
		lpPal->palPalEntry[i].peFlags = 0;
	}
	GlobalUnlock(hPal);
	hPalette = CreatePalette(lpPal);
	if (hPalette == NULL) {
		MessageBox(hWnd, "パレット作成失敗", "Error", MB_OK);
	}
	GlobalFree(hPal);
	return hPalette;
}

int MakeBMPInfo(LPBITMAPINFOHEADER lpBi)
{
	LPRGBQUAD lpRGB;
	int i;

	lpRGB = (LPRGBQUAD)(szBuffer + sizeof(BITMAPINFOHEADER));

	for (i = 0; i < (int)lpBi->biClrUsed; i++) {
		lpbmp_info->bmiColors[i].rgbBlue = lpRGB->rgbBlue;
		lpbmp_info->bmiColors[i].rgbGreen = lpRGB->rgbGreen;
		lpbmp_info->bmiColors[i].rgbRed = lpRGB->rgbRed;
		lpbmp_info->bmiColors[i].rgbReserved = 0;
		lpRGB++;
	}
	return 0;
}
こちらは、うまく動作していますが、ここで問題の部分でビットマップ画像のピクセルを取得し、配列へピクセル情報を格納する為には、
どのようにしたらよいでしょうか?
自分では、GetPixelで配列に格納してやってみましたが、読み込みに時間がかかってしまい
非効率でした。

3.(a)何がしたいのか・(b)結局何が知りたいのか
(a)1:メインダイアログに画像を1度表示する
  2:画像から全ての画素値を参照する
  3:参照した画素値から画像処理の計算を実行
  4:メインダイアログのボタンをクリック後、
    得られた画像を別のダイアログへ表示
この過程の中で、2の部分の画像を参照する部分、
また、4の画像を表示する部分で使用しているGetPixel、SetPixelが遅い為改善したい。

(b)上記したプログラムの配列の中にビット情報(RGB)を格納し、RGB値を参照する。
  この配列の中にビット情報を格納する方法が分かりません。
  ※ちなみにBitmap構造体の仕組みは理解できたつもりですが、fileheaderやinfoheader
の関数は存在している物の肝心のデータは何処から参照すればよいのか?
  SetFilePointerで画像データまでのオフセット値を飛ばし、ReadFileで読み込もうともしましたが
  うまくいきませんでした。

4.C言語の知識
C言語の知識としましては、
・配列,関数,構造体,変数,nume,deleat,new,if,for,switchくらいはできます。
・ポインタ(まだ理解出来て日が浅い為、しっかり理解できているか不安ではあります。)
・クラス(こちらの方は、まだ手を付けていません)
クラスの方は、コンソールアプリケーションやDxLibなどの簡単なゲームなどを作るのに、
今ある知識で充分作れた為、まだ手を付けておりません。

どうにも今の自分には知識不足で
解決できそうにない為、どうかご教授願いただけたら幸いです。
どうか宜しくお願い致します。

@ZEROXE

WindowsAPI GetPixelについて

#2

投稿記事 by @ZEROXE » 11年前

プログラムの所々にメモがありますが、自分で重要だと思う部分をメモとして
書いておくと何が書いてあるか何をやらなければいけないかなど、
後で見直した時に分かりやすいと思うことをいくつか書き残してあります。

そのせいで見にくい部分も多々見られますがそこのところ御了承ください。

@ZEROXE

WindowsAPI GetPixelについて

#3

投稿記事 by @ZEROXE » 11年前

そろそろ睡眠の時間ですので、
大変申し訳ないですが、
解答に対する返答に関しましては、今日のお昼頃になると思います。
どうか宜しくお願い致します。

※追記
ソースファイルの方は、複数に分けてあり今回問題のところのみ掲載しました。
今回問題となっている所としましては、

コード:

void RGB_V(HWND hWnd, int x, int y, int *my_R, int *my_G, int *my_B, int *Flag)
{
    //毎回この作業を行うのは重い
    HBITMAP hBMPOLD;//画像が読まれていない
    LPDWORD lpRGB;
    HDC hdcBMP;
    HDC hDC;
    BITMAPINFO BmpInfo;
  
    switch (wx == NULL || wy == NULL ? *Flag = -1 : 0)
    {
    case 0:
        hDC = GetDC(hWnd);
 
        // ヘッダ情報の設定
        ZeroMemory(&BmpInfo, sizeof(BITMAPINFO));
 
        BmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        BmpInfo.bmiHeader.biWidth = wx;//幅
        BmpInfo.bmiHeader.biHeight = -wy;//高さ
        BmpInfo.bmiHeader.biPlanes = 1;
        BmpInfo.bmiHeader.biBitCount = 32;
        BmpInfo.bmiHeader.biCompression = BI_RGB;
        
        //*************************************************
 
        hBMP = CreateDIBSection(hDC, &BmpInfo, DIB_RGB_COLORS, (LPVOID*)(&lpRGB), NULL, 0);
 
        hdcBMP = CreateCompatibleDC(hDC);
 
        hBMPOLD = (HBITMAP)SelectObject(hdcBMP, hBMP);
 
        SelectObject(hdcBMP, hBMPOLD);
//*************************************************************************
//問題の部分
        GetDIBits(hDC, hBMP, 0, wy,
            lpRGB, &BmpInfo, DIB_RGB_COLORS
            );
//**************************************************************************
        *my_R = (BYTE)(lpRGB[wx * y + x] >> 8 * 2);
 
        *my_G = (BYTE)(lpRGB[wx * y + x] >> 8 * 1);
 
        *my_B = (BYTE)(lpRGB[wx * y + x] >> 8 * 0);
 
        //*************************************************
 
        DeleteObject(hdcBMP);
 
        DeleteObject(hBMP);
 
        *Flag = 0;
 
        ReleaseDC(hWnd, hDC);
        break;
    }
 
 
}
この部分でピクセル情報の格納を行って、RGB値をGetPixelのように参照するプログラム
を作成したいということです。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: WindowsAPI GetPixelについて

#4

投稿記事 by みけCAT » 11年前

まだ使ったことはありませんが、libbmpというものがあります。
http://code.google.com/p/libbmp/
これを使えば、比較的簡単にbmpファイルの読み書きができるかもしれません。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

@ZEROXE

WindowsAPI GetPixelについて

#5

投稿記事 by @ZEROXE » 11年前

みけCATさんご解答の方有難うございます。

コード:

#include <bmpfile.h>
fatal error C1083: include ファイルを開けません。'bmpfile.h':No such file or directory

こちらの方、標準で積んであるヘッダーファイルではないようですね。
少し調べてみたのですが、中々望み通りの検索結果が得られない為、
お手数ではありますが、導入方法などのサイトも載せていただくことはできないでしょうか。

また、上記したプログラムの方での実現は難しいのでしょうか?

@ZEROXE

WindowsAPI GetPixelについて

#6

投稿記事 by @ZEROXE » 11年前

コード:

	switch (wx == NULL || wy == NULL ? *Flag = -1 : 0)
	{
	case 0:
		hDC = GetDC(hWnd);

		// ヘッダ情報の設定
		ZeroMemory(&BmpInfo, sizeof(BITMAPINFO));
		BmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
		BmpInfo.bmiHeader.biWidth = wx;//幅
		BmpInfo.bmiHeader.biHeight = -wy;//高さ
		BmpInfo.bmiHeader.biPlanes = 1;
		BmpInfo.bmiHeader.biBitCount = 32;
		BmpInfo.bmiHeader.biCompression = BI_RGB;

		hBMP = CreateDIBSection(hDC, &BmpInfo, DIB_RGB_COLORS, (LPVOID*)(&lpRGB), NULL, 0);

		hdcBMP = CreateCompatibleDC(hDC);

		hBMPOLD = (HBITMAP)SelectObject(hdcBMP, hBMP);

		SelectObject(hdcBMP, hBMPOLD);

		//*************************************************
		for (int x = 0; x < wx; ++x)
		for (int y = 0; y < wy; ++y)
		{
			lpRGB[wx * y + x] = GetPixel(hDC,x, y);
		}
                //*************************************************

		*my_R = (BYTE)(lpRGB[wx * y + x] >> 8 * 2);

		*my_G = (BYTE)(lpRGB[wx * y + x] >> 8 * 1);

		*my_B = (BYTE)(lpRGB[wx * y + x] >> 8 * 0);

		DeleteObject(hdcBMP);

		DeleteObject(hBMP);

		*Flag = 0;

		ReleaseDC(hWnd, hDC);
		break;
	}
参考にしたサイト:http://okwave.jp/qa/q2895002.html

このプログラム自体は、このサイトに書いてあるものなのですが、
ここで作成している空のビットマップにbmpのピクセルデータをまとめて読み込みたいたいのですが、
上記の通りGetPixelでは読み込み自体に時間がかかってしまう為あまり現実的ではありません。
必要なピクセルのみ読み込めば良いかもしれませんが、
少ない量ならば時間はかかりませんが、
やはり多量のピクセルを読み込むには時間がかかります。
GetDIBitsなどのものでまとめてpixel情報を取得することは難しいでしょうか?

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: WindowsAPI GetPixelについて

#7

投稿記事 by ISLe » 11年前

BMPファイルをDIBセクションに読み込むのはWin32 APIのLoadImage関数一発でできます。

空のビットマップに画素を移すのは、転送元のビットマップハンドルからGetDIBitsで読み込んで、転送先のビットマップハンドルにSetDIBitsで書き込めば良いのですが、画像処理が目的ならアクセスしやすいようにピクセル情報を配列に格納することを優先すべきなのでは?
目的と手段がズレているように感じます。


ビットマップ形式の32ビット幅は仕様に曖昧な点があるので、24ビット幅にしたほうが良いと思います。
24ビット幅の場合、画像の水平サイズによっては行毎にアライメントが発生するので注意が必要です。

@ZEROXE

WindowsAPI GetPixelについて

#8

投稿記事 by @ZEROXE » 11年前

ISLeさんご解答ありがとうございます。
ピクセルの情報を配列に格納した方が確かにアクセスはしやすいですが、
ネットなどに乗っている各関数の説明がなかなか理解できず、
C++のコードなどがなかなか見つからず、検索していたところ
この方法を見つけました。

ですからピクセルの情報を直接配列に格納し、
そのピクセル情報から色の情報を取り出せるなら、そちらの方を優先したいところですね。

@ZEROXE

WindowsAPI GetPixelについて

#9

投稿記事 by @ZEROXE » 11年前

質問なのですが、

コード:

	hBMP = (HBITMAP)LoadImage(g_hInst, strFile, IMAGE_BITMAP, wx, wy, LR_CREATEDIBSECTION);
このようにイメージをロードしました。
ここからどのようにして配列へビットデータを格納すれば良いのでしょうか?

アバター
へにっくす
記事: 634
登録日時: 13年前
住所: 東京都

Re: WindowsAPI GetPixelについて

#10

投稿記事 by へにっくす » 11年前

以下は参考になりますかね。C++のコードです。

生産がす:32bitDIB(2)画像読み込み

関連記事も追ってくと、いいかもしれません。(1)~(7)まであるし。
written by へにっくす

@ZEROXE

WindowsAPI GetPixelについて

#11

投稿記事 by @ZEROXE » 11年前

へにっくすさんご解答の方ありがとうございます。
少しこのサイトを参考に自分で考えてみようと思います。

@ZEROXE

WindowsAPI GetPixelについて

#12

投稿記事 by @ZEROXE » 11年前

いくつかの解答にあった方法を自分で試行錯誤し、
再度分からないようであれば、またこの掲示板の方を利用させていただきたいと思います。
ひとまず解決とさせていただきます。
みけCATさん、ISLeさん、へにっくすさんご解答の方有難うございました。

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: WindowsAPI GetPixelについて

#13

投稿記事 by ISLe » 11年前

解決したようですが、せっかくなので投稿します。
サンプルコード書いてみました。
C++じゃないしウィンドウプロシージャにベタ書きですしいろいろ手抜きがあります。

カレントディレクトリにあるtest.bmpを表示するウィンドウズアプリです。
最初にベタな配列にピクセルデータを取り込んで、その配列のピクセルデータを使って表示します。

コード:

#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

struct PIXEL_DATA // ピクセルデータの保持用
{
	COLORREF pixel; // とりあえずのCOLORREF型
};

static struct PIXEL_DATA *pixels;
static int width;
static int height;

static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_CREATE:
		{
			HDC hdc;
			hdc = GetDC(hWnd);
			if (hdc) {
				// カレントディレクトリの画像ファイルtest.bmpを読み込む
				HBITMAP hbmp = LoadImage(NULL, "test.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);
				if (hbmp) {
					BITMAP bm;
					if (GetObject(hbmp, sizeof(BITMAP), &bm) != 0) {
						width  = bm.bmWidth;
						height = bm.bmHeight;
						// ピクセルデータを保持するメモリ領域を確保する
						pixels = (struct PIXEL_DATA *)malloc(sizeof(struct PIXEL_DATA) * bm.bmWidth * bm.bmHeight);
						if (pixels) {
							BYTE *pbits = NULL;
							int storagebytes;
							// ビットマップからピクセルを読み出すための一行分のメモリ領域を確保する
							storagebytes = ((bm.bmWidth * 3) + 3) & ~3;
							pbits = (BYTE *)malloc(sizeof(BYTE) * storagebytes);
							if (pbits) {
								BITMAPINFO bmi;
								int x, y;
								// ビットマップから一行ずつピクセル情報を取得して変換する
								// ※読み込んだビットマップは常に左下原点
								bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
								bmi.bmiHeader.biWidth       = bm.bmWidth;
								bmi.bmiHeader.biHeight      = bm.bmHeight;
								bmi.bmiHeader.biPlanes      = 1;
								bmi.bmiHeader.biBitCount    = 24;
								bmi.bmiHeader.biCompression = BI_RGB;
								for (y=0; y<bm.bmHeight; y++) {
									if (GetDIBits(hdc, hbmp, (bm.bmHeight - y - 1), 1, pbits, &bmi, DIB_RGB_COLORS) != 0) {
										for (x=0; x<bm.bmWidth; x++) {
											int r, g, b;
											b = pbits[x * 3 + 0];
											g = pbits[x * 3 + 1];
											r = pbits[x * 3 + 2];
											pixels[y * bm.bmWidth + x].pixel = RGB(r, g, b);
										}
									}
								}
								free(pbits);
							}
						}
					}
					DeleteObject(hbmp);
				}
				ReleaseDC(hWnd, hdc);
			}
		}
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	case WM_PAINT:
		{
			HDC hdc;
			PAINTSTRUCT ps;
			hdc = BeginPaint(hWnd, &ps);

			if (pixels) {
				BYTE *pbits = NULL;
				int storagebytes;
				// 保持しているピクセルデータで描画するための一行分のメモリ領域を確保する
				storagebytes = ((width * 3) + 3) & ~3;
				pbits = (BYTE *)malloc(sizeof(BYTE) * storagebytes);
				if (pbits) {
					BITMAPINFO bmi;
					int x, y;
					// 保持しているピクセルデータから一行ずつ変換して描画する
					bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
					bmi.bmiHeader.biWidth       = width;
					bmi.bmiHeader.biHeight      = 1;
					bmi.bmiHeader.biPlanes      = 1;
					bmi.bmiHeader.biBitCount    = 24;
					bmi.bmiHeader.biCompression = BI_RGB;
					for (y=0; y<height; y++) {
						for (x=0; x<width; x++) {
							int r, g, b;
							r = GetRValue(pixels[y * width + x].pixel);
							g = GetGValue(pixels[y * width + x].pixel);
							b = GetBValue(pixels[y * width + x].pixel);
							pbits[x * 3 + 0] = b;
							pbits[x * 3 + 1] = g;
							pbits[x * 3 + 2] = r;
						}
						SetDIBitsToDevice(hdc, 0, y, width, 1, 0, 0, 0, 1, pbits, &bmi, DIB_RGB_COLORS);
					}
					free(pbits);
				}
			}

			EndPaint(hWnd, &ps);
		}
		break;
	}
	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

#define MYAPP_WINDOWNAME	"WindowTitle"
#define MYAPP_CLASSNAME		"WindowClass"

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	WNDCLASSEX wc;
	HWND       hwnd;
	MSG        msg;
	BOOL       bRet;

	wc.cbSize			= sizeof(WNDCLASSEX);
	wc.style			= CS_HREDRAW|CS_VREDRAW;
	wc.lpfnWndProc		= WndProc;
	wc.cbClsExtra		= 0;
	wc.cbWndExtra		= 0;
	wc.hInstance		= hInstance;
	wc.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor			= LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground	= (HBRUSH)GetStockObject(BLACK_BRUSH);
	wc.lpszMenuName 	= NULL;
	wc.lpszClassName	= MYAPP_CLASSNAME;
	wc.hIconSm			= LoadIcon(NULL, IDI_APPLICATION);
	if (!RegisterClassEx(&wc))
		return 0;

	hwnd = CreateWindowEx(
		0,
		MYAPP_CLASSNAME,
		MYAPP_WINDOWNAME,
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		NULL,
		NULL,
		hInstance,
		NULL
		);
	if (!hwnd)
		return 0;

	ShowWindow(hwnd, nShowCmd);
	UpdateWindow(hwnd);

	while (bRet = GetMessage(&msg, NULL, 0, 0))
	{
		if (bRet == -1) return 0;
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
    return msg.wParam;
}

@ZEROXE

WindowsAPI GetPixelについて

#14

投稿記事 by @ZEROXE » 11年前

ISLeさん解決後の回答の方ありがとうございました。
その後も色々と参考のサイトなどを参考にしてみたのですが、
理解に苦しみ目的の機能を実装できずにいたところ、
再度こちらの掲示板を見直してみたところ、ISLeさんの回答を見つけました。
こちらのプログラムを参考にプログラムを組んでみようと思います。
お陰様で希望が見えてきました。
御回答の方、有難うございました。

@ZEROXE

WindowsAPI GetPixelについて

#15

投稿記事 by @ZEROXE » 11年前

目的の画像処理の方は、ISLeさんのプログラムの方で上手く実装できました。
有難うございます。

問題解決後の質問で大変恐縮なのですが、
ダイアログBOXへ画像を表示する場合は、
どのようにしたら良いのでしょうか?

コード:

			//画像表示
			hdc2 = BeginPaint(hWnd, &ps);

			if (pixels) {
				BYTE *pbits = NULL;
				int storagebytes;
				// 保持しているピクセルデータで描画するための一行分のメモリ領域を確保する
				storagebytes = ((width * 3) + 3) & ~3;
				pbits = (BYTE *)malloc(sizeof(BYTE)* storagebytes);
				if (pbits) {
					BITMAPINFO bmi;
					int x, y;
					// 保持しているピクセルデータから一行ずつ変換して描画する
					bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
					bmi.bmiHeader.biWidth = width;
					bmi.bmiHeader.biHeight = 1;
					bmi.bmiHeader.biPlanes = 1;
					bmi.bmiHeader.biBitCount = 24;
					bmi.bmiHeader.biCompression = BI_RGB;
					/*for (y=0; y<height; y++) {
					for (x=0; x<width; x++) {
					int r, g, b;
					r = GetRValue(pixels[y * width + x].pixel);
					g = GetGValue(pixels[y * width + x].pixel);
					b = GetBValue(pixels[y * width + x].pixel);
					pbits[x * 3 + 0] = b;
					pbits[x * 3 + 1] = g;
					pbits[x * 3 + 2] = r;
					}*/

					for (y = 0; y<height; y++)
					{
						for (x = 0; x<width; x++)
						{
							int r, g, b;
							int r1, g1, b1;
							r = GetRValue(pixels[y * width + x].pixel);
							g = GetGValue(pixels[y * width + x].pixel);
							b = GetBValue(pixels[y * width + x].pixel);
							E = r + g + b;
							switch (x<(width - 1) ? 0 : -1)
							{
							case 0:
								r1 = GetRValue(pixels[y * width + (x + 1)].pixel);
								g1 = GetGValue(pixels[y * width + (x + 1)].pixel);
								b1 = GetBValue(pixels[y * width + (x + 1)].pixel);
								break;
							case -1:
								r1 = 0;
								g1 = 0;
								b1 = 0;
								break;
							}
							E2 = r1 + g1 + b1;

							switch (abs(E2 - E)>100 ? 0 : -1)
							{
							case 0:
								pbits[x * 3 + 0] = b;
								pbits[x * 3 + 1] = g;
								pbits[x * 3 + 2] = r;
								break;
							case -1:
								pbits[x * 3 + 0] = 255;
								pbits[x * 3 + 1] = 255;
								pbits[x * 3 + 2] = 255;
								break;
							}
						}

						SetDIBitsToDevice(hdc2, 0, y, width, 1, 0, 0, 0, 1, pbits, &bmi, DIB_RGB_COLORS);
					}
					free(pbits);
				}
			}

			EndPaint(hWnd, &ps);
ISLeさんのコードをこのように改良し、簡単なエッジ検出プログラムを作成したのですが、
この結果をダイアログボックスに表示する場合は、どのようにしたらよいのでしょうか?
SetDIBitsToDeviceでメインダイアログの方にビットを書き込んでいるということはわかるのですが、
hdc2 = BeginPaint(hWnd, &ps);のハンドル(hWnd)をダイアログBOXのハンドルに変えるだけでは表示はできませんでした。
少しアドバイスを頂けるとありがたいです。

@ZEROXE

WindowsAPI GetPixelについて

#16

投稿記事 by @ZEROXE » 11年前

質問の追記
0.画像を(ファイルを開くダイアログにて)読み込む

1.画像をメイン画面の方へ表示

2.メイン画面に設置されたボタンをクリック後、画像処理を実行する。

3.クリックしたボタンで開いたダイアログボックスに画像処理結果を表示する。(問題点)

ダイアログボックスの方は、複数扱いたいと思っています。

ボタンクリック後、ダイアログボックスは開きますが、画像を表示できません。

ダイアログボックスの方は、MoveWindowにて画像の大きさに合わせて大きさを調節するようにしています。

今までは、、GetPixelにて色を取得後、GetDlgItem(...,SetPixel(...))にてダイアログボックスへ表示していましたが、

こちらもGetPixel同様に、非常に遅い為、表示に時間がかかってしまいます。

今回、回答いただいた方法で、メイン画面の方には高速に表示できるようにはなったのですが、

ダイアログボックスへは、表示ができないので再度質問をさせて頂いた次第です。

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: WindowsAPI GetPixelについて

#17

投稿記事 by usao » 11年前

>hdc2 = BeginPaint(hWnd, &ps);のハンドル(hWnd)をダイアログBOXのハンドルに変えるだけでは表示はできませんでした。

これ,ダイアログのプロシージャの方でやってるんですよね?
(メインの画面(?)という側じゃなくて)
オフトピック
GetObject()のところで,DIBSECTION構造体に情報を受けとれば
GetDIBits()とかを使わなくて済むかも.
最後に編集したユーザー usao on 2014年2月04日(火) 18:20 [ 編集 1 回目 ]

@ZEROXE

WindowsAPI GetPixelについて

#18

投稿記事 by @ZEROXE » 11年前

usaoさん返信の方有難うございます。
こちらの処理は、メイン処理で実行しています。
ダイアログプロシージャの方での実行ではありません。

メイン画面のボタン処理で画像処理をした後、
ダイアログボックスへ画像を表示したいのですができないのでしょうか。

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: WindowsAPI GetPixelについて

#19

投稿記事 by usao » 11年前

ダイアログに表示したいのなら
ダイアログのプロシージャのWM_PAINTのところに書けばよいのではないかと.

・メイン側のボタン処理 → ダイアログに再描画要求を出す → ダイアログのプロシージャで描画

@ZEROXE

WindowsAPI GetPixelについて

#20

投稿記事 by @ZEROXE » 11年前

usaoさん御回答の有難うございます。
そちらの方法で少しプログラムの改良の方をしてみようと思います。

@ZEROXE

WindowsAPI GetPixelについて

#21

投稿記事 by @ZEROXE » 11年前

usaoさん御回答の方ありがとうございました。
お陰様でダイアログの方へ表示することができました有難うございました。

最後となりますが、
WindowsAPIの方は、C++言語始めたての頃に挫折してしまい
最近になって、またやり始めました。
分からないところは、ネットで調べ、
どうしても自己解決ができないところなどは、掲示板で質問したりして解決していますが、
まだWindowsAPIの方は始めて日が浅いので、知識の方を増やして行きたいのですが、
オススメの分かりやすい書籍や勉強の方法などありましたら教えていただけないでしょうか。

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: WindowsAPI GetPixelについて

#22

投稿記事 by ISLe » 11年前

usao さんが書きました:
オフトピック
GetObject()のところで,DIBSECTION構造体に情報を受けとれば
GetDIBits()とかを使わなくて済むかも.
それだと読み込んだビットマップのフォーマット(ビット幅)に左右されるのでピクセルにアクセスするコードが煩雑になります。
サンプルコードの場合だと内部的には24ビット固定でコードを統一しています。

読み込み時にDIBSECTIONを指定しているのは、デバイス(デスクトップ)依存に変換されて劣化するのを防ぐ効果を期待したものです。
実際にはそんな効果はないかもしれません。
最後に編集したユーザー ISLe on 2014年2月04日(火) 19:05 [ 編集 1 回目 ]

@ZEROXE

WindowsAPI GetPixelについて

#23

投稿記事 by @ZEROXE » 11年前

ISLeさん御回答有難うございます。
usaoさんの指摘の方は、ダイアログボックスの方をプログラムの方へ反映させていただきました。
GetObject()の方は、変えておりません。

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: WindowsAPI GetPixelについて

#24

投稿記事 by usao » 11年前

オフトピック
GetDIBits()で所望の形式に変換しているということですね.わかりました.

@ZEROXE

WindowsAPI GetPixelについて

#25

投稿記事 by @ZEROXE » 11年前

これでこの質問は解決にしたいと思います。
みけCATさん、ISLeさん、へにっくすさん、usaoさん
どうも有難うございました。
またこの掲示板を御利用させて頂く事があるかと思いますが、
その時はどうぞ宜しくお願い致します。
このトピックは既に解決していますが改めて解決をさせて頂きます。

閉鎖

“C言語何でも質問掲示板” へ戻る