• 締切済み

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(); } }

みんなの回答

  • myuki1232
  • ベストアンサー率57% (97/170)
回答No.2

>cvAddWeightedだと、同じサイズ、移動時は再計算、変形後の配列をどうするかなどなど、 >問題があって、cvAddWeightedでは実現できないと考えております。 cvAddWeighted を出したのはただの例です。 合成方法など無数にありますから、ご自分で用途に合う関数をお選びください。 >ROIは矩形しか対応していないと色々なところで記載されていたので、 >考えていなかったのですが、ROIで非対称の台形なども指定できるのでしょうか? そんなことは自分で組み合わせてするのですよ。 OpenCV 自体は別に 3D に限定するものではない、汎用の画像処理ライブラリですから、台形変換がしたいのであれば、台形変換をすればいいのです。 幸いにも、cvWarpPerspective という関数で透視投影変換ができ、cvGetPerspectiveTransform で変換行列を簡単に求められます。 台形変換は透視投影変換の一種ですから、できますよね。 >移動時は再計算…など、問題があって…実現できないと考えております。 を見て思ったのですが、使い方を根本的に勘違いしていませんか? OpenGL では GPU に処理ステージというものがあって、モデルビュー変換や投影変換はパラメータを指定すれば勝手にやってくれますが、 OpenCV は汎用の画像処理ライブラリですから、そのようなフレームワークは無く、変換同士の組み合わせや、パラメータが変わった時の再計算などは全部自分でやる必要があります。

usami33
質問者

お礼

ありがとうございます でも、ご意見ではなく、回答をいただけると助かるのですが。

  • myuki1232
  • ベストアンサー率57% (97/170)
回答No.1

アルファ合成をするには、例えば 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を設定してから合成するとよいでしょう。

usami33
質問者

補足

回答ありがとうございます。 cvAddWeightedだと、同じサイズ、移動時は再計算、変形後の配列をどうするかなどなど、 問題があって、cvAddWeightedでは実現できないと考えております。 OpenGLの様にZバッファを用いて、アルファ値を設定するだけで、背景が透過されるのが好ましいのですが、 GLはGLで色々制約があるので、CVで実現する方法があればと思い質問させていただきました。 ROIは矩形しか対応していないと色々なところで記載されていたので、 考えていなかったのですが、ROIで非対称の台形なども指定できるのでしょうか? ※CvPoint2D32fも矩形しか対応してなく、実際は長方形とひし形(頂点が対象)の物しかできないので、  やる前から諦めてました

関連するQ&A

  • Open CVについて

    現在,OpenCVとVC++2008のC++/CLIでwindows formアプリケーションを作成しています。 フォーム上のpictureBoxにUSBカメラから取得した画像を,録画しながら,pictureBoxに表示させています。しかし,取り込んだ画像が,pictureBoxに収まり切っていないようです。(添付画像のようなに枠内の画像に対して,肌色部分しか,pictureBoxに表示されていない状態) コードは http://hisoap.jugem.jp/?eid=156 を参考に,以下のように記述しています。 CvCapture *capture srcImage = cvQueryFrame(capture); Bitmap^ bmpPicBox = gcnew Bitmap(pictureBox->Width, pictureBox->Height); pictureBox->Image = bmpPicBox; Graphics^g = Graphics::FromImage(pictureBox->Image); Bitmap^ bmp = gcnew Bitmap(pictureBox->Width, pictureBox->Height, srcImage->widthStep,System::Drawing::Imaging::PixelFormat::Format24bppRgb, IntPtr(srcImage->imageData)); g->DrawImage(bmp, 0, 0, srcImage->width , srcImage->height); どのようにすれば,画像をpictureBoxにぴったりと表示させることができるでしょうか?

  • vc++ 2005 Pictureboxの透過処理

    お世話になります。 VC 2005で開発しているC++で教えていただきたい事が有ります。 PictureboxBの上にPictureboxAを透過率50%位で重ねて表示したいのですが、 Pictureboxのプロパティ等で一括で指定できないでしょうか? 出来ない場合、画像を一括で透過処理する方法が有りましたら教えていただけないでしょうか ※ ググって、単色を透過するのは、色々見つけたのですが、画像全体を透過する方法を見つけることが出来ませんでした。 現状は単純にファイル(写真)を読み込んで、PictureboxのImageに格納しているだけです。 ※将来的には、PictureboxAをドラッグで移動させたいので、背景画像(PictureboxB)との位相を取る方法以外でお願いいたします。 Bitmap^ PhotBMP = gcnew Bitmap(filename); // この間にサイズ変更&位置合わせの処理が有りますが、記載を省略させていただいております。 PictureboxA->Image = PhotBMP;

  • 二つの画像を並べて表示

    ひとりで独学でVC++2005を勉強してるのですが、pictureBoxでつまずいます。初心者ですがわかりやすく教えて頂けたらと思います。 やりたい事はタイトル通り、画像を単純に並べて表示したいだけなのですが、WEB場で検索しても的を得た答えが見つかりませんでした。 二つの画像を読み込んで、新しいBitmapデータに書き込めばいいのかと思ったのですが、どうやっていいのか見当が付きません。 Bitmap^ bmpA = gcnew Bitmap("testAA.bmp"); Bitmap^ bmpB = gcnew Bitmap("testAB.bmp"); int w = bmpA->Width + bmpB->Width; int h = bmpA->Height + bmpB->Height; Bitmap^ bmp = gcnew Bitmap(w,h); //ここで何やっていいかわかりません。 pictureBox1->Image = bmp; 最終的にはタイル的にどんどん並べて行きたいと考えています。 助言の方よろしくお願いします。

  • プログラムで、bmpをjpgに替えたらエラーして困ってます・・・。

    マネージ形式でbmpの画像の情報をlabel1などで表示できたんですけど、ファイル名の形式をjpgにしたら、情報が表示できずにエラーしました。 どこがまちがってるか、教えてください。 エラーした、プログラムをのせるんでアドバイスお願いします。 private: System::Void button3_Click(System::Object^ sender, System::EventArgs^ e) {   Bitmap^image2; image2 = gcnew Bitmap( "画像名.jpg");   pictureBox1->Image = image2;        label3->Text = String::Format("幅(width) 高さ(height): {0}", image2->Size); } この、プログラムで、bmgの時は、image2 = gcnew Bitmap( "画像名.bmp");で、組んでエラーはなっかたんですけど、jpgの時は、image2 = gcnew Bitmap( "画像名.jpg");でしたら、エラーします。 MSDNで探してもわからず、色々試したんですがエラーしかでません。 ネットで検索してもあまりいい例が見つかりませんでした。適切なアドバイスお願いします。

  • VB.NETにおける二値化処理の高速化

    いつも参考にさせて頂いております。 現在、VB.NET(VS2003/.NET Framework1.1)を使用して画像の二値化処理のプログラムを作成しております。 処理する事は簡単で、ビットマップファイルのRED要素を取り出し、閾値内なら白に変換して二値化するプログラムです。 以下がそのプログラムです。 ----- '変換する前の画像をファイルから読み込む Dim img1 As System.Drawing.Bitmap = New System.Drawing.Bitmap(filepath) '変換後のビットマップ Dim img2 As System.Drawing.Bitmap = New System.Drawing.Bitmap(img1.Width, img2.Height) '二値化処理 Dim b As Byte For i = 0 To img1.Width - 1 For j = 0 To img1.Height - 1 b = img1.GetPixel(i, j).R If b >= 閾値下限 And b <= 閾値上限 Then img2.SetPixel(i, j, Color.White) Else img2.SetPixel(i, j, Color.Black) End If Next Next PictureBox1.Image = img ----- これで処理は出来るのですが、ファイルが大きい場合は、非常に時間が掛かってしまいます。処理速度はCPUの速度にもよると思うのですが、できるだけ高速化したのですが、何かよい知恵があればご教授頂けると助かります。よろしくお願いいたします。 XP Pro SP2/VS2003/VB.NET/.NET Framework1.1

  • 色の変更

    また分からないことが出来ましたので、よろしくお願いいたします。 今、openFileDialogで画像を読取、その画像の黒色を白色に変更してpicutreBoxに表示するプログラムを作成しています。 [C#] Bitmap img = new Bitmap(openFileDialog.FileName); Graphics g = Graphics.FromImage(img); System.Drawing.Imaging.ColorMap[] cms = new System.Drawing.Imaging.ColorMap[] {new System.Drawing.Imaging.ColorMap(), new System.Drawing.Imaging.ColorMap()}; cms[0].OldColor = Color.Black; cms[0].NewColor = Color.White; System.Drawing.Imaging.ImageAttributes ia = new System.Drawing.Imaging.ImageAttributes(); ia.SetRemapTable(cms); g.DrawImage(img, new Rectangle(img.Width + 10, 0, img.Width, img.Height), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel,ia); g.Dispose(); PictureBox1.Image = img; という風に作成したのですが、色が変更されませんでした。 どこが違うのか分かられる方がいらっしゃいましたら、よろしくお願いいたします。

  • 兄弟のpictureboxは透過処理をするには?

    度々質問して申し訳ありません。 Controls.Addで親子にしたpicturebox はちゃんと透過処理してくれるのですが、 同じ親pictureboxの子供たち(兄弟)同士の透過処理が行われません。 違う設定が必要なのでしょうか? 教えていただけますか?よろしくお願いします。 文字数多くて載せられないので、重要であろう箇所のみです。スミマセン。 image = New Bitmap("c:\image.png")'透過部有 iconGraphics = Graphics.FromImage(image) Icon1 = New System.Windows.Forms.PictureBox iconGraphics.DrawImage(image, 0, 0, iconSize, iconSize) PictureBox1.Image = image Icon1.Location = New Point(8, 8) Icon1.Width = iconSize Icon1.Height = iconSize Icon1.BackColor = Color.Transparent PictureBox1.Controls.Add(Me.Icon1) Icon1.BringToFront() Icon1.Image = image

  • VB.netでのPictuerBoxに描写した内容の保存について。

    VB.netでのPictuerBoxに描写した内容の保存について。 PictureBoxに描写した内容を保存してみると、描写した項目事態は正しく保存されているのですが、背景が真っ黒になってしまいますこれは、なぜなのでしょうか? ソースは以下の様な感じです。 Dim bmp As Bitmap Dim g As Graphics bmp = New Bitmap(PictureBox1.Width, PictureBox1.Height) PictureBox1.Image = bmp g = Graphics.FromImage(PictureBox1.Image) g.DrawLine(Pens.AliceBlue, 0, 10, 20, 10) PictureBox1.Refresh() PictureBox1.Image.Save("test.jpg", System.Drawing.Imaging.ImageFormat.Jpeg) どなたかわかる方よろしくお願いいたします。

  • Visual Basic 拡大方法について

    こんばんわ Visual Basic 2010を使用してプログラミングをしています。 地図の画像を読み込み、ダブルクリックをすると拡大するというものを組んでいます。 ただ、ダブルクリックすると拡大するところまではできたのですが ダブルクリックしたところがパソコンの画面の中央にくるようにするにはどうすればいいかがわかりません。 方法が分かるかた助言、アドバイスよろしくお願いいたします。 参考までに現在組んでいる拡大部分のコードは以下のようになっています。 パソコンの画面サイズは1200*800です Private Sub PictureBox1_DoubleClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.DoubleClick Dim bmp = New Bitmap(PictureBox1.Image, PictureBox1.Width * 1.5, PictureBox1.Height * 1.5) PictureBox1.SizeMode = PictureBoxSizeMode.AutoSize PictureBox1.Image = bmp PictureBox1.Refresh() End Sub よろしくお願いいたします。

  • VC++2005で高解像度画像の取り扱い。

    いつも質問ばかりで申し訳ないのですが、独学で勉強していて聞ける人がいないので協力して頂けたらと思います。 VC++2005のOS Windows32bit環境で高解像度(10240pixel × 10240pixel以上)の画像を取り扱うにはどうしたら良いのでしょうか? Bitmap^ bmp = gcnew Bitmap( 10240, 10240 ); ~省略 pictureBox1->Image = bmp ; のような書き方をして、エラーが出てる場所は Bitmap^ bmp = gcnew Bitmap( 10240, 10240 ); の部分です。 Bitmap^ bmp = gcnew Bitmap( 5120, 5120 ); だと平気です。 メモリーが不足しています。と警告が出てるのですが、はやり32bit環境では限界なのでしょうか? PCには8GB(うち5GB、RAMディスク)のメモリーを積んでますが、そう言う問題でもないですよね。 PhotoShopやAftterEffectとかはかなりの高解像度でも表示出来てるので不可能では無いとは思うのですが、初心者レベルでは無謀なのでしょうか? 何か打開策があれば教えて頂けたら助かります。 よろしくお願いします。

専門家に質問してみよう