c/c++语言开发共享QT+OpenCV实现录屏功能

本文使用qt+opencv来实现对指定窗体画面录制,并保存为avi文件。(1)获取窗体界面qscreen类有一个grabwindow函数,可以用来获取窗体的画面,这个函数使用很简单,就是传入窗体句柄和

c/c++开发分享QT+OpenCV实现录屏功能使用qt+opencv来实现对指定窗体画面录制,并保存为avi文件。

(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<<wbitcount)*sizeof(rgbquad);        //设置位图信息头结构      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;      //为位图内容分配内存      hdib  = globalalloc(ghnd,dwbmbitssize+dwpalettesize+sizeof(bitmapinfoheader));      lpbi = (lpbitmapinfoheader)globallock(hdib);      *lpbi = bi;      // 处理调色板      hpal = getstockobject(default_palette);      if (hpal)      {          hdc = ::getdc(null);          holdpal=selectpalette(hdc,(hpalette)hpal,false);          realizepalette(hdc);      }      // 获取该调色板下新的像素值      getdibits(hdc,hbitmap,0,(uint)bitmap.bmheight,(lpstr)lpbi+sizeof(bitmapinfoheader)+dwpalettesize, (bitmapinfo *)lpbi,dib_rgb_colors);      //恢复调色板      if (holdpal)      {          selectpalette(hdc, holdpal, true);          realizepalette(hdc);          ::releasedc(null, hdc);      }      // 设置位图文件头      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));      // 写入位图文件其余内容      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();      }  }

以上就是c/c++开发分享QT+OpenCV实现录屏功能的全部内容,希望对大家的学习有所帮助,也希望大家多多支持<计算机技术网(www.ctvol.com)!!>。

需要了解更多c/c++开发分享QT+OpenCV实现录屏功能,都可以关注C/C++技术分享栏目—计算机技术网(www.ctvol.com)!

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/c-cdevelopment/1043010.html

(0)
上一篇 2022年1月31日
下一篇 2022年1月31日

精彩推荐