OpenCV用视频采集卡采集灰度图API
OpenCV capture gray scale image with videocapture card API
我正在开发一个 Qt 应用程序,我必须为我工作中的一个项目从不同的视频采集卡(不同版本)采集视频图像。
我已经成功地捕获了几张卡,使用 OpenCV
和 DirectShow
驱动程序(作为标准方法思考),我可以在 cv::Mat
中读取图像,然后,将它们转换成 QImage
。然后我在 QImage 准备就绪的情况下发出信号,MainWindow 接收到该信号并在 QLabel 中绘制捕获的图像(就像我在这里看到的许多示例一样:P)。
但是,现在,我需要在没有 DirectShow 的情况下使用自定义制造商 API 从卡中捕获图像。
总结:使用API,您可以分配一个与组件(例如小部件)关联的Windows句柄(WHND),并在驱动程序接收到捕获的图像时注册回调,渲染图像并将它们绘制到关联的句柄中。渲染和绘画调用的事件是:
int CALLBACK OnVideoRawStreamCallback( BYTE* buffer, ULONG bufLen, unsigned __int64 timeStamp, void* context, ULONG channel, ULONG boardID, ULONG productID );
然后,它调用 ret = AvVideoRender( handle, buffer, bufLen );
,在其中渲染图像并绘制到句柄中。
好吧,我正在尝试替换 "AvVideoRender" 以进行 OpenCv 转换。我认为转换在 cv::Mat 中接收到的 BYTES*,然后在 QImage 中转换这个 cv::Mat 它可以工作,对吧?
问题是我无法获得彩色图像...只有灰度图像。我的意思是,如果我这样做:
int CALLBACK OnVideoRawStreamCallback( BYTE* buffer, ULONG bufLen, unsigned __int64 timeStamp, void* context, ULONG channel, ULONG boardID, ULONG productID )
{
// Original syntax
//ret = AvVideoRender( m_videoRender[0], buffer, bufLen );
// => New
// Converting in a OpenCV Matrix
cv::Mat mMatFrame(IMAGE_HEIGHT, IMAGE_WIDTH, CV_8U , buffer);
// Converting cv::Mat in a QImage
QImage qVideoCam((uchar*)mMatFrame.data, mMatFrame.cols, mMatFrame.rows, mMatFrame.step, QImage::Format_Indexed8);
// Emit a SIGNAL with the new QImage
emit imageReady(qVideoCam);
}
它工作正常,我可以看到视频捕获...但是是灰度颜色。
我认为我必须将 cv::Mat 转换为 CV_8UC3 而不是 CV_8U...但是当应用程序尝试将 cv::Mat 转换为一个QImage。这是我尝试将其转换为彩色图像的示例代码:
int CALLBACK OnVideoRawStreamCallback( BYTE* buffer, ULONG bufLen, unsigned __int64 timeStamp, void* context, ULONG channel, ULONG boardID, ULONG productID )
{
// Original syntax
//ret = AvVideoRender( m_videoRender[0], buffer, bufLen );
// => New
// Converting in a OpenCV Matrix
cv::Mat mMatFrame(IMAGE_HEIGHT, IMAGE_WIDTH, CV_8UC3 , buffer);
// Converting cv::Mat in a QImage
QImage qVideoCam((uchar*)mMatFrame.data, mMatFrame.cols, mMatFrame.rows, mMatFrame.step, QImage::Format_RGB888);
// Emit a SIGNAL with the new QImage
emit imageReady(qVideoCam);
}
视频规格如下:
- 分辨率:720x576 (PAL)
- 帧率:25 帧/秒
- 颜色:YUV12
所以,我想知道是否可以使用此参数将 BYTES* 转换为彩色图像。我认为这是可能的..我确定我做错了什么...但我不知道是什么 :S
我已经使用原始 AvVideoRender 进行了测试,我可以在 QLabel 中看到彩色视频...因此,我可以知道我正在接收彩色图像。但是使用这个解决方案我有一些与我的项目相关的问题(例如,不是通用解决方案)并且我认为我无法控制手柄(我无法获得 Pixmap 并缩放它以保持纵横比,因为示例)
感谢阅读,给您带来的不便深表歉意!
我找到了解决方案:)。最后,我必须将 YV12 数组转换为三维 RGB 数组。我不知道为什么,但是 cv::cvtColor 转换对我不起作用(我尝试了很多组合)。
我发现这个 yv12 到 rgb 的转换(yv12torgb 函数):
http://sourcecodebrowser.com/codeine/1.0/capture_frame_8cpp_source.html
并进行了一些修改以获得 cv::Mat 作为 return 值(由 unsigned char* 代替)。这是解决方案:
cv::Mat yv12ToRgb( uchar *pBuffer, const int w, const int h )
{
#define clip_8_bit(val) \
{ \
if( val < 0 ) \
val = 0; \
else if( val > 255 ) \
val = 255; \
}
cv::Mat result(h, w, CV_8UC3);
long ySize=w*h;
long uSize;
uSize=ySize>>2;
uchar *output=result.data;
uchar *pY=pBuffer;
uchar *pU=pY+ySize;
uchar *pV=pU+uSize;
int y, u, v;
int r, g, b;
int sub_i_uv;
int sub_j_uv;
const int uv_width = w / 2;
const int uv_height = h / 2;
uchar * const rgb = new uchar[(w * h * 4)]; //qt needs a 32bit align
if( !rgb )
return result;
for( int i = 0; i < h; ++i ) {
// calculate u & v rows
sub_i_uv = ((i * uv_height) / h);
for( int j = 0; j < w; ++j ) {
// calculate u & v columns
sub_j_uv = (j * uv_width) / w;
/***************************************************
*
* Colour conversion from
* http://www.inforamp.net/~poynton/notes/colour_and_gamma/ColorFAQ.html#RTFToC30
*
* Thanks to Billy Biggs <vektor@dumbterm.net>
* for the pointer and the following conversion.
*
* R' = [ 1.1644 0 1.5960 ] ([ Y' ] [ 16 ])
* G' = [ 1.1644 -0.3918 -0.8130 ] * ([ Cb ] - [ 128 ])
* B' = [ 1.1644 2.0172 0 ] ([ Cr ] [ 128 ])
*
* Where in xine the above values are represented as
*
* Y' == image->y
* Cb == image->u
* Cr == image->v
*
***************************************************/
y = pY[(i * w) + j] - 16;
u = pU[(sub_i_uv * uv_width) + sub_j_uv] - 128;
v = pV[(sub_i_uv * uv_width) + sub_j_uv] - 128;
r = (int)((1.1644 * (double)y) + (1.5960 * (double)v));
g = (int)((1.1644 * (double)y) - (0.3918 * (double)u) - (0.8130 * (double)v));
b = (int)((1.1644 * (double)y) + (2.0172 * (double)u));
clip_8_bit( b );
clip_8_bit( g );
clip_8_bit( r );
/*rgb[(i * w + j) * 4 + 0] = r;
rgb[(i * w + j) * 4 + 1] = g;
rgb[(i * w + j) * 4 + 2] = b;
rgb[(i * w + j) * 4 + 3] = 0;*/
*output++=b;
*output++=g;
*output++=r;
}
}
return result;
}
然后,我的电话是:
mMatFrame = yv12ToRgb( buffer, IMAGE_WIDTH, IMAGE_HEIGHT );
QImage qVideoCam((uchar*)mMatFrame.data, mMatFrame.cols, mMatFrame.rows, mMatFrame.step, QImage::Format_RGB888);
emit imageReady(qVideoCam);
感谢大家的帮助,给您带来的不便深表歉意:)
我正在开发一个 Qt 应用程序,我必须为我工作中的一个项目从不同的视频采集卡(不同版本)采集视频图像。
我已经成功地捕获了几张卡,使用 OpenCV
和 DirectShow
驱动程序(作为标准方法思考),我可以在 cv::Mat
中读取图像,然后,将它们转换成 QImage
。然后我在 QImage 准备就绪的情况下发出信号,MainWindow 接收到该信号并在 QLabel 中绘制捕获的图像(就像我在这里看到的许多示例一样:P)。
但是,现在,我需要在没有 DirectShow 的情况下使用自定义制造商 API 从卡中捕获图像。
总结:使用API,您可以分配一个与组件(例如小部件)关联的Windows句柄(WHND),并在驱动程序接收到捕获的图像时注册回调,渲染图像并将它们绘制到关联的句柄中。渲染和绘画调用的事件是:
int CALLBACK OnVideoRawStreamCallback( BYTE* buffer, ULONG bufLen, unsigned __int64 timeStamp, void* context, ULONG channel, ULONG boardID, ULONG productID );
然后,它调用 ret = AvVideoRender( handle, buffer, bufLen );
,在其中渲染图像并绘制到句柄中。
好吧,我正在尝试替换 "AvVideoRender" 以进行 OpenCv 转换。我认为转换在 cv::Mat 中接收到的 BYTES*,然后在 QImage 中转换这个 cv::Mat 它可以工作,对吧?
问题是我无法获得彩色图像...只有灰度图像。我的意思是,如果我这样做:
int CALLBACK OnVideoRawStreamCallback( BYTE* buffer, ULONG bufLen, unsigned __int64 timeStamp, void* context, ULONG channel, ULONG boardID, ULONG productID )
{
// Original syntax
//ret = AvVideoRender( m_videoRender[0], buffer, bufLen );
// => New
// Converting in a OpenCV Matrix
cv::Mat mMatFrame(IMAGE_HEIGHT, IMAGE_WIDTH, CV_8U , buffer);
// Converting cv::Mat in a QImage
QImage qVideoCam((uchar*)mMatFrame.data, mMatFrame.cols, mMatFrame.rows, mMatFrame.step, QImage::Format_Indexed8);
// Emit a SIGNAL with the new QImage
emit imageReady(qVideoCam);
}
它工作正常,我可以看到视频捕获...但是是灰度颜色。
我认为我必须将 cv::Mat 转换为 CV_8UC3 而不是 CV_8U...但是当应用程序尝试将 cv::Mat 转换为一个QImage。这是我尝试将其转换为彩色图像的示例代码:
int CALLBACK OnVideoRawStreamCallback( BYTE* buffer, ULONG bufLen, unsigned __int64 timeStamp, void* context, ULONG channel, ULONG boardID, ULONG productID )
{
// Original syntax
//ret = AvVideoRender( m_videoRender[0], buffer, bufLen );
// => New
// Converting in a OpenCV Matrix
cv::Mat mMatFrame(IMAGE_HEIGHT, IMAGE_WIDTH, CV_8UC3 , buffer);
// Converting cv::Mat in a QImage
QImage qVideoCam((uchar*)mMatFrame.data, mMatFrame.cols, mMatFrame.rows, mMatFrame.step, QImage::Format_RGB888);
// Emit a SIGNAL with the new QImage
emit imageReady(qVideoCam);
}
视频规格如下:
- 分辨率:720x576 (PAL)
- 帧率:25 帧/秒
- 颜色:YUV12
所以,我想知道是否可以使用此参数将 BYTES* 转换为彩色图像。我认为这是可能的..我确定我做错了什么...但我不知道是什么 :S
我已经使用原始 AvVideoRender 进行了测试,我可以在 QLabel 中看到彩色视频...因此,我可以知道我正在接收彩色图像。但是使用这个解决方案我有一些与我的项目相关的问题(例如,不是通用解决方案)并且我认为我无法控制手柄(我无法获得 Pixmap 并缩放它以保持纵横比,因为示例)
感谢阅读,给您带来的不便深表歉意!
我找到了解决方案:)。最后,我必须将 YV12 数组转换为三维 RGB 数组。我不知道为什么,但是 cv::cvtColor 转换对我不起作用(我尝试了很多组合)。
我发现这个 yv12 到 rgb 的转换(yv12torgb 函数):
http://sourcecodebrowser.com/codeine/1.0/capture_frame_8cpp_source.html
并进行了一些修改以获得 cv::Mat 作为 return 值(由 unsigned char* 代替)。这是解决方案:
cv::Mat yv12ToRgb( uchar *pBuffer, const int w, const int h )
{
#define clip_8_bit(val) \
{ \
if( val < 0 ) \
val = 0; \
else if( val > 255 ) \
val = 255; \
}
cv::Mat result(h, w, CV_8UC3);
long ySize=w*h;
long uSize;
uSize=ySize>>2;
uchar *output=result.data;
uchar *pY=pBuffer;
uchar *pU=pY+ySize;
uchar *pV=pU+uSize;
int y, u, v;
int r, g, b;
int sub_i_uv;
int sub_j_uv;
const int uv_width = w / 2;
const int uv_height = h / 2;
uchar * const rgb = new uchar[(w * h * 4)]; //qt needs a 32bit align
if( !rgb )
return result;
for( int i = 0; i < h; ++i ) {
// calculate u & v rows
sub_i_uv = ((i * uv_height) / h);
for( int j = 0; j < w; ++j ) {
// calculate u & v columns
sub_j_uv = (j * uv_width) / w;
/***************************************************
*
* Colour conversion from
* http://www.inforamp.net/~poynton/notes/colour_and_gamma/ColorFAQ.html#RTFToC30
*
* Thanks to Billy Biggs <vektor@dumbterm.net>
* for the pointer and the following conversion.
*
* R' = [ 1.1644 0 1.5960 ] ([ Y' ] [ 16 ])
* G' = [ 1.1644 -0.3918 -0.8130 ] * ([ Cb ] - [ 128 ])
* B' = [ 1.1644 2.0172 0 ] ([ Cr ] [ 128 ])
*
* Where in xine the above values are represented as
*
* Y' == image->y
* Cb == image->u
* Cr == image->v
*
***************************************************/
y = pY[(i * w) + j] - 16;
u = pU[(sub_i_uv * uv_width) + sub_j_uv] - 128;
v = pV[(sub_i_uv * uv_width) + sub_j_uv] - 128;
r = (int)((1.1644 * (double)y) + (1.5960 * (double)v));
g = (int)((1.1644 * (double)y) - (0.3918 * (double)u) - (0.8130 * (double)v));
b = (int)((1.1644 * (double)y) + (2.0172 * (double)u));
clip_8_bit( b );
clip_8_bit( g );
clip_8_bit( r );
/*rgb[(i * w + j) * 4 + 0] = r;
rgb[(i * w + j) * 4 + 1] = g;
rgb[(i * w + j) * 4 + 2] = b;
rgb[(i * w + j) * 4 + 3] = 0;*/
*output++=b;
*output++=g;
*output++=r;
}
}
return result;
}
然后,我的电话是:
mMatFrame = yv12ToRgb( buffer, IMAGE_WIDTH, IMAGE_HEIGHT );
QImage qVideoCam((uchar*)mMatFrame.data, mMatFrame.cols, mMatFrame.rows, mMatFrame.step, QImage::Format_RGB888);
emit imageReady(qVideoCam);
感谢大家的帮助,给您带来的不便深表歉意:)