Win32におけるOpenGLでの映像描画について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
なまり

Win32におけるOpenGLでの映像描画について

#1

投稿記事 by なまり » 8年前

カメラで映像を撮影し、視線方向の移動を行った上でWindowsのモニタにフルスクリーン表示するというアプリケーションを作成している者です。
現在、OpenGLの「glTexImage2D()」でうまく描画ができず困っています。


以下の手順で映像を取り込んで描画を行おうとしています。
①VC++にカメラ用のSDKをインクルードし、その機能で撮影した1フレームの画像を、RGBA情報を保持するためのbyte配列に格納する。(これを繰り返して映像として映し出す)

②OpenGLで視線方向を指定し、①で取り込んだ配列をテクスチャとして張り付けてモニタ上にレンダリングする。


①については単体で動作を確認したところ、配列に格納した値をPrintfで出力できたため問題ないと思います。

②についてはgClearやRectを用いて簡単に描画し、その状態での視線移動は正常にできていることを確認しました。(参考サイト:http://marupeke296.com/OGL_No1_Install.html
しかし、①で作成したbyte配列をglTexImage2D()の引数に入れて実行したところ、画面上になにも表示されませんでした。タスクバーにアプリケーションが出るため、実行事態はできていると思います。


こちらが作成したプログラムです。Win32やOpenGLを始めたばかりなので、至らない点が多いとは思いますがよろしくお願いします。
そもそも他の方法でやったほうが処理が早いしラクだよという意見もあれば。


おそらく問題は、ウィンドウプロシージャ側のスクリプトにある「DrawScene()」の中だと思います。

_tWinMain側

コード:

#include <windows.h>
#include "resource.h"
// OpenGL
#include <tchar.h>
#include <gl/glut.h>
// FlyCapture
#include <FC1/pgrflycapture.h>	// カメラの関数等(required:include directory "\Point Grey Research\FlyCaptureSDK\include\FC1")
#include <C/FlyCapture2_C.h>
#define TIMER_ID 1
typedef BOOL(WINAPI *PFNWGLSWAPINTERVALEXTPROC)	(int interval);	// wgl関数へのポインタ(VSYNC用)
extern PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;

/////////////////////////////////////////////////////////////////////////////
/// 関数プロトタイプ ////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// _tWinMain()
bool InitApplications();
bool InitRegisterClass( HINSTANCE );
bool InitWindow( HINSTANCE, int);
bool FinalizeApplication();
// WindowProcedure()
LRESULT CALLBACK WindowProcedure( HWND, UINT, WPARAM, LPARAM );
bool InitOpenGL( HWND, HDC*, HGLRC* );
void InitCamera( int );
void FinalizeOpenGL( HGLRC ,HDC );
void DrawScene();

/////////////////////////////////////////////////////////////////////////////
/// 変数・構造体定義 ////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
const char *gName = "OpenGLテスト";
RECT _windowRect = { 0, 0, 800, 600 };
HWND _hWindow;
HGLRC _openglContext;	// 作成ウィンドウ1のコンテキスト
HDC _hdc = NULL;	// 初期化されていないかもよとエラーがでるので仕方なくお外
GLuint _textureID[2];
FlyCaptureContext _contextRight, _contextLeft;
FlyCaptureImage _imageRight, _imageLeft;
FlyCaptureImage _imageConvertedRight, _imageConvertedLeft;
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
unsigned char _pixelRight[640][480][4];

/////////////////////////////////////////////////////////////////////////////
/// メイン関数 //////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)	
	MSG msg;	HACCEL hAccelTable;

/// アプリケーションの初期化 ////////////////////////////////////////////////
	if ( !InitRegisterClass( hInstance ) )
		return -1;
	if ( !InitWindow( hInstance,  nCmdShow ) )
		return -1;
	hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_WIN32OGL);

/// メッセージループ ////////////////////////////////////////////////////////	
	do{
		if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ){
			TranslateMessage( &msg );
			DispatchMessage( &msg );
		}
		else {
			/* 
				To do --命令が来ていないときに処理したいことがあればここに追加--
			*/
		}
	} while ( msg.message != WM_QUIT )

	return 0;
}


/////////////////////////////////////////////////////////////////////////////
/// ウィンドウクラスの生成を行う ////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
bool InitRegisterClass( HINSTANCE hInstance )
{
	// 生成するウィンドウクラスの設定
	WNDCLASSEX wcex = {	sizeof(WNDCLASSEX),	CS_HREDRAW | CS_VREDRAW,WindowProcedure,0,0,hInstance,NULL,NULL,(HBRUSH)(COLOR_WINDOW + 1),NULL,(TCHAR*)gName,NULL };

	// ウィンドウクラスの生成
	if ( (ATOM)0 == RegisterClassEx( &wcex ) ){
		//printf("ウィンドウクラスの生成に失敗しました.\n");
		return false;
	}

	return true;
}


/////////////////////////////////////////////////////////////////////////////
/// ウィンドウの生成を行う //////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
bool InitWindow(HINSTANCE hInstance ,int nCmdShow)
{
	// ウィンドウを生成する
	_hWindow = CreateWindow(gName,gName,WS_VISIBLE | WS_POPUP, 0,	0,_windowRect.right - _windowRect.left,_windowRect.bottom - _windowRect.top,NULL,	NULL, hInstance, NULL);									

// ウィンドウ作成データ (WM_CREATEでLPARAMに渡したい値)
	if ( _hWindow == NULL )
		return false;

	ShowWindow(_hWindow, nCmdShow);
	UpdateWindow(_hWindow);

	SetTimer(_hWindow, TIMER_ID, 20, NULL);

	return true;
}

ウィンドウプロシージャ側

コード:

LRESULT CALLBACK WindowProcedure(HWND _hWindow,UINT message,WPARAM wParam,LPARAM lParam)
{
	PAINTSTRUCT ps;
	RECT rect;

	switch (message){
	case WM_CREATE:
		InitOpenGL( _hWindow, &_hdc, &_openglContext); //下に関数

		wglMakeCurrent( _hdc, _openglContext);      
		InitCamera(0); //下に関数
		wglMakeCurrent(NULL, NULL);

		ReleaseDC( _hWindow, _hdc );
		break;
	case WM_PAINT:
		_hdc = BeginPaint(_hWindow, &ps); // 更新領域を初期化
		wglMakeCurrent(_hdc, _openglContext);      // レンダリングコンテキストをカレントに

		DrawScene();

		wglMakeCurrent(NULL, NULL);      // レンダリングコンテキストをカレントから外す
		EndPaint(_hWindow, &ps);        // 更新領域を空に戻す
		break;
	case WM_TIMER:
		InvalidateRect( _hWindow , NULL, false); // 再描画のメッセージを送る
		break;
	case WM_ERASEBKGND:     // 背景を消さない
		return TRUE;
	// キー入力が発生した場合
	case WM_KEYDOWN:
		switch (wParam){
		// [ESC]キーが押された場合,ウィンドウを削除する
		case VK_ESCAPE:
			DestroyWindow( _hWindow );
			break;
		}
		break;
	case WM_DESTROY:
		PostQuitMessage(0);	//レンダリングコンテキストの削除
		FinalizeOpenGL(_openglContext, _hdc);
		break;
	default:
		return DefWindowProc( _hWindow, message, wParam, lParam);
	}

	return 0;
}

/////////////////////////////////////////////////////////////////////////////
/// OpenGLで描画を行うように設定 ////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
bool InitOpenGL(HWND hWindow,HDC *_hdc,HGLRC *_openglContext)
{
	// ピクセルフォーマットの作成
	PIXELFORMATDESCRIPTOR pixelForMatdescriptor = {sizeof(PIXELFORMATDESCRIPTOR),1,	PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, PFD_TYPE_RGBA,32,0, 0, 0, 0, 0, 0,0,0,0,0, 0, 0, 0,24,8,0,	PFD_MAIN_PLANE,0,0, 0, 0};

	// 生成したウィンドウのディスプレイデバイスコンテキスト(ウィンドウの挙動を決定できる箱)のハンドルを取得 (OpenGLで描写したいウィンドウを指定する)
	*_hdc = GetDC( hWindow );
	if (_hdc == NULL)
		return false;

	// hWindowの領域を_windowRectに格納する
	GetClientRect( hWindow, &_windowRect );

	// デバイスコンテキストに適したピクセルフォーマットを取得
	int format = ChoosePixelFormat( *_hdc, &pixelForMatdescriptor );
	if ( format == 0 )
		return false;

	// OpenGLが使うデバイスコンテキストに指定のピクセルフォーマットをセット
	if ( !SetPixelFormat( *_hdc, format, &pixelForMatdescriptor ) )
		return false;

	// OpenGL contextを作成
	*_openglContext = wglCreateContext( *_hdc );

	// 作成されたコンテキストをカレント(実行状態)にする
	if (!wglMakeCurrent(*_hdc, *_openglContext))
		return false;

	// 垂直同期をとる用
	wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
	if (wglSwapIntervalEXT)
		wglSwapIntervalEXT(1);

	wglMakeCurrent(NULL, NULL);

	ReleaseDC(_hWindow, *_hdc);

	return true;
}


/////////////////////////////////////////////////////////////////////////////
/// カメラの初期化処理 //////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void InitCamera( int cameraNum ){
	if (cameraNum == 0){
		// FlyCaptureカメラのコンテキストを作成
		 flycaptureCreateContext(&_contextRight);
		
		// カメラの初期化
		printf("Initializing Right Camera.\n");

		flycaptureInitialize(_contextRight,	0);		

		printf("Starting Right Camera.\n\n");

		flycaptureStart(	_contextRight,FLYCAPTURE_VIDEOMODE_640x480RGB,FLYCAPTURE_FRAMERATE_30);

		// 変数の初期化
		memset(&_imageRight, 0x0, sizeof(FlyCaptureImage));
		memset(&_imageConvertedRight, 0x0, sizeof(FlyCaptureImage));
		_imageConvertedRight.pData = new unsigned char[sizeof(_pixelRight)];
		_imageConvertedRight.pixelFormat = FLYCAPTURE_BGRU;
	}

	// 有効無効
	glEnable(GL_TEXTURE_2D);
	glEnable(GL_DEPTH_TEST);
	glDisable(GL_CULL_FACE);

	glGenTextures(1, &_textureID[cameraNum]);				
	glBindTexture(GL_TEXTURE_2D, _textureID[cameraNum]);

	// 拡大縮小の設定
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	glPixelStorei(GL_UNPACK_ALIGNMENT, 4);


	//	ウィンドウ全体をビューポートにする
	glViewport(0, 0, 800, 600);
	//	透視変換行列の指定
	glMatrixMode(GL_PROJECTION);
	//	透視変換行列の初期化
	glLoadIdentity();

	gluPerspective(25.0, 800 / 600, 1.0, 100.0);	// 透視変換行列を視野角で設定する
}


/////////////////////////////////////////////////////////////////////////////
/// OpenGLの解放処理(問題のシーン) ///////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void DrawScene(){
	flycaptureGrabImage2(_contextRight,&_imageRight);

	unsigned char *ptr1;
	for (int i = 0; i < 640; i++){
		ptr1 = &(_imageRight.pData[i * _imageRight.iRowInc]);

		for (int j = 0; j < 480; j++)
		{
			_pixelRight[i][j][0] = ptr1[0];
			_pixelRight[i][j][1] = ptr1[1];
			_pixelRight[i][j][2] = ptr1[2];
			_pixelRight[i][j][3] = 255;

			ptr1 += 3;
		}
	}

/// 指定ウィンドウへの描画設定 //////////////////////////////////////////////
	wglMakeCurrent(_hdc, _openglContext);	
	glMatrixMode(GL_MODELVIEW);

	glLoadIdentity();
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

/// 空間の設定 //////////////////////////////////////////////////////////////
	glClear(GL_COLOR_BUFFER_BIT);

	glBindTexture(GL_TEXTURE_2D, _textureID[0]);

	glTexImage2D(
		GL_TEXTURE_2D, 0, GL_RGBA, 640, 480,
		0, GL_RGBA, GL_UNSIGNED_BYTE, _contextRight
		);

	glBegin(GL_QUADS);
	glNormal3d(-1.0, 0.0, 0.0);
	glTexCoord2d(0.0, 1.0);
	glVertex3d(4.5, -1.3275, -1.3275);
	glTexCoord2d(1.0, 1.0);
	glVertex3d(4.5, -1.3275, 1.3275);
	glTexCoord2d(1.0, 0.0);
	glVertex3d(4.5, 1.3275, 1.3275);
	glTexCoord2d(0.0, 0.0);
	glVertex3d(4.5, 1.3275, -1.3275);
	glEnd();

	glFlush();	// ここまでバッファ上で処理したものを実際にレンダリングする
	glBindTexture(GL_TEXTURE_2D, 0);

	
/// 視点の設定 //////////////////////////////////////////////////////////////
	glMatrixMode(GL_MODELVIEW);	// モデルビューにする
	glLoadIdentity();			// 変換処理が累積した変換行列の初期化

	gluLookAt( 
				0.0, 0.0, 0.0,	// 視点の位置x,y,z;
				0.0, 0.0, 0.0,	// 視界の中心位置の参照点座標x,y,z
				0.0, 1.0, 0.0);	// 視界の上方向のベクトルx,y,z
							
	SwapBuffers(_hdc);						// Windows APIのほうでデバイスコンテキストをスワップするらしい ()
	wglMakeCurrent(NULL, NULL);				// ウィンドウ1の描画を終了
}

Win32とOpenGL以外で実現しようとしたこと。
・FlyCaptureのdllをUnityで読み込んでGUI周りの簡略化
 →C#でのダブルポインタやC++とのメモリの取り方の違いあたりで断念
・処理をOpenCVでさせる
 →OpenGLすら分かっていないのに、CVにまで手を出すとやばそうと思い断念


開発環境
・OS :Windows 7 64bit
・ソフト:Visual Studio 2013 Express for Windows Desktop
・カメラ:FL2-03S2C(Point Grey Reserch社)
・glut :freeglut3.0.0 (導入の参考にしたサイト:https://tokoik.github.io/opengl/libglut.html

C6b14

Re: Win32におけるOpenGLでの映像描画について

#2

投稿記事 by C6b14 » 8年前

突然お邪魔します。WinMainに{が抜けてたり;が抜けてたりしましたが真っ黒な画面がでました。(カメラ部分はダミーのコード)https://tokoik.github.io/opengl/libglut.htmlがわかり易かったのでサンプルを作りました。glutを使うのであればWindows基本周りの事はglutに任せたほうがいいのでは?。サンプル画像画像

コード:

#include <windows.h >
#include <stdio.h >
#include <GL/glut.h >
///// TEST_01 --- 画像
#define TEX_HEIGHT 512
#define TEX_WIDTH  512

static GLubyte image[TEX_HEIGHT][TEX_WIDTH][4];
///// TEST_02 --- 単色
#define TEXSIZE 64	//テクスチャの高さ幅
#define MY_RGB 3	//RGBでの指定数
/////
void initTexture(void) /// 画像データの読み込み
{
	FILE *fp;
	int x, z;

	/* texture file open */
	if ((fp = fopen("test.tga", "rb")) == NULL) {
		fprintf(stderr, "texture file cannot open\n");
		return;
	}
	fseek(fp, 18, SEEK_SET);
	for (x = 0; x<TEX_HEIGHT; x++) {
		for (z = 0; z<TEX_WIDTH; z++) {
			image[x][z][2] = fgetc(fp);/* B */
			image[x][z][1] = fgetc(fp);/* G */
			image[x][z][0] = fgetc(fp);/* R */
			image[x][z][3] = fgetc(fp);/* alpha */
		}
	}
	fclose(fp);
}
//描画
void disp(void)
{
	glEnable(GL_TEXTURE_2D);  /// テクスチャ有効

	glClear(GL_COLOR_BUFFER_BIT); /// Clear

	glBegin(GL_POLYGON);

	glTexCoord2f(0, 0); glVertex2f(-0.9, -0.9);
	glTexCoord2f(1, 0); glVertex2f(-0.9, 0.9);
	glTexCoord2f(1, 1); glVertex2f(0.9, 0.9);
	glTexCoord2f(0, 1); glVertex2f(0.9, -0.9);

	glEnd();

	glutSwapBuffers();  // ダブルバッファリング:ScreenFlip:下記002

	//glFlush();
}

// 視点:回る:
void OnTimer(int value) {       /// <---005
	glRotatef(1, 0.5, 1, 0.25); /// //(X,Y,Z)=(0.5,1,0.25)を中心軸に1度回転
	glutPostRedisplay();        /// 20ミリ秒ごとにウィンドウを更新
	glutTimerFunc(20, OnTimer, 0);  /// 005--->
}
//////////////////////////////////////////////////////////////////
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	LPSTR lpCmdLine, int nCmdShow)
{
	/////
	glutInitWindowSize(600, 600); /// 001
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);  /// 002
	glutCreateWindow("GLUT");    /// 003
	glutDisplayFunc(disp);       /// 004
	glutTimerFunc(20, OnTimer, 0); /// 005--->
				 
	GLuint textures; //テクスチャID=Handle

	glGenTextures(1, &textures); /// Handleを獲得

	glBindTexture(GL_TEXTURE_2D, textures);  /// Bind
	//拡大・縮小についての設定
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	//////////////////////////////////////////////////////////////////

	initTexture();  /// 画像データの読み込み

	//テクスチャ:単色
	int h = 0;
	const int MAX = TEXSIZE * TEXSIZE * MY_RGB;
	GLubyte tarray[MAX];
	for (int i = 0; i < MAX; i += 3)
	{
		tarray[i]     = 0xFF; // 赤
		tarray[i + 1] = 0xFF; // 青
		tarray[i + 2] = 0x00; // 緑
	}
/////
	//[テクスチャ作成パターン1][TEST_01]

	glTexImage2D(
		GL_TEXTURE_2D, 0, 3,
		512, 513,
		0, GL_RGBA, GL_UNSIGNED_BYTE, image);

/////
    //[テクスチャ作成パターン2][TEST_02]
	/*
    gluBuild2DMipmaps(
        GL_TEXTURE_2D,3,
        64,64,
        GL_RGB,GL_UNSIGNED_BYTE,tarray);
		*/
/////
	glutMainLoop();  /// 006

	glDeleteTextures(1, &textures); /// Delete

	return 0;
}
////////////////////////////////////////////////////////////////////
Windows10,VS2015 を使用しました。
画像データ(.tga)はhttp://www.oit.ac.jp/is/~whashimo/serve ... /#Section4から借りました。

C6b14

Re: Win32におけるOpenGLでの映像描画について

#3

投稿記事 by C6b14 » 8年前

あ、すみません。85行 h はいらないです。91,92 のコメント 緑、青が逆でした。

C6b14

Re: Win32におけるOpenGLでの映像描画について

#4

投稿記事 by C6b14 » 8年前

よく見ると 99行 512, 513 は 512, 512 です。すみません。 

閉鎖

“C言語何でも質問掲示板” へ戻る