トップページ > 記事閲覧
OpenCV(IplImage)への画像変換
名前:あき 日時: 2013/08/31 23:46

LoadGraphで読み込んだ画像をOpenCVのIplImageに変換する方法はあるでしょうか? 過去ログを拝見したところ、IplImageをDXライブラリで取り扱うための変換方法は見つけましたが、その逆の方法がわかりませんでした。 現在、PlayMovieToGraphで動画再生しているのですが、再生中の動画をフレーム毎にOpenCVで加工した上で別の動画ファイルとして保存するのが目的です。 ※動画再生自体はOpenCVでも可能なのですが、OpenCVは音声出力に対応していないため、動画再生はDXライブラリ(PlayMovieToGraph)を利用したいです。
メンテ

Page: 1 |

Re: OpenCV(IplImage)への画像変換 ( No.1 )
名前:管理人 日時:2013/09/01 23:15

PlayMovieToGraph で再生中の動画の各ピクセルの色を取得するには GetMovieBaseImageToGraph で取得できる BASEIMAGE 構造体を使います 各ピクセルの色を取得して DrawPixel で動画を描画するようなプログラムは以下のようになります #include "DxLib.h" int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { int MovieHandle ; int i, j ; int r = 0, g = 0, b = 0 ; BASEIMAGE *MovieImage ; BYTE *Image ; ChangeWindowMode( TRUE ) ; if( DxLib_Init() == -1 ) return -1 ; MovieHandle = LoadGraph( "Test.avi" ) ; PlayMovieToGraph( MovieHandle, DX_PLAYTYPE_LOOP ) ; SetDrawScreen( DX_SCREEN_BACK ) ; while( ProcessMessage() == 0 ) { ClearDrawScreen() ; // 動画の更新も兼ねているので毎フレーム GetMovieBaseImageToGraph を呼ぶ MovieImage = GetMovieBaseImageToGraph( MovieHandle ) ; // ピクセルフォーマットが R8G8B8 の 24bit の場合と X8R8G8B8 の 32bit の場合があるので switch で分岐 switch( MovieImage->ColorData.ColorBitDepth ) { case 24 : // R8G8B8 for( i = 0 ; i < MovieImage->Height ; i ++ ) { // iライン目のピクセル情報が格納されているメモリアドレスの算出 Image = ( BYTE * )MovieImage->GraphData + i * MovieImage->Pitch ; for( j = 0 ; j < MovieImage->Width ; j ++ ) { DrawPixel( j, i, GetColor( Image[ 2 ], Image[ 1 ], Image[ 0 ] ) ) ; Image += 3 ; // 1pixel分メモリアドレスを進める } } break ; case 32 : // X8R8G8B8 for( i = 0 ; i < MovieImage->Height ; i ++ ) { // iライン目のピクセル情報が格納されているメモリアドレスの算出 Image = ( BYTE * )MovieImage->GraphData + i * MovieImage->Pitch ; for( j = 0 ; j < MovieImage->Width ; j ++ ) { DrawPixel( j, i, GetColor( Image[ 2 ], Image[ 1 ], Image[ 0 ] ) ) ; Image += 4 ; // 1pixel分メモリアドレスを進める } } break ; } ScreenFlip() ; } DxLib_End() ; return 0 ; } OpenCV は使用したことがないので解説などを見ての予想になるのですが、毎フレームの動画の イメージを OpenCV の IplImage に変換するとなると以下のような感じになると思います・・・ ( コンパイルできるかどうかは確認していません ) #include <cv.h> #include <highgui.h> #include <ctype.h> #include "DxLib.h" int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { int MovieHandle ; int i, j ; int r = 0, g = 0, b = 0 ; BASEIMAGE *MovieImage ; BYTE *Image ; BYTE *CvImageP ; IplImage *CvImage ; ChangeWindowMode( TRUE ) ; if( DxLib_Init() == -1 ) return -1 ; MovieHandle = LoadGraph( "Test.avi" ) ; PlayMovieToGraph( MovieHandle, DX_PLAYTYPE_LOOP ) ; MovieImage = GetMovieBaseImageToGraph( MovieHandle ) ; // 動画のサイズの R8G8B8 フォーマットの IplImage を作成 CvImage = cvCreateImage( cvSize( MovieImage->Width, MovieImage->Height ), IPL_DEPTH_8U, 3 ) ; SetDrawScreen( DX_SCREEN_BACK ) ; while( ProcessMessage() == 0 ) { ClearDrawScreen() ; // 動画の更新も兼ねているので毎フレーム GetMovieBaseImageToGraph を呼ぶ MovieImage = GetMovieBaseImageToGraph( MovieHandle ) ; // ピクセルフォーマットが R8G8B8 の 24bit の場合と X8R8G8B8 の 32bit の場合があるので switch で分岐 switch( MovieImage->ColorData.ColorBitDepth ) { case 24 : // R8G8B8 for( i = 0 ; i < MovieImage->Height ; i ++ ) { // iライン目のピクセル情報が格納されているメモリアドレスの算出 Image = ( BYTE * )MovieImage->GraphData + i * MovieImage->Pitch ; CvImageP = ( BYTE * )CvImage->imageData + i * CvImage->widthStep ; for( j = 0 ; j < MovieImage->Width ; j ++ ) { CvImageP[ 0 ] = Image[ 0 ] ; // 青 CvImageP[ 1 ] = Image[ 1 ] ; // 緑 CvImageP[ 2 ] = Image[ 2 ] ; // 赤 // 1pixel分メモリアドレスを進める Image += 3 ; CvImageP += 3 ; } } break ; case 32 : // X8R8G8B8 for( i = 0 ; i < MovieImage->Height ; i ++ ) { // iライン目のピクセル情報が格納されているメモリアドレスの算出 Image = ( BYTE * )MovieImage->GraphData + i * MovieImage->Pitch ; CvImageP = ( BYTE * )CvImage->imageData + i * CvImage->widthStep ; for( j = 0 ; j < MovieImage->Width ; j ++ ) { CvImageP[ 0 ] = Image[ 0 ] ; // 青 CvImageP[ 1 ] = Image[ 1 ] ; // 緑 CvImageP[ 2 ] = Image[ 2 ] ; // 赤 // 1pixel分メモリアドレスを進める Image += 4 ; CvImageP += 3 ; } } break ; } ScreenFlip() ; } DxLib_End() ; return 0 ; }
メンテ
Re: OpenCV(IplImage)への画像変換 ( No.2 )
名前:あき 日時:2013/09/01 15:51

管理人様、早々のご回答ありがとうございます。 GetMovieBaseImageToGraph関数の存在を初めて知りました。 早速、下記ソースを試していますが、GetMovieBaseImageToGraphで取得したBASEIMAGEは 全て0がセットされている状態で、Width、Heightを参照しても0となっています。 再生自体は行えているので、動画ファイルは正しく読み込めているのですが 何かわかりますでしょうか? ============================================== int MovieHandle = 0; BASEIMAGE *MovieImage = NULL; IplImage *CvImage = NULL; // 動画ファイル読み込み MovieHandle = LoadGraph( "TEST.AVI" ) ; if ( MovieHandle == -1 ) return 1; } // 再生 PlayMovieToGraph( MovieHandle, DX_PLAYTYPE_LOOP ) ; // 現在のフレームのBASEIMAGEを取得 MovieImage = GetMovieBaseImageToGraph( MovieHandle ) ; →取得後、MovieImage->Width と MovieImage->Height はいずれも0。 CvImage = cvCreateImage( cvSize( MovieImage->Width, MovieImage->Height ), IPL_DEPTH_8U, 3 ) ; ==============================================
メンテ
Re: OpenCV(IplImage)への画像変換 ( No.3 )
名前:管理人 日時:2013/09/01 23:32

すみません、動画再生は非同期で行われているので PlayMovieToGraph を実行した直後は 画像データがまだ格納されていないのでした・・・ 画像のサイズは GetGraphSize で取得することができますので、 CvImage = cvCreateImage( cvSize( MovieImage->Width, MovieImage->Height ), IPL_DEPTH_8U, 3 ) ; この部分を以下のように書き換えてください int ImageWidth, ImageHeight ; GetGraphSize( MovieHandle, &ImageWidth, &ImageHeight ) ; CvImage = cvCreateImage( cvSize( ImageWidth, ImageHeight ), IPL_DEPTH_8U, 3 ) ; あと、動画の画像が更新されたかどうかも確認する手段が無かったので、GetMovieBaseImageToGraph に 引数を追加して更新されたかどうかを取得できるようにしました BASEIMAGE * GetMovieBaseImageToGraph( int GraphHandle, int *ImageUpdateFlag ) ; 追加した第二引数に int型の変数のアドレスを渡すとそこに前回の GetMovieBaseImageToGraph 呼び出し以降に 画像が更新されたかどうかが格納されます( TRUEが格納された場合:更新された FALSEが格納された場合:更新されていない ) この変更を行ったバージョンをアップしましたので、よろしければダウンロードしてください m(_ _;m http://homepage2.nifty.com/natupaji/DxLib/DxLibVCTest.exe // VisualC++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibBCCTest.exe // BorlandC++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibGCC_DevCppTest.exe // Dev-C++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibGCC_MinGWTest.exe // MinGW 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibDotNet.zip // .NET用 http://homepage2.nifty.com/natupaji/DxLib/DxLibMakeTest.exe // ソース (中身を既存のライブラリのファイルに上書きして、BCCをお使いの 場合は『再構築』を、VCをお使いの場合は『リビルド』を、 Dev-C++をお使いの方は「Rebuild All(Ctrl+F11)」をして下さい) 追加した第二引数を使うようにプログラムを書き直すと以下のようになります #include <cv.h> #include <highgui.h> #include <ctype.h> #include "DxLib.h" int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { int MovieHandle ; int i, j ; int r = 0, g = 0, b = 0 ; BASEIMAGE *MovieImage ; BYTE *Image ; BYTE *CvImageP ; IplImage *CvImage ; int ImageUpdateFlag ; int ImageWidth, ImageHeight ; ChangeWindowMode( TRUE ) ; if( DxLib_Init() == -1 ) return -1 ; MovieHandle = LoadGraph( "Test.avi" ) ; PlayMovieToGraph( MovieHandle, DX_PLAYTYPE_LOOP ) ; // 動画のサイズの R8G8B8 フォーマットの IplImage を作成 GetGraphSize( MovieHandle, &ImageWidth, &ImageHeight ) ; CvImage = cvCreateImage( cvSize( ImageWidth, ImageHeight ), IPL_DEPTH_8U, 3 ) ; // 動画の再生が終了するまで繰り返し while( GetMovieStateToGraph( MovieHandle ) == TRUE ) { // 動画の画像が更新されるのを待つ while( ProcessMessage() == 0 ) { MovieImage = GetMovieBaseImageToGraph( MovieHandle, &ImageUpdateFlag ) ; if( ImageUpdateFlag == TRUE ) break ; // 更新されていなかったらCPUを少し休ませる Sleep( 1 ) ; } // ピクセルフォーマットが R8G8B8 の 24bit の場合と X8R8G8B8 の 32bit の場合があるので switch で分岐 switch( MovieImage->ColorData.ColorBitDepth ) { case 24 : // R8G8B8 for( i = 0 ; i < MovieImage->Height ; i ++ ) { // iライン目のピクセル情報が格納されているメモリアドレスの算出 Image = ( BYTE * )MovieImage->GraphData + i * MovieImage->Pitch ; CvImageP = ( BYTE * )CvImage->imageData + i * CvImage->widthStep ; for( j = 0 ; j < MovieImage->Width ; j ++ ) { CvImageP[ 0 ] = Image[ 0 ] ; // 青 CvImageP[ 1 ] = Image[ 1 ] ; // 緑 CvImageP[ 2 ] = Image[ 2 ] ; // 赤 // 1pixel分メモリアドレスを進める Image += 3 ; CvImageP += 3 ; } } break ; case 32 : // X8R8G8B8 for( i = 0 ; i < MovieImage->Height ; i ++ ) { // iライン目のピクセル情報が格納されているメモリアドレスの算出 Image = ( BYTE * )MovieImage->GraphData + i * MovieImage->Pitch ; CvImageP = ( BYTE * )CvImage->imageData + i * CvImage->widthStep ; for( j = 0 ; j < MovieImage->Width ; j ++ ) { CvImageP[ 0 ] = Image[ 0 ] ; // 青 CvImageP[ 1 ] = Image[ 1 ] ; // 緑 CvImageP[ 2 ] = Image[ 2 ] ; // 赤 // 1pixel分メモリアドレスを進める Image += 4 ; CvImageP += 3 ; } } break ; } } DxLib_End() ; return 0 ; } よろしければお試しください
メンテ
Re: OpenCV(IplImage)への画像変換 ( No.4 )
名前:あき 日時:2013/09/03 22:16

管理人様 バージョンアップありがとうございます。 まとまった時間が取れず、すぐに試すことができず申し訳ありませんが 動画のピクセルフォーマットを得るにはGetMovieBaseImageToGraphでBASEIMAGEを取得する以外に方法はないでしょうか? 最初にピクセルフォーマットに合ったIplImageを作成しておいて 再生中の動画のイメージはmemcpyでサイズ分コピーすればソースがよりスマートになるかと思いまして。 (できれば毎フレームごとにピクセルフォーマットを判断したくない。) 動画再生は非同期ということなので、ちょっと無理やりですが GetMovieBaseImageToGraphでBASEIMAGEが取得できるまで待機させるくらいしか思いつかず。。
メンテ
Re: OpenCV(IplImage)への画像変換 ( No.5 )
名前:管理人 日時:2013/09/05 14:02

> 動画のピクセルフォーマットを得るにはGetMovieBaseImageToGraphでBASEIMAGEを取得する以外に方法はないでしょうか? はい、無いです 少し改良して、LoadGraph の直後に GetMovieBaseImageToGraph を呼んでも BASEIMAGE 構造体の中の メンバー変数 GraphData 以外は有効な値が入るようにしました これで最初のフレームの画像が格納される前からピクセルフォーマットと幅、高さを GetMovieBaseImageToGraph で 取得できるようになりました ただ、ピッチ( 1ライン辺りのバイト数 )はアライメントの関係で BASEIMAGE、IplImage 双方とも必ずしも 幅 * 1ピクセル辺りのバイト数 ではありませんので、memcpy を使用するとしても if( MovieImage->Pitch == CvImage->widthStep ) { memcpy( CvImage->imageData, MovieImage->GraphData, MovieImage->Pitch * MovieImage->Height ) ; } else { BYTE *Dest ; BYTE *Src ; int CopySize ; Dest = ( BYTE * )CvImage->imageData ; Src = ( BYTE * )MovieImage->GraphData ; CopySize = MovieImage->ColorData.ColorBitDepth / 8 * MovieImage->Width ; for( i = 0; i < MovieImage->Height ; i ++ ) { memcpy( Dest, Src, CopySize ) ; Dest += CvImage->widthStep ; Src += MovieImage->Pitch ; } } ↑のように Pitch と widthStep が等しくない場合は縦解像度の回数だけ memcpy を呼ぶようにする必要があります
メンテ
Re: OpenCV(IplImage)への画像変換 ( No.6 )
名前:あき(解決) 日時:2013/09/05 16:30

> 少し改良して、LoadGraph の直後に GetMovieBaseImageToGraph を呼んでも BASEIMAGE 構造体の中の > メンバー変数 GraphData 以外は有効な値が入るようにしました > これで最初のフレームの画像が格納される前からピクセルフォーマットと幅、高さを GetMovieBaseImageToGraph で > 取得できるようになりました この点も改良頂いていたのですね。ありがとうございます。 アライメントというワードを初めて聞いたので、OpenCV側を調べてIplImage構造体を確認したところ > int widthStep; /* アライメントが調整された画像の行のバイトサイズ */ とありました。(4バイト単位に調整されているとのことです。) これも大変勉強になりました。 やりたい事が実現できましたのでこれで解決とさせて頂きます。 ご丁寧に説明頂いてありがとうございましたm(_ _)m
メンテ
Re: OpenCV(IplImage)への画像変換 ( No.7 )
名前:管理人 日時:2013/09/05 17:47

すみません、内容を変更したのに暫定バージョンのURLを載せておくのを忘れていました m(_ _;m 新しい正式バージョンでも変更は反映されていますが一応・・・ http://homepage2.nifty.com/natupaji/DxLib/DxLibVCTest.exe // VisualC++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibBCCTest.exe // BorlandC++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibGCC_DevCppTest.exe // Dev-C++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibGCC_MinGWTest.exe // MinGW 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibDotNet.zip // .NET用 http://homepage2.nifty.com/natupaji/DxLib/DxLibMakeTest.exe // ソース (中身を既存のライブラリのファイルに上書きして、BCCをお使いの 場合は『再構築』を、VCをお使いの場合は『リビルド』を、 Dev-C++をお使いの方は「Rebuild All(Ctrl+F11)」をして下さい)
メンテ
Re: OpenCV(IplImage)への画像変換 ( No.8 )
名前:あき(解決) 日時:2013/09/05 18:41

上記、承知しました。 どうもありがとうございます。
メンテ

Page: 1 |

題名
名前
コメント
パスワード (記事メンテ時に使用)

   クッキー保存