千家信息网

怎么用QT+OpenCV实现录屏功能

发表于:2024-11-27 作者:千家信息网编辑
千家信息网最后更新 2024年11月27日,这篇"怎么用QT+OpenCV实现录屏功能"文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这
千家信息网最后更新 2024年11月27日怎么用QT+OpenCV实现录屏功能

这篇"怎么用QT+OpenCV实现录屏功能"文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇"怎么用QT+OpenCV实现录屏功能"文章吧。

(1)获取窗体界面

QScreen类有一个grabWindow函数,可以用来获取窗体的画面,这个函数使用很简单,就是传入窗体句柄和要截取的坐标。但是这个函数有一个缺陷,它是通过截取桌面画面的方式,而不是通过

窗体获取界面,所以当你的窗体被其他窗体遮挡时,就无法截取完整的窗体界面,如果你是要录制整个桌面画面,那用这个函数就可以了,下面的方法调用GDI函数来实现,即使窗体被遮挡时仍然能够获取到完整界面,但是窗体最小化时也一样无法获取。

/**    函数功能:获取窗体指定窗体图像*   参      数:hd:窗体句柄*                 pm:保存获取到的图片*                 x:截取的起始x坐标,*                 y:截取的起始y坐标,*                 w:截取的宽度*                 h:截取的高度*/bool GetGDIBitmap(HWND hd,QPixmap &pm, int x, int y, int w, int h){    if(hd==NULL)        return false;    HDC hDC;    hDC=GetDCEx(hd,NULL,DCX_PARENTCLIP );    HDC hMemDC;                    //内存缓冲设备环境    HBITMAP hbmMem,hbmOld;        //内存缓冲设备环境中的位图    RECT rc;    rc.left=x;    rc.top=y;    rc.right=x+w;    rc.bottom=y+h;    //判断边境值    RECT clientrc;    ::GetClientRect(hd,&clientrc);    int xc =0;    int cx =0;    int cy =0;    if(rc.bottom>clientrc.bottom || rc.bottom<0)        rc.bottom=clientrc.bottom;    if(rc.right>clientrc.right || rc.right<0)        rc.right=clientrc.right;    // 24位图的BITMAPINFO    BITMAPINFO *pBITMAPINFO = (BITMAPINFO*)malloc(sizeof(BITMAPINFOHEADER));    memset(pBITMAPINFO, 0, sizeof(BITMAPINFOHEADER));    BITMAPINFOHEADER *pInfo_Header = (BITMAPINFOHEADER *)pBITMAPINFO;    pInfo_Header->biSize = sizeof(BITMAPINFOHEADER);    pInfo_Header->biWidth = rc.right - rc.left;    pInfo_Header->biHeight = (rc.bottom - rc.top);    pInfo_Header->biPlanes = 1;    pInfo_Header->biBitCount = 24;    pInfo_Header->biCompression = BI_RGB;    hMemDC=CreateCompatibleDC(hDC);    //创建内存兼容设备环境    //创建内存兼容位图    hbmMem=CreateCompatibleBitmap(hDC,pInfo_Header->biWidth,pInfo_Header->biHeight);    hbmOld=(HBITMAP)SelectObject(hMemDC,hbmMem);    //将内存设备环境中的内容绘制到物理设备环境   hDC    BitBlt(hMemDC,0,0,pInfo_Header->biWidth,pInfo_Header->biHeight,hDC,cx+rc.left,xc+cy+rc.top,CAPTUREBLT|SRCCOPY);    HBITMAP hBitmap=(HBITMAP)SelectObject(hMemDC,hbmOld);    // 获得数据buf    DWORD bufSize=(pInfo_Header->biWidth * 3 + 3) / 4 * 4 * pInfo_Header->biHeight;    BYTE * pBuffer = new BYTE[bufSize];    int aHeight=pInfo_Header->biHeight;    if(::GetDIBits(hMemDC, hBitmap, 0, aHeight, pBuffer,pBITMAPINFO, DIB_RGB_COLORS) == 0)    {        return false;    }    bool bret=BitmapToPixmap(hBitmap,pm);    ReleaseDC(hd,hDC);    //释放资源    DeleteObject(hbmMem);    DeleteObject(hbmOld);    DeleteDC(hMemDC);    free(pBITMAPINFO);    ::DeleteObject(hBitmap);    delete [] pBuffer;    return bret;}    /**    函数功能:将bitmap转为QPixmap*/bool BitmapToPixmap(HBITMAP hBitmap, QPixmap &pm){    HDC     hDC;    //设备描述表    int     iBits;    //当前显示分辨率下每个像素所占字节数    WORD    wBitCount;    //位图中每个像素所占字节数    //定义调色板大小, 位图中像素字节大小 ,  位图文件大小 , 写入文件字节数    DWORD           dwPaletteSize=0,dwBmBitsSize,dwDIBSize;    BITMAP          Bitmap;    //位图属性结构    BITMAPFILEHEADER   bmfHdr;    //位图文件头结构    BITMAPINFOHEADER   bi;    //位图信息头结构    LPBITMAPINFOHEADER lpbi;    //指向位图信息头结构    HANDLE          hDib, hPal;    HPALETTE     hOldPal=NULL;    //定义文件,分配内存句柄,调色板句柄    //计算位图文件每个像素所占字节数    hDC = CreateDC(L"DISPLAY",NULL,NULL,NULL);    iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);    DeleteDC(hDC);    if (iBits <= 1)        wBitCount = 1;    else if (iBits <= 4)        wBitCount = 4;    else if (iBits <= 8)        wBitCount = 8;    else if (iBits <= 24)        wBitCount = 24;    else        wBitCount = 24;    //计算调色板大小    if (wBitCount <= 8)        dwPaletteSize=(1<buffer;    uchar *p=(uchar*)&bmfHdr;    // 写入位图文件头    buffer.insert(buffer.end(),p,p+sizeof(BITMAPFILEHEADER));    // 写入位图文件其余内容    p=(uchar*)lpbi;    buffer.insert(buffer.end(),p,p+sizeof(BITMAPINFOHEADER)+dwPaletteSize+dwBmBitsSize);    //清除    GlobalUnlock(hDib);    GlobalFree(hDib);    pm=QPixmap::fromImage(QImage::fromData(buffer.data(),buffer.size()));    return true;}

(2)录制画面

bool g_needstop =false;void Record(){     RECT rect;     //获取窗体位置大小     GetWindowRect(hd,&rect);     cv::Size frameSize;     frameSize.width=rect.right-rect.left;     frameSize.height=rect.bottom-rect.top;        cv::VideoWriter VideoWriter;     if(!VideoWriter.open("d:\\1.avi",CV_FOURCC('M', 'J', 'P', 'G'),40,frameSize))         return;    while(!g_needstop)    {        QPixmap pm;        GetGDIBitmap(hd,pm,0,0,frameSize.width,frameSize.height);        VideoWriter.write(ImageToMat(pm.toImage()));    }        VideoWriter.release(); }Mat ImageToMat(QImage img,QString imgFormat){    if(img.isNull())        return Mat();    QByteArray ba;    QBuffer buffer(&ba);    buffer.open(QIODevice::WriteOnly);    img.save(&buffer,imgFormat.toLatin1().data());    _InputArray arrSrc(ba.data(), ba.size());    Mat mat = cv::imdecode(arrSrc, CV_LOAD_IMAGE_COLOR);    return mat;}

(3) 播放视频

void Play(){    cv::VideoCapture Capture;    if(!Capture.open("d:\\1.avi"))          return;    Mat frame;    //逐帧读取画面    while(Capture.read(frame))    {            //转成QImage格式用于显示           QImage img = MatToImage(frame);           emit Frame(img);           QThread::msleep(40);    }    Capture.release();    emit PlayFinsh();}QImage MatToImage(Mat mat){    if(mat.type() == CV_8UC1)    {        QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);        // Set the color table (used to translate colour indexes to qRgb values)        image.setColorCount(256);        for(int i = 0; i < 256; i++)        {            image.setColor(i, qRgb(i, i, i));        }        // Copy input Mat        uchar *pSrc = mat.data;        for(int row = 0; row < mat.rows; row ++)        {            uchar *pDest = image.scanLine(row);            memcpy(pDest, pSrc, mat.cols);            pSrc += mat.step;        }        return image;    }    // 8-bits unsigned, NO. OF CHANNELS = 3    else if(mat.type() == CV_8UC3)    {        // Copy input Mat        const uchar *pSrc = (const uchar*)mat.data;        // Create QImage with same dimensions as input Mat        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);        return image.rgbSwapped();    }    else if(mat.type() == CV_8UC4)    {        qDebug() << "CV_8UC4";        // Copy input Mat        const uchar *pSrc = (const uchar*)mat.data;        // Create QImage with same dimensions as input Mat        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);        return image.copy();    }    else    {        qDebug() << "ERROR: Mat could not be converted to QImage.";        return QImage();    }}

以上就是关于"怎么用QT+OpenCV实现录屏功能"这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注行业资讯频道。

0