OpenCV使用视频捕捉卡API捕获灰度图像

时间:2015-03-04 11:56:01

标签: qt opencv video capture

我正在开发一个Qt应用程序,我必须在工作中为不同的视频采集卡(不同版本)捕获视频图像。

我使用OpenCVDirectShow驱动程序(作为标准方法考虑)成功捕获了几张卡片,我可以在cv::Mat中读取图像,然后,将它们转换为QImage。然后我发出一个准备好QImage的信号,并且MainWindow接收到这个信号,在QLabel中绘制捕获的图像(就像我在这里看到的很多例子:P)。

但是,现在,我需要使用自定义制造商API从卡中捕获图像而不使用DirectShow。

总结:使用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_8UC3转换cv :: Mat而不是CV_8U ...但是当应用程序尝试将cv :: Mat转换为QImage时,我有一个unhandle异常。这是我的示例代码尝试将其转换为彩色图像:

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)
  • FrameRate:25 fps
  • 颜色:YUV12

所以,我想知道,如果用这个参数我可以在彩色图像中转换BYTES *。我认为这是可能的......我确信我做错了什么......但我不知道是什么:S

我已经使用原版AvVideoRender进行了测试,我可以在QLabel中看到彩色视频...所以,我知道我已经收到了彩色图像。但是通过这个解决方案,我遇到了一些与我的项目相关的问题(例如,不是一般解决方案),我认为我无法控制句柄(我无法获得Pixmap并将其保持为纵横比,例如)

感谢阅读并抱歉给您带来不便!

1 个答案:

答案 0 :(得分:0)

我得到了解决方案:)。最后,我不得不将YV12阵列转换为三维RGB阵列。我不知道为什么,但是,cv :: cvtColor转换对我来说并不起作用(我尝试了很多组合)。

我发现这个yv12转换为rgb(yv12torgb函数):

http://sourcecodebrowser.com/codeine/1.0/capture_frame_8cpp_source.html

并进行了一些修改以获得cv :: Mat作为返回值(以无符号字符*表示)。这是解决方案:

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);

感谢所有人的帮助,对不起的不便之处:)