- 締切済み
OpenCVの透過処理
VC 2010 C++/CLI + OpenCVで教えていただきたい事が有ります。 【教えていただきたい事】 ・pbPictureの画像を透過処理して表示 ※ 同じサイズの画像をアルファブレンドしたり、上面の画像の背景のみを透過するサンプルは見かけるのですが、 背面と異なるサイズの上面の画像全体を透過する、サンプルを見つけられませんでした。 (純粋に透過する機能がopenCVには無いとの事で、小細工が必要なのだと考えています) 【やりたいこと】 ・pbBackground(Picturebox)に背景となる画像を読込表示 ・pbPicture(Picturebox)に親フォームで作成したBMPの図形(画像)を半透明(透過率50%位)で重ねて表示 ・pbBackgroundのサイズは読込データ依存 ・pbPictureのサイズは親フォームで作成した図形依存 ※つまり、pbBackgroundとpbPictureは違うサイズ ・将来的には、マウス移動でpbPictureの位置、大きさ、台形補間をする予定 イメージとしては、下記URLのお化け屋敷の画像とほぼ同じ http://aidiary.hatenablog.com/entry/20061203/1251465083 ※実際は、背景が風景で、上書きする画像は建屋 【現状できているのは】 ・cvLoadImageで画像を読込してpbBackgroundに描画 ・親フォームで作成した図形を無加工でpbPictureに描画 【現状のソース】 System::Void PhotoRead_Click(System::Object^ sender, System::EventArgs^ e) { double BmpX,BmpY,XYRatio; double PhotoX,PhotoY; int PX,PY; System::Drawing::Point p; System::String^ filename; // pbBackgroundのディフォルトサイズは500×500 OpenFileDialog^ OpFile = gcnew OpenFileDialog(); // OpFile->DefaultExt = "jpg"; OpFile->Filter = "画像ファイル(*.jpg;*.png;*.bmp;*.gif)|*.jpg;*.png;*.bmp;*.gif"; if (OpFile->ShowDialog() == Windows::Forms::DialogResult::OK) { SuspendLayout(); filename = OpFile->FileName; // String^型をchar*に安全に変換 char* pStr = (char*)System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi( filename ).ToPointer(); // ファイル読み込み IplImage* img = cvLoadImage( pStr ); if( img == 0 ){ return; } // Bitmapに直接img->imgDataを読ませると、エラーになるのでコピーデータを渡す IntPtr ip( new unsigned char[ img->widthStep * img->height ] ); memcpy( ip.ToPointer(), img->imageData, img->widthStep * img->height ); Bitmap^ bmp = gcnew Bitmap(img->width, img->height, img->widthStep, System::Drawing::Imaging::PixelFormat::Format24bppRgb, ip); // 読み込みデータは解放 cvReleaseImage( &img ); //ピクチャボックスをビットマップ画像サイズに合わせる BmpX = (double)bmp->Width; BmpY = (double)bmp->Height; PhotoX = 500; PhotoY = 500; p.X = 10; p.Y = 40; PX = 500; PY = 500; if (BmpX <= BmpY) { XYRatio = BmpY / BmpX; PX = (int)(PhotoX / XYRatio); p.X = 10 + (500 - PX) /2; } else { XYRatio = BmpX / BmpY; PY = (int)(PhotoY / XYRatio); p.Y = 40 + (500 - PY) /2; } PictureBox^ pbBackground=gcnew PictureBox; pbBackground->Location = p; // サイズ指定、従来はWidthとHeightを別々に定義していたが、Sizeを使用すると1行で済む pbBackground->Size=System::Drawing::Size(PX,PY); //ピクチャボックスのImageへ読込画像をセット pbBackground->SizeMode = PictureBoxSizeMode::StretchImage; pbBackground->Image = bmp; Controls->Add(pbBackground); // ピクチャーボックスのpbBackgroundを親としているので、相対座標は0にする BmpX = (double)PhotBMP->Width; BmpY = (double)PhotBMP->Height; PhotoX = pbBackground->Width; PhotoY = pbBackground->Height; GX = (int)(PX / 2 - 100) + p.X; GY = (int)(PY / 2 - 100) + p.Y; // PictureBoxのグラフィックエリアにBitmapを描画する。 PictureBox^ pbPicture=gcnew PictureBox; pbPicture->Parent = pbBackground; pbPicture->Location = System::Drawing::Point(GX, GY); pbPicture->Size = System::Drawing::Size(200, 200); pbPicture->SizeMode = PictureBoxSizeMode::StretchImage; // 上書きする画像をセット pbPicture->Image = PhotBMP; Controls->Add(pbPicture); // デバッグで見やすくするためにバックをどぎつい色に BackColor=Color::FromArgb(0xFF,0xFF,0x00,0x00); pbPicture->BringToFront(); pbCursor->BringToFront(); ResumeLayout(); } }
- みんなの回答 (2)
- 専門家の回答
みんなの回答
- myuki1232
- ベストアンサー率57% (97/170)
>cvAddWeightedだと、同じサイズ、移動時は再計算、変形後の配列をどうするかなどなど、 >問題があって、cvAddWeightedでは実現できないと考えております。 cvAddWeighted を出したのはただの例です。 合成方法など無数にありますから、ご自分で用途に合う関数をお選びください。 >ROIは矩形しか対応していないと色々なところで記載されていたので、 >考えていなかったのですが、ROIで非対称の台形なども指定できるのでしょうか? そんなことは自分で組み合わせてするのですよ。 OpenCV 自体は別に 3D に限定するものではない、汎用の画像処理ライブラリですから、台形変換がしたいのであれば、台形変換をすればいいのです。 幸いにも、cvWarpPerspective という関数で透視投影変換ができ、cvGetPerspectiveTransform で変換行列を簡単に求められます。 台形変換は透視投影変換の一種ですから、できますよね。 >移動時は再計算…など、問題があって…実現できないと考えております。 を見て思ったのですが、使い方を根本的に勘違いしていませんか? OpenGL では GPU に処理ステージというものがあって、モデルビュー変換や投影変換はパラメータを指定すれば勝手にやってくれますが、 OpenCV は汎用の画像処理ライブラリですから、そのようなフレームワークは無く、変換同士の組み合わせや、パラメータが変わった時の再計算などは全部自分でやる必要があります。
- myuki1232
- ベストアンサー率57% (97/170)
アルファ合成をするには、例えば AddWeighted のような関数を使用します。 http://opencv.jp/opencv-2svn/c/core_operations_on_arrays.html#addweighted ただし、既にご存知の通り、同じ合成する2者の画像は同じサイズでなければなりません。 > マスクを除くすべての入出力配列は,同じ型,同じサイズ(または ROI サイズ)でなければいけません. 異なるサイズの画像の中の一部に対して操作するには、ROI(Region Of Interest; 注目領域)というものを設定する必要があります。 http://opencv.jp/opencv-2svn/c/core_operations_on_arrays.html#setimageroi 今回の場合ですと、背景画像の中の任意の座標に、上面画像と同じサイズのROIを設定してから合成するとよいでしょう。
補足
回答ありがとうございます。 cvAddWeightedだと、同じサイズ、移動時は再計算、変形後の配列をどうするかなどなど、 問題があって、cvAddWeightedでは実現できないと考えております。 OpenGLの様にZバッファを用いて、アルファ値を設定するだけで、背景が透過されるのが好ましいのですが、 GLはGLで色々制約があるので、CVで実現する方法があればと思い質問させていただきました。 ROIは矩形しか対応していないと色々なところで記載されていたので、 考えていなかったのですが、ROIで非対称の台形なども指定できるのでしょうか? ※CvPoint2D32fも矩形しか対応してなく、実際は長方形とひし形(頂点が対象)の物しかできないので、 やる前から諦めてました
お礼
ありがとうございます でも、ご意見ではなく、回答をいただけると助かるのですが。