怎么用QT+OpenCV实现录屏功能
发表于:2025-01-19 作者:千家信息网编辑
千家信息网最后更新 2025年01月19日,这篇"怎么用QT+OpenCV实现录屏功能"文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这
千家信息网最后更新 2025年01月19日怎么用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实现录屏功能"这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注行业资讯频道。
位图
窗体
内容
文件
内存
函数
设备
调色板
功能
像素
大小
字节
环境
画面
结构
句柄
界面
信息
坐标
就是
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
富国全球科技互联网
语音对讲软件开发收费情况
网络安全检测技术要求
量子传输网络技术
作物模型数据库组建
咸阳软件开发怎么样
数据库优化有哪些
数据库碎片化技术
四川中小学生道德与网络安全
物联网上位机软件开发
医学类软件开发企业
软件开发要不要读研
数据库在表前加序列号
盘古网络技术公司老总
响当当网络技术
宝塔面板修改数据库名
我的世界神盾局服务器大战
华为服务器装甲骨文
校园网络安全情景剧剧本
php 存储代码到数据库
演示软件开发用什么软件
夏梦服务器
学校网络安全应急演练脚本
硬件开发需要了解软件开发
数据库加密的分类
国家统计局编制数据库
邮件服务器访问不到端口
win10怎么确定网络安全
电脑pvp在哪个服务器
昆明狗狗数据库