您好,登錄后才能下訂單哦!
這篇“怎么用QT+OpenCV實(shí)現(xiàn)錄屏功能”文章的知識點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“怎么用QT+OpenCV實(shí)現(xiàn)錄屏功能”文章吧。
QScreen類有一個(gè)grabWindow函數(shù),可以用來獲取窗體的畫面,這個(gè)函數(shù)使用很簡單,就是傳入窗體句柄和要截取的坐標(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位圖的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); //創(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)境 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); // 獲得數(shù)據(jù)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; } /* * 函數(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; else wBitCount = 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; }
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; }
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 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(); } }
以上就是關(guān)于“怎么用QT+OpenCV實(shí)現(xiàn)錄屏功能”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關(guān)的知識內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。