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
上記、承知しました。
どうもありがとうございます。
|
|