前提・実現したいこと
現在windows10の環境でコマンドプロンプトにてgccを利用しC言語プログラムを行っております。
内容は、ウィンドウに表示されたものを、画像保存(BITMAP保存)を経由せずに、0と1で配列表現しようと思っております。
イメージとしては以下です。
(説明)
左のひよこ画像・・・PCに表示されている背景です。
右のひよこ・・・ウィンドウアプリで一定の範囲を映し出しています。
該当のソースコード
hiyoko_analysis.c
c
1#include <stdio.h> 2#include <windows.h> 3#define WINDOWS_CLASS_NAME TEXT("WisdomSoft.Sample.Window") 4 5LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); // ウインドウプロシージャ関数 6ATOM InitApp(HINSTANCE); 7BOOL InitInstance(HINSTANCE,int); 8char szClassName[]="sample"; //ウインドウクラス 9 10HINSTANCE hInst; 11int ncshow; 12HWND hWnd; 13 14int WINAPI WinMain(HINSTANCE hCurInst,HINSTANCE hPrevInst, 15 LPSTR lpsCmdLine,int nCmdShow ){ 16 MSG msg; 17 BOOL bRet; 18 hInst = hCurInst; 19 ncshow = nCmdShow; 20 if(!InitApp(hInst)) return FALSE; 21 if(!InitInstance(hCurInst,ncshow)) return FALSE; 22 23 while((bRet = GetMessage(&msg,NULL,0,0)) != 0){ 24 if(bRet == -1){ 25 MessageBox(NULL,"GetMessage ERR","Error",MB_OK); 26 break; 27 }else{ 28 TranslateMessage(&msg); 29 DispatchMessage(&msg); 30 //} 31 } 32 } 33 return (int)msg.wParam; 34} 35 36//ウインドウクラスの登録 37ATOM InitApp(HINSTANCE hInst){ 38 WNDCLASSEX wc; 39 wc.cbSize = sizeof(WNDCLASSEX); 40 wc.style =CS_HREDRAW | CS_VREDRAW; 41 wc.lpfnWndProc = WndProc;//プロ―ジャー名 42 wc.cbClsExtra = 0; 43 wc.cbWndExtra = 0; 44 wc.hInstance = hInst;//インスタンス 45 wc.hIcon = (HICON)LoadImage(NULL, 46 MAKEINTRESOURCE(IDI_APPLICATION), 47 IMAGE_ICON, 48 0, 49 0, 50 LR_DEFAULTSIZE | LR_SHARED); 51 wc.hCursor = (HCURSOR)LoadImage(NULL, 52 MAKEINTRESOURCE(IDC_ARROW), 53 IMAGE_CURSOR, 54 0, 55 0, 56 LR_DEFAULTSIZE | LR_SHARED); 57 wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 58 wc.lpszMenuName = NULL; //メニュー名 59 wc.lpszClassName = (LPCSTR)szClassName; 60 wc.hIconSm = (HICON)LoadImage(NULL, 61 MAKEINTRESOURCE(IDI_APPLICATION), 62 IMAGE_ICON, 63 0, 64 0, 65 LR_DEFAULTSIZE | LR_SHARED); 66 return (RegisterClassEx(&wc)); 67} 68 69 70//ウインドウの生成 71BOOL InitInstance(HINSTANCE hInst,int nCmdShow) 72{ 73 74 hWnd = CreateWindow(szClassName, 75 "title bar name", 76 WS_OVERLAPPEDWINDOW,//ウインドウの種類 77 1000, //x座標 78 600, //y座標 79 400, //幅 80 300, //高さ 81 NULL, //親ウインドウのハンドル、親を作るときは NULL 82 NULL, //メニューハンドル、クラスメニューを使うときは NULL 83 hInst, //インスタンスハンドル 84 NULL); 85 if(!hWnd) return FALSE; 86 ShowWindow(hWnd,nCmdShow); 87 UpdateWindow(hWnd); 88 return TRUE; 89} 90 91 92void paint(HWND hWnd){ 93 94 PAINTSTRUCT ps; 95 HDC hdc = BeginPaint(hWnd,&ps); 96 97 RECT rc; 98 GetClientRect(hWnd,&rc);//ウインドウの範囲を取得 99 100 BitBlt(hdc, rc.left, rc.top, 200, 200, CreateDC(TEXT("DISPLAY") , NULL , NULL , NULL), 400, 350, SRCCOPY); 101 printf("hWnd %d\n", hWnd); 102 EndPaint(hWnd,&ps); 103} 104 105//ウィンドウプロシージャ 106LRESULT CALLBACK WndProc(HWND hWnd,UINT msg,WPARAM wp,LPARAM lp) 107{ 108 int id; 109 HDC hdc; 110 HBRUSH hBrush; 111 PAINTSTRUCT ps; 112 113 switch(msg){ 114 case WM_CREATE: 115 SetLayeredWindowAttributes(hWnd, RGB(255, 0, 0), 0, LWA_COLORKEY); 116 SetTimer(hWnd,1000,500,NULL); 117 break; 118 case WM_PAINT: 119 paint(hWnd); 120 break; 121 122 case WM_TIMER: 123 if(wp == 1000){ 124 //再描画要求 125 InvalidateRect(hWnd, NULL,1); 126 UpdateWindow(hWnd); 127 } 128 else return (DefWindowProc(hWnd,msg,wp,lp)); 129 break; 130 131 case WM_CLOSE: 132 id = MessageBox(hWnd, 133 "終了してもよろしいですか", 134 "確認", 135 MB_YESNO | MB_ICONQUESTION); 136 if (id == IDYES) 137 KillTimer(hWnd,1000);//タイマーを破棄 138 DestroyWindow(hWnd); 139 break; 140 141 case WM_DESTROY: 142 PostQuitMessage(0); 143 break; 144 default: 145 return (DefWindowProc(hWnd,msg,wp,lp)); 146 } 147 return 0; 148} 149 150int main( void ) 151{ 152 return WinMain(GetModuleHandle(NULL), NULL, NULL, SW_SHOWDEFAULT); 153}
いわゆる画像のディジタル化。標本化からの量子化といっていいのでしょうか。
今、対象の場所をウィンドウに映し出すことところまでできました。
発生している問題・エラーメッセージ
ただ、これを0と1で表現する際に、一度画像に変換して(bitmap保存等)からその画像を0と1へ変換する方法もあると思うのですが、ローカルに画像保存をしますとスピードやPCへの負荷や削除する手間があるため、今ウィンドウに表示されているそのものを使用して01変換表示する方法はないのでしょうか。
試したこと
◇試したこと1:ペイント関数時にデータ状態確認
c
1void paint(HWND hWnd){ 2 3 PAINTSTRUCT ps; 4 HDC hdc = BeginPaint(hWnd,&ps); 5 printf("hdc %d\n", hdc); 6 printf("ps %d\n", ps); 7 8 9 RECT rc; 10 GetClientRect(hWnd,&rc);//ウインドウの範囲を取得 11 printf("rc %d\n", rc); 12 13 BitBlt(hdc, rc.left, rc.top, 200, 200, CreateDC(TEXT("DISPLAY") , NULL , NULL , NULL), 400, 350, SRCCOPY); 14 printf("hWnd %d\n", hWnd); 15 EndPaint(hWnd,&ps); 16} 17
◇試したこと2:ウインドウを構成する要素を調べるため、システムの情報を得るGetSystemMetrics()の利用
SM_CXBORDERでウインドウの幅などの情報は得られますが、表示されている画素の情報は得られませんでした。
◇試したこと3:(試せていないこと)メモリデバイスコンテキストから情報を得る
DDBを作るサイト
方向性のみ。
◇試したこと4:BITMAP構造体からピクセル画素を得る
BITMAP構造体から情報取得
上記サイトからメモリデバイスコンテキストなどについて学び画素などの情報を得ようと試みました。
c
1 // 追加2行 2 LPBYTE lp1; 3 BITMAP bm; 4 5 BitBlt(hdc, rc.left, rc.top, 200, 200, CreateDC(TEXT("DISPLAY") , NULL , NULL , NULL), 400, 350, SRCCOPY); 6 7 // 追加3行 8 GetObject(hdc, (int)sizeof(BITMAP), &bm); 9 lp1 = (LPBYTE)bm.bmBits; 10 printf("lp1[0] %d\n", lp1[0]); 11 12 printf("hWnd %d\n", hWnd); 13 EndPaint(hWnd,&ps);
元のソースコードの100行目あたりに上記のコードに変更してみました。
追加で2行と3行と記載されている箇所です。
結果的には、
先頭のピクセルの画素(赤色?)を取得できているようですが、暫くするとフリーズしてしまいました。
なぜ止まってしまうのでしょうか。メモリ解放などの理由からでしょうか。
いろいろ参考書やサイトで調べているのですが、どれも保存をして読み込んでからという処理ばかりでした。
言い換えれば、ウィンドウの画素の情報を取得さえできれば、あとは閾値を決めて01変換できます。ウィンドウの画素数の情報取得するAPIや何かよい方法はないか思案しております。
リアルタイムに素早く映し出している画を01変換表示する方法として標本化量子化などを毎回計算するよりも、画像を一度保存してからそこから変換が早いなど他の方法でも構いません。何かアドバイス頂けないでしょうか。
よろしくお願い致します。
補足情報(FW/ツールのバージョンなど)
OS:windows10
言語:c
コンパイラ:gcc
2021/5/4 追記
デスクトップをCreateDIBSectionを使用しHBITMAP型の返却値を取得し、デスクトップ画の情報を反映させ、hbmpPrevに情報反映しましたが、その後のメモリアクセスとRGM色情報の取得で詰まっております。このあとにアクセスする方法のアドバイス頂けないでしょうか。よろしくお願い致します。
c
1#include <windows.h> 2#include <stdio.h> 3void DrawCursor(HDC hdc); 4BOOL WriteBitmap(LPTSTR lpszFileName, int nWidth, int nHeight, LPVOID lpBits); 5HBITMAP CreateBackbuffer(int nWidth, int nHeight); 6 7int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow) 8{ 9 HDC hdc; 10 HWND hwndDesk; 11 RECT rc; 12 BITMAP bm; 13 HBITMAP hbmp; 14 HBITMAP hbmpPrev; 15 16 hwndDesk = GetDesktopWindow(); 17 GetWindowRect(hwndDesk, &rc); 18 19 hdc = CreateCompatibleDC(NULL); 20 21 // CreateDIBSectionで作成したビットマップは直接ピクセルデータにアクセス出来るポインタが使用出来る 22 hbmp = CreateBackbuffer(rc.right, rc.bottom); 23 24 BITMAP i; 25 hbmpPrev = (HBITMAP)SelectObject(hdc, hbmp); 26 //printf("%d\n", hbmpPrev[0]); 27 28 29 // ピクセルデータを取得したいイメージをBitBltで転送して取り出せばよい 30 BitBlt(hdc, 0, 0, rc.right, rc.bottom, GetWindowDC(hwndDesk), 0, 0, SRCCOPY); 31 DrawCursor(hdc); 32 33 GetObject(hbmp, sizeof(BITMAP), &bm); 34 if (WriteBitmap(TEXT("capture.bmp"), rc.right, rc.bottom, bm.bmBits)) 35 MessageBox(NULL, TEXT("ファイルを作成しました。"), TEXT("OK"), MB_OK); 36 else 37 MessageBox(NULL, TEXT("ファイルの作成に失敗しました。"), NULL, MB_ICONWARNING); 38 // DIBセクションのHBITMAPをSelectObjectしたメモリDCを転送先にしてBitBltしたら、作成時に受け取ったポインタにピクセルデータが格納 39 SelectObject(hdc, hbmpPrev); 40 DeleteObject(hbmp); 41 DeleteDC(hdc); 42 43 return 0; 44} 45 46void DrawCursor(HDC hdc) 47{ 48 int x, y; 49 CURSORINFO cursorInfo; 50 ICONINFO iconInfo; 51 52 cursorInfo.cbSize = sizeof(CURSORINFO); 53 GetCursorInfo(&cursorInfo); 54 55 GetIconInfo(cursorInfo.hCursor, &iconInfo); 56 57 x = cursorInfo.ptScreenPos.x - iconInfo.xHotspot; 58 y = cursorInfo.ptScreenPos.y - iconInfo.yHotspot; 59 DrawIcon(hdc, x, y, cursorInfo.hCursor); 60} 61 62BOOL WriteBitmap(LPTSTR lpszFileName, int nWidth, int nHeight, LPVOID lpBits) 63{ 64 HANDLE hFile; 65 DWORD dwResult; 66 DWORD dwSizeImage; 67 BITMAPFILEHEADER bmfHeader; 68 BITMAPINFOHEADER bmiHeader; 69 70 hFile = CreateFile(lpszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 71 if (hFile == INVALID_HANDLE_VALUE) 72 return FALSE; 73 74 dwSizeImage = nHeight * ((3 * nWidth + 3) / 4) * 4; 75 76 ZeroMemory(&bmfHeader, sizeof(BITMAPFILEHEADER)); 77 bmfHeader.bfType = *(LPWORD)"BM"; 78 bmfHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwSizeImage; 79 bmfHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); 80 81 WriteFile(hFile, &bmfHeader, sizeof(BITMAPFILEHEADER), &dwResult, NULL); 82 83 ZeroMemory(&bmiHeader, sizeof(BITMAPINFOHEADER)); 84 bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 85 bmiHeader.biWidth = nWidth; 86 bmiHeader.biHeight = nHeight; 87 bmiHeader.biPlanes = 1; 88 bmiHeader.biBitCount = 24; 89 bmiHeader.biSizeImage = dwSizeImage; 90 bmiHeader.biCompression = BI_RGB; 91 92 WriteFile(hFile, &bmiHeader, sizeof(BITMAPINFOHEADER), &dwResult, NULL); 93 94 WriteFile(hFile, lpBits, dwSizeImage, &dwResult, NULL); 95 96 CloseHandle(hFile); 97 98 return TRUE; 99} 100 101HBITMAP CreateBackbuffer(int nWidth, int nHeight) 102{ 103 LPVOID lp; 104 BITMAPINFO bmi; 105 BITMAPINFOHEADER bmiHeader; 106 107 ZeroMemory(&bmiHeader, sizeof(BITMAPINFOHEADER)); 108 bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 109 bmiHeader.biWidth = nWidth; 110 bmiHeader.biHeight = nHeight; 111 bmiHeader.biPlanes = 1; 112 bmiHeader.biBitCount = 24; 113 114 bmi.bmiHeader = bmiHeader; 115 116 return CreateDIBSection(NULL, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS, &lp, NULL, 0); 117}
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/05/04 00:37 編集
2021/05/04 01:39
退会済みユーザー
2021/05/04 03:03 編集
2021/05/04 05:29 編集
退会済みユーザー
2021/05/04 05:33 編集
2021/05/04 05:59 編集
退会済みユーザー
2021/05/04 06:20 編集
2021/05/04 08:41
退会済みユーザー
2021/05/04 09:20 編集
2021/05/04 09:44