• ベストアンサー

MFC - ダイアログボックスのPictureControlへの画像表示

はじめまして。 現在MFCにおいて、ダイアログ形式のアプリケーションを作成しています。環境はVisual Studio 2005になります。 内容はWebカメラからのキャプチャを行い、そのキャプチャされた画像をダイアログ上に配置したPictureControlへ表示するというものです。 キャプチャされた画像は、1チャネルのグレースケールでありunsigned char型の1次元配列で格納されています。よってビットマップとして表示するには自身で構造体BITMAPINFOを作成しなければなりません。現状以下のように作成したのですが、うまく表示されません。 画像サイズは 320×240 です。 PictureControlのIDを IDC_BITMAP と設定し、 画素情報が格納されている配列を m_pbit とします。 int i; CWnd *pWnd = GetDlgItem( IDC_BITMAP ); CDC *Capt = pWnd->GetDC(); BITMAPINFO bmif; bmif.bmiHeader.biBitCount   =8; bmif.bmiHeader.biClrImportant =0; bmif.bmiHeader.biClrUsed    =256; bmif.bmiHeader.biCompression  =0; bmif.bmiHeader.biHeight     =240; bmif.bmiHeader.biPlanes     =1; bmif.bmiHeader.biSize      =sizeof(BITMAPINFOHEADER); bmif.bmiHeader.biSizeImage   =320*240; bmif.bmiHeader.biWidth     =320; bmif.bmiHeader.biXPelsPerMeter =0; bmif.bmiHeader.biYPelsPerMeter =0; for(i=0; i<256; i++){  bmif.bmiColors[i].rgbBlue = i;  bmif.bmiColors[i].rgbGreen = i;  bmif.bmiColors[i].rgbRed  = i;  bmif.bmiColors[i].rgbReserved = 0; } SetDIBitsToDevice(Capt->m_hDC, 0, 0, 320, 240, 0, 0, 0, 240, m_pbit, &bmif, DIB_RGB_COLORS); グレースケール画像なので配列bmiColorsは全て同色としました。 また、PictureControlのTypeをオーナ描画など全てのTypeを試しましたが、表示されませんでした。 必ずPictureControlに描画しなければならないという決まりはないのですが、ダイアログボックスにビットマップを表示するにはPictureControlだと考え、それに表示するようプログラムを組みました。 画素情報(グレースケールの輝度情報)のみ既知である状態からビットマップをダイアログに表示するためには他に方法があるのでしょうか? 上記のプログラムにおける間違い、またその他の方法についてアドバイスを頂けたらと思います。 よろしくお願いいたします。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

 こんにちは。  パレットサイズ(biClrUsedの数字)の分だけRGBQUADの配列を拡張して割り当てないといけません。  正しくは、以下です。実際には、予め割り当てておくのが良いでしょう。 //割り当てる LPBITMAPINFO pbmi = static_cast<LPBITMAPINFO>(::malloc(sizeof(BITMAPINFOHEADER) + (sizeof(RGBQUAD) * 256))); pbmi->bmiHeader.biBitCount=8; pbmi->bmiHeader.biClrImportant=0; pbmi->bmiHeader.biClrUsed=256; pbmi->bmiHeader.biCompression=0; pbmi->bmiHeader.biHeight=240; pbmi->bmiHeader.biPlanes=1; pbmi->bmiHeader.biSize=sizeof(BITMAPINFOHEADER); pbmi->bmiHeader.biSizeImage=320*240; pbmi->bmiHeader.biWidth=320; pbmi->bmiHeader.biXPelsPerMeter=0; pbmi->bmiHeader.biYPelsPerMeter=0; for(i=0;i<256;i++) { pbmi->bmiColors[i].rgbBlue=i; pbmi->bmiColors[i].rgbGreen=i; pbmi->bmiColors[i].rgbRed=i; pbmi->bmiColors[i].rgbReserved=0; } ::SetDIBitsToDevice(Capt->m_hDC, 0, 0, 320, 240, 0, 0, 0, 240, m_pbit, pbmi, DIB_RGB_COLORS); //開放する ::free(pbmi); -------------------------------------------------------------------------------------------------------------- 強引ですが、以下の様なやり方も出来ます。 struct BMI { BITMAPINFOHEADER bmiHeader; RGBQUAD arrPalette[256]; }; //キャストする BMI bmi; LPBITMAPINFO pbmi = reinterpret_cast<LPBITMAPINFO>(&bmi); //ヘッダとパレットの代入をする pbmi->bmiHeader.biBitCount=... //使用する ::SetDIBitsToDevice(...) //開放は必要ない

happy-hack
質問者

お礼

返信ありがとうございました。 BITMAPINFOHEADER + RGBQUADのメモリ領域を確保しなければいけなかったのですね。適切なアドバイスに感謝します。 キャプチャの方も無事にPictureControlへ出力することができました。 ありがとうございます。

その他の回答 (1)

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.2

リソースエディタでピクチャーコントロールのTypeは変更なさいましたか? ピクチャーコントロールを追加しただけではTypeは『フレーム』になっています この状態では ピクチャーコントロールに対してSetBitmapを行ってもイメージを表示しません Typeを『ビットマップ』に変更しましょう プロパティIDも『IDC_STATIC』以外にしたほうがいいでしょう CBitmapクラスを使うというのも一つの手ですよ ダイアログクラスのメンバーに CBbitmap m_bmpObj などを追加して ピクチャーボックスにセットするときに m_bmpObj.DeleteObject(); // orgBmp[320 x 240]にグレースケールのデータがあるとして char* pbuf = (char*)calloc( 320*240, sizeof(RGBQUAD) ) for ( int y = 0; y < 240; y++ ) {   for ( int x = 0; x < 320; x++ ) {     pbuf[ y * 1280 * ( x * 4 ) + 0 ] = orgBmp[ y * 320 + x ];     pbuf[ y * 1280 * ( x * 4 ) + 1 ] = orgBmp[ y * 320 + x ];     pbuf[ y * 1280 * ( x * 4 ) + 2 ] = orgBmp[ y * 320 + x ];     pbuf[ y * 1280 * ( x * 4 ) + 3 ] = 0;   } } m_bmpObj.CreateBitmap( 320, 240, 1, 32, pbuf ); // m_ctlPictureはピクチャーボックスのコントロール変数 m_ctlPicture.SetBitmap( m_bmpObj ); // または // ((CStatic*)GetDlgItem(IDC_PICTURE1))->SetBitmap( m_bmpObj ); free( pbuf );

happy-hack
質問者

お礼

返信ありがとうございます。 確かにCBitmapクラスを使用し、1チャネルを3チャネルに変換後に表示する方法もありますね。参考にさせていただきます。ただ pbuf[ y * 1280 * ( x * 4 ) + 0 ] は pbuf[ y * 1280 + ( x * 4 ) + 0 ] ですね。 丁寧に解説いただきありがとうございました。

関連するQ&A

  • mfcの画像表示で、bmp表示がよくわかりません

    mfcの画像表示で、bmp表示がよくわかりません。 特に、SelectObject()でBitmapを戻す等が特によくわかりません。 今までは、そういうもんだとしてきたのですが、放っておけない事態になりまして、 相談させて下さい。 (1)下記のbmpDC.SelectObject(oldbmp)等について、その仕組みを詳細に紹介しているHPを ご存じでしたらお教えください。 (2)下記プログラムの画像の扱いで、まずい部分を、おかしいなと思われた部分をお教えください。  動作は、問題なく動作しています。BITMAPを敷き詰めるプログラムです。 CArray<HBITMAP> hBitAry; (HBITMAPを配列にしているまずさは今回は除外して下さい。) … int topX=-100-5; int topY=0; int hLen=100; int wLen=100; int yoko=0; CDC *pDC=mPict.GetDC(); for(int i=0; i<hBitAry.GetCount(); i++) { CDC bmpDC; bmpDC.CreateCompatibleDC(pDC); CBitmap *pBitmap=CBitmap::FromHandle(hBitAry.GetAt(i)); BITMAP BMP; pBitmap->GetBitmap(&BMP); CBitmap *oldbmp=bmpDC.SelectObject(pBitmap); if(yoko<3) { topX+=100+5; yoko++; } else { topX=0; topY+=100+5; yoko=0; } pDC->SetStretchBltMode(COLORONCOLOR); pDC->StretchBlt(topX,topY,100,100,&bmpDC,0,0,BMP.bmWidth,BMP.bmHeight,SRCCOPY); bmpDC.SelectObject(oldbmp); ::DeleteObject(CBitmap::FromHandle(hBitAry.GetAt(i))); } ReleaseDC(pDC); どうぞよろしくお願い致します。

  • ビットマップ画像の色取得のご相談

    ビットマップ画像の色取得のご相談 WinXPでVC++2008ExpressEditionを使用してWinアプリケーションで画像処理をしようとしています.そこで,現在ビットマップのカラー画像を二値化(閾値判別分析法)するために,各色の抽出してグレースケール化を試みているのですが,色々試したのですがエラーがとれないので,もし間違い等ありましたら,ご助言いただけたらなと思います.何卒よろしくお願いいたします. 【エラー内容】 'System.ArgumentOutOfRangeException' のハンドルされていない例外が System.Drawing.dll で発生しました。追加情報: パラメータは正の値で、高さより小さい値指定しなければなりません。 【流れ】(ボタンを押したら以下三つを実行) 1.ファイルの読み込みピクチャーボックスに表示 2. ビットマップ画像の色の抽出 3. グレースケール化 /*ここから*/ OpenFileDialog^ OpenDlg = gcnew OpenFileDialog; //ファイルを開くダイアログ OpenDlg->Filter ="画像ファイル(*.bmp,*.jpg,*.jpeg,*.png,*.tif,*.tiff,*.ico)|*.bmp;*.jpg;*.jpeg;*.png;*.tif;*.tiff;*.ico"; OpenDlg->ShowDialog(); //ダイアログの表示 if (OpenDlg->FileName == "") { //ファイル名が指定されなかった場合 return; } Bitmap^ bmp; bmp = gcnew Bitmap(OpenDlg->FileName); //Bitmapをファイルより作成 pictureBox1->Image = bmp; //ピクチャボックスへ画像の表示 Bitmap^ bmp1 = gcnew Bitmap(pictureBox1->Image); unsigned char Image_in[480][640][3]; //Image_in[Y][X][3] unsigned char (*Gray)[640] = new unsigned char[480][640]; //(*Gray)[X] = new unsigned char[Y][X] double Y; int i, j; //iがY方向,jがX方向 Color color1; unsigned char R,G,B; // 赤,緑,青成分の抽出 for( i = 1; i < 480; i++) //Y方向 { for( j = 1; j < 640; j++) //X方向 { ////////////////////////////////////////////// /*この辺がエラーの原因だと思うのですが・・・*/ color1 = bmp->GetPixel(i,j); R = color1.R; G = color1.G; B = color1.B; Image_in[i][j][0] = R; Image_in[i][j][1] = G; Image_in[i][j][2] = B; } } //RGB to Gray カラー画像をグレースケール化 for( i = 0; i < 480; i++) //Y方向 { for( j = 0; j < 640; j++) //X方向 { Y = 0.299*Image_in[i][j][0] + 0.587*Image_in[i][j][1] + 0.114*Image_in[i][j][2]; Gray[i][j] = Y; } }

  • ダイアログボックスについて。

    ダイアログボックスについての質問です。 開発環境はVisual C++ 2005.netでありSDKを利用しています。 ダイアログボックスにPicture Controlを貼り付け、Combo Boxの内容が変わるたびにそのPicture Controlに画像を表示するようなプログラムを作りたいと考えています。 自分が考える手順としてはまずPicture Controlについてサブクラス化を行い、親のダイアログボックスが表示されると同時にPicture ControlのプロシージャでWM_CREATEメッセージを受け取り描画を行う。 そして親のダイアログボックスに貼り付けたCombo Boxの内容が変更された場合に、Picture ControlのウィンドウハンドルにむけてWM_PAINTメッセージを送信する。 こんな手順で行いたいのですが、少し不安な部分が出てきました。 Combo Boxの内容が変更され、Picture Controlのウィンドウハンドルに向けてWM_PAINTメッセージを送信し、Picture ControlプロシージャではWM_PAINTメッセージがきたとき画像の描画を行う場合、このプロシージャではどの画像を描画してよいか不明です。 そのため何番の画像の表示命令が来たのかを示すために、親のダイアログボックスに貼り付けたCombo Boxが変更された場合、Picture Controlに向けてWM_PAINTメッセージと表示画像番号をパラメータとして送信したいのです。 もちろんグローバル変数を用意すれば簡単なのですが、できるだけ使用しないように記述をしたいのです。そこで考えたのが、 SendMessage(GetDlgItem(hDlgWnd, IDC_PICTURE), WM_PAINT, 0, MAKELPARAM(0, number)); このようにnumberをLPARAMの下位ワードとして送信しようと考えました。 このメッセージ送信を行い、Picture ControlプロシージャでWM_PAINTメッセージが到着したとき、LOWORD(lparam)からnumberを取り出す。 実現したい目的のため、このような方法を考えましたが、エラーなく実行できるでしょうか? もしあやしい部分が見つかった場合はアドバイスをお願いします。そしてこの方法よりも簡単に処理できる方法があれば教えていただきたいです。 自分としてはサブクラス化は面倒なので、Picture Controlをオーナードローとして扱う方法も考えましたが、うまく動きませんでしたTT

  • c言語を使いダイアログにbmpを表示したい 

    はじめまして、 私は、c言語は初心者なのでが、ダイアログボックスに、画像(bmp)が表示することができません。 ソースは、 hdc = BeginPaint(hDlg, &ps); //指定ウィンドウ内での描写準備 // ビットマップをファイルからロードする hBitmap = ::LoadBitmap( NULL, _T("test.bmp") ); // ウィンドウのデバイスコンテキストハンドルを取得する hDC = GetDC( hDlg ); // メモリデバイスコンテキストを作成する hCompatDC = CreateCompatibleDC( hDC ); // ロードしたビットマップを選択する GetObject(hBitmap, sizeof(BITMAP), &bmp); // ビットマップをウィンドウに転送する(表示する) if(hBitmap != NULL){ StretchBlt( hDC, 0, 0, 100, 100, hCompatDC, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY ); SendDlgItemMessage( hDlg, IDC_STATIC, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap); } なのですが、これはメインウィンドウでは動くのですが、ダイアログボックスでは動かずこまっています。 どうか、助言のほどよろしくお願いします。

  • ■IllustratorとPhotoshop、画像の濃度が異なって表示される

    こんにちは、皆さんのご助力をぜひお願い致します。 ■今、IllustratorCSでチラシの原稿を作成しています。 TIFF形式のグレースケール画像(400dpi)を配置し、その上にフォントを載せたいと思いました。 グレースケール画像は、紙に書かれた絵をスキャンし、Photoshop6.0にて加工した画像です。 ■で、このグレースケール画像をIllustrator内で表示した際、画像の濃度が、Photoshopで表示した場合に比べ、薄く表示されてしまいます。 Photoshop画面での画像の濃度を100%とすると、Illustratorでは70%ぐらいなのです。 そして、印刷した場合でも、同様の結果になります。 ■ソフトの違いによって、グレースケール画像の濃度が異なるので、困っています。どちらのソフトでも、同じ濃度で表示されるようにしたいのです。 ■カラー設定なども、調べてみたのですが、RBG、CYMKの設定は両者とも同じです。 ちなみに、カラー画像の場合(CYMK)は、このような濃度の差異はあまりありません。グレースケール画像においてのみ、表示の差異が大きいのです。 どうぞよろしくお願い致します。

  • Bitmap.GetPixelより高速なもの

    いまVBでBitmap.GetPixelを使って、グレースケールの画像のRGBを取得しています。 まあグレースケールなんでRGB同じなのでとりあえずRの値を使うとして、 200*300の画像をFor文でBitmap.GetPixelを使うととてもじゃないぐらい遅いです。 ある程度調べると、LockBits()というものが見つかったのですが使い方がわかりません。 教えてください。

  • ScanLineを使っての画像の色データ取得

    現在、Visual C++を使用して、ある画像のグレースケール化、二値化などの加工を行うプログラムを作成しています。 しかし、今は各ピクセルの値を1つずつとっている状態なので、(行の)for文の中に(列の)for文がある状態になっていて計算量が多くなっているため、加工画像を表示させるまでに時間が少しかかっています。 そこで、ScanLineを用いて1行のデータをとるようなプログラムを作っているのですが、「・・・のメンバーではありません」などのエラーが出て、実行することができない状態です。 現在、加工画像は Bitmap^ bmap_gray=gcnew Bitmap(pictureBox1->Image); としているのですが、ScanLineを使うにはどのようなプログラム文を書けばいいのでしょうか?

  • ボタンクリックでタブ内のピクチャコントロールに画像描画

    呼び出し元ダイアログ(A)と コンボボックスのあるダイアログ(B) そしてタブの中に入るダイアログ(C)があります。 それぞれのダイアログ内にあるものは以下のとおり A→ボタン1(IDC_BUTTON1)…Bを呼び出すためのもの   ボタン2(IDC_BUTTON2)…画像を呼び出すためのもの   タブ(IDC_TAB1)…Cが入るもの B→コンボボックス(IDC_COMBO1)…画像を選択するもの   ↓   dataは「picture1;picture2」   OK/CANCELボタン…略 C→ピクチャボックス(IDC_PICT1)…画像を表示させるためのもの プログラムでAのタブの中にCを入れるところを完成しました。 次に以下のようなことをやりたいのですが、どのように処理をしたらいいのかわかりません。 ボタン1を押す→Bが呼び出される→コンボボックスで画像を選択→ボタン2を押す→タブ内のピクチャボックスにコンボボックスで指定した画像が表示される。 というようにしたいです。 1つのダイアログ上で画像をピクチャボックスに表示するものはやったことがありますが、ダイアログを挟んでの表示はやったことがないためここ2日悩んでいます。 下手な説明かとは思いますがご教授の程よろしくお願いいたします。 ※コンボボックス変数→CComboBox m_combo; ピクチャボックス変数→CStatic m_picture;

  • 8bit(256色)グレースケール画像の保存

    32bitのRGB画像ではなく、8bitのグレースケール画像を保存したいと考えています。 保存形式は、tiffとbmpのどちらでも構いません。 ですが、以下のような方法では、 アルファチャンネルを含んだ32bitのRGB画像が保存されてしまいます。 (作成中のプログラムの一例)    Dim img As Bitmap    Dim x As Integer    Dim y As Integer    img = New Bitmap(256, 50)    For x = 0 To 255       For y = 0 To 49          img.SetPixel(x, y, Color.FromArgb(x, x, x))       Next    Next    img.Save("gradation.tif", System.Drawing.Imaging.ImageFormat.Tiff) なお、一例として単純なグラデーション画像を保存していますが、 あくまでも一例であり、グラデーション画像を作成することが目的ではありません。 最終的には、VisualBasicのBitmapクラスで作成したbitmap画像を Photoshopで、8bitのグレースケール画像として開けることが理想です。 どうか、アドバイスをよろしくお願い致しますm(__)m

  • エディットボックスの背景の色変更方法

    C++初心者です。 どうしても、答えが出てこないことがあり質問致します。 環境 VC++Express2008 Win32API ダイアログベース ダイアログにResEditにエディットボックスを配置して あとは文字や背景の色替えをコーディングしてます。 文字は表示できるのですがその背景を色替えができません。 いろいろ、ネットで調べるも、ほとんどMFCのサンプルばかりで 意味がわかりません。 テストプログラムは以下です。 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { hInst = hInstance; //ダイアログボックス表示 DialogBox(hInst,MAKEINTRESOURCE(IDD_DIALOG1), NULL, DialogProc); return 0; } BOOL CALLBACK DialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hdc; HWND pWnd; PAINTSTRUCT ps; switch (msg) { case WM_INITDIALOG: break; case WM_PAINT: pWnd = GetDlgItem(hWnd, IDC_EDIT10); hdc = BeginPaint(pWnd,&ps); SetBkColor(hdc, RGB(0,255,0)); //←うまくいかない!! SetWindowText(pWnd, _T("aaa")); EndPaint(pWnd, &ps);       break;         以下省略 これで、テキスト"aaa"は表示されますが、背景は変わりません。 SetBkColorの使い方がまずいと思うのですが 僕のイメージ的にSetWindowTextと同じようにウィンドウハンドル指定で 背景を変える方法ってないのかなって素人ながら思うのですが、、わかりません。 あと、質問が変わってしまうのですが、ダイアログウィンドウに100個くらいのエディットボックスを 作成して、それらの背景色を替えて状態表示(点滅もあり)を行うようなものを作りたいのですが ナンセンスなのでしょうか? Rectangleで座標指定で100個の箱を作成する方がCPU負荷などもないのかなーって思います。 では、質問の内容がよくわからない点などあるかもしれませんが よろしくお願いいたします。