QT+OPENCV实现录屏功能
生活随笔
收集整理的這篇文章主要介紹了
QT+OPENCV实现录屏功能
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
本文使用QT+opencv來實(shí)現(xiàn)對(duì)指定窗體畫面錄制,并保存為avi文件。
(1)獲取窗體界面
QScreen類有一個(gè)grabWindow函數(shù),可以用來獲取窗體的畫面,這個(gè)函數(shù)使用很簡(jiǎn)單,就是傳入窗體句柄和要截取的坐標(biāo)。但是這個(gè)函數(shù)有一個(gè)缺陷,它是通過截取桌面畫面的方式,而不是通過
窗體獲取界面,所以當(dāng)你的窗體被其他窗體遮擋時(shí),就無法截取完整的窗體界面,如果你是要錄制整個(gè)桌面畫面,那用這個(gè)函數(shù)就可以了,下面的方法調(diào)用GDI函數(shù)來實(shí)現(xiàn),即使窗體被遮擋時(shí)仍然能夠獲取到完整界面,但是窗體最小化時(shí)也一樣無法獲取。
/* * 函數(shù)功能:獲取窗體指定窗體圖像 * 參 數(shù):hd:窗體句柄 * pm:保存獲取到的圖片 * x:截取的起始x坐標(biāo), * y:截取的起始y坐標(biāo), * 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; //內(nèi)存緩沖設(shè)備環(huán)境HBITMAP hbmMem,hbmOld; //內(nèi)存緩沖設(shè)備環(huán)境中的位圖 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位圖的BITMAPINFOBITMAPINFO *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); //創(chuàng)建內(nèi)存兼容設(shè)備環(huán)境//創(chuàng)建內(nèi)存兼容位圖hbmMem=CreateCompatibleBitmap(hDC,pInfo_Header->biWidth,pInfo_Header->biHeight);hbmOld=(HBITMAP)SelectObject(hMemDC,hbmMem);//將內(nèi)存設(shè)備環(huán)境中的內(nèi)容繪制到物理設(shè)備環(huán)境 hDCBitBlt(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);// 獲得數(shù)據(jù)bufDWORD 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; } /* * 函數(shù)功能:將bitmap轉(zhuǎn)為QPixmap */ bool BitmapToPixmap(HBITMAP hBitmap, QPixmap &pm) {HDC hDC;//設(shè)備描述表int iBits;//當(dāng)前顯示分辨率下每個(gè)像素所占字節(jié)數(shù) WORD wBitCount;//位圖中每個(gè)像素所占字節(jié)數(shù)//定義調(diào)色板大小, 位圖中像素字節(jié)大小 , 位圖文件大小 , 寫入文件字節(jié)數(shù)DWORD dwPaletteSize=0,dwBmBitsSize,dwDIBSize;BITMAP Bitmap;//位圖屬性結(jié)構(gòu) BITMAPFILEHEADER bmfHdr;//位圖文件頭結(jié)構(gòu) BITMAPINFOHEADER bi;//位圖信息頭結(jié)構(gòu) LPBITMAPINFOHEADER lpbi;//指向位圖信息頭結(jié)構(gòu) HANDLE hDib, hPal;HPALETTE hOldPal=NULL;//定義文件,分配內(nèi)存句柄,調(diào)色板句柄//計(jì)算位圖文件每個(gè)像素所占字節(jié)數(shù)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;elsewBitCount = 24;//計(jì)算調(diào)色板大小if (wBitCount <= 8)dwPaletteSize=(1<<wBitCount)*sizeof(RGBQUAD);//設(shè)置位圖信息頭結(jié)構(gòu)GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap);bi.biSize = sizeof(BITMAPINFOHEADER);bi.biWidth = Bitmap.bmWidth;bi.biHeight = Bitmap.bmHeight;bi.biPlanes = 1;bi.biBitCount = wBitCount;bi.biCompression = BI_RGB;bi.biSizeImage = 0;bi.biXPelsPerMeter = 0;bi.biYPelsPerMeter = 0;bi.biClrUsed = 0;bi.biClrImportant = 0;dwBmBitsSize = ((Bitmap.bmWidth*wBitCount+31)/32)*4*Bitmap.bmHeight;//為位圖內(nèi)容分配內(nèi)存hDib = GlobalAlloc(GHND,dwBmBitsSize+dwPaletteSize+sizeof(BITMAPINFOHEADER));lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);*lpbi = bi;// 處理調(diào)色板hPal = GetStockObject(DEFAULT_PALETTE);if (hPal){hDC = ::GetDC(NULL);hOldPal=SelectPalette(hDC,(HPALETTE)hPal,FALSE);RealizePalette(hDC);}// 獲取該調(diào)色板下新的像素值GetDIBits(hDC,hBitmap,0,(UINT)Bitmap.bmHeight,(LPSTR)lpbi+sizeof(BITMAPINFOHEADER)+dwPaletteSize, (BITMAPINFO *)lpbi,DIB_RGB_COLORS);//恢復(fù)調(diào)色板if (hOldPal){SelectPalette(hDC, hOldPal, TRUE);RealizePalette(hDC);::ReleaseDC(NULL, hDC);}// 設(shè)置位圖文件頭bmfHdr.bfType = 0x4D42; // "BM"dwDIBSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+dwPaletteSize+dwBmBitsSize;bmfHdr.bfSize = dwDIBSize;bmfHdr.bfReserved1 = 0;bmfHdr.bfReserved2 = 0;bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER)+(DWORD)sizeof(BITMAPINFOHEADER)+dwPaletteSize;std::vector<uchar>buffer;uchar *p=(uchar*)&bmfHdr;// 寫入位圖文件頭buffer.insert(buffer.end(),p,p+sizeof(BITMAPFILEHEADER));// 寫入位圖文件其余內(nèi)容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)){//轉(zhuǎn)成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 Matuchar *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 = 3else if(mat.type() == CV_8UC3){// Copy input Matconst 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 Matconst 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();} }?
轉(zhuǎn)載于:https://www.cnblogs.com/WushiShengFei/p/11202250.html
總結(jié)
以上是生活随笔為你收集整理的QT+OPENCV实现录屏功能的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CSS三栏布局
- 下一篇: Luogu2791 幼儿园篮球题【斯特林