由於項目需要,近期一直在做基於攝像機方面的研究,前幾天寫了一個小程序,要實時顯示攝像機捕捉到的圖像,本來以爲是一件很簡單的事情,卻讓我費了不少功夫,也學到了不少東西。攝像機都有自己的SDK,截取部分有自己的API,我所要做的就是把攝像機截取到的圖像格式(yuv422)轉換到我顯示所需要的rgb格式(這個我近期會抽時間研究下,然後寫點東西),然後通過調用OpenCV函數來顯示就可以了,但我遇到的問題卻是一個又一個。
在創建完OpenCV所支持的圖像數據結構IplImage後,需要把轉換後的rgb格式複製到IplImage數據結構中,在複製的過程中,我把行列順序弄反,結果後來得到的圖像是花屏。另外一個比較有意思的事情是關於OpenCV函數cvShowImage()和cvWaitKey(),之前都是用這兩個函數顯示一幅圖像,從來沒有做過連續顯示(視頻顯示)的工作,當我確認我的IplImage是千真萬確正確後,我用cvShowImage()函數顯示卻得到了一幅灰色圖像,而且鼠標顯示一直處於忙碌狀態,因爲我要用while(1)循環一直調用cvShowImage()函數,我當時把cvWaitKey()函數放在了while循環外面,抱着試試看的態度我把cvWaitKey()函數放在循環內部cvShowImage()的後面,圖像就可以正常顯示了,google下,原來有人遇到和我一樣的問題:http://www.opencv.org.cn/forum/viewtopic.php?f=1&t=3324&p=11520,看了上面的解釋,自己還是有些不明白,主要是對Windows編程瞭解很少,裏面關於消息處理機制的東西不太明白。
爲了方便讀者看,把Windows平臺下的cvWaitKey()代碼貼在這裏:
cvWaitKey( int delay )
{
int time0 = GetTickCount();
for(;;)
{
CvWindow* window;
MSG message;
int is_processed = 0;
if( (delay > 0 && abs((int)(GetTickCount() - time0)) >= delay) || hg_windows == 0 )
return -1;
if( delay <= 0 )
GetMessage(&message, 0, 0, 0);
else if( PeekMessage(&message, 0, 0, 0, PM_REMOVE) == FALSE )
{
Sleep(1);
continue;
}
for( window = hg_windows; window != 0 && is_processed == 0; window = window->next )
{
if( window->hwnd == message.hwnd || window->frame == message.hwnd )
{
is_processed = 1;
switch(message.message)
{
case WM_DESTROY:
case WM_CHAR:
DispatchMessage(&message);
return (int)message.wParam;
case WM_KEYDOWN:
TranslateMessage(&message);
default:
DispatchMessage(&message);
is_processed = 1;
break;
}
}
}
if( !is_processed )
{
TranslateMessage(&message);
DispatchMessage(&message);
}
}
}
關於cvWaitKey()函數的說明:
函數原型:int cvWaitKey( int delay=0 );
The cvWaitKey() function asks the program to stop and wait for a keystroke.
If a positive argument is given, the program will wait for that number of milliseconds and then continue even if nothing is pressed.
If the argument is set to 0 or to a negative number, the program will wait indefinitely for a keypress.
鑑於以上幾點:
我現在的處理方法是:把cvWaitKey()函數放在循環內部cvShowImage()的後面,參數選1,1ms的時間還是可以忽略不計的。這樣就可以實時的顯示攝像機圖像了。