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();
}
}
お礼
わかりやすいお答えをどうもありがとうございます。 おかげさまでうまく透過faviconを作ることができました。