首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用opencv从帧创建divx编码的avi

使用opencv从帧创建divx编码的avi
EN

Stack Overflow用户
提问于 2016-11-16 03:42:00
回答 2查看 921关注 0票数 1

这个问题类似于this one尤其是this one但是我想要的输出是不同的。我正在尝试使用opencv捕获桌面到视频。首选输出是采用divx编码的avi文件。我是opencv和位图编程的新手。

作为第一步,为了确保divx编解码器存在,我创建了一个纯色(黄色)的单帧(cv::Mat),并将其写入视频文件100次,如下所示:

代码语言:javascript
复制
int main(int argc, char* argv[])
{
   cv::Mat frame(1200, 1920, CV_8UC3, cv::Scalar(0, 50000, 50000));

   cv::VideoWriter* videoWriter = new cv::VideoWriter(
                "C:/videos/desktop.avi", 
                 CV_FOURCC('D','I','V','3'), 
                 5, cv::Size(1920, 1200), true);

   int frameCount = 0;

   while (frameCount < 100)
   {
      videoWriter->write(frame);
      ::Sleep(100);
      frameCount++;
    }

    delete videoWriter;
    return 0;
}

这是完美的工作-视频文件被创建,并可以在我的Win 10机器上使用VLC,Windows Media Player或Films&TV应用程序播放。它是100帧稳定的黄色,但它表明视频的创建是正确的。

下一步:用桌面的一系列截图替换上面代码中的虚拟cv::Mat框架。我使用以下命令获得桌面窗口的句柄GetDesktopWindow()(https://msdn.microsoft.com/en-us/library/windows/desktop/ms633504(v=vs.85%29.aspx),然后使用函数hwnd2mat (取自this所以问题--谢谢!)将从桌面句柄获得的位图转换为可以写入视频的cv::Mat。

我逐字复制了hwnd2mat函数,只是没有缩放图像-桌面位图已经是1920x1200,而且我创建的cv::Mat也是CV_8UC3而不是CV_

8UC4 (CV_8UC4导致我的应用程序崩溃)。

以下是代码,包括重印的hwnd2mat:

代码语言:javascript
复制
int main(int argc, char* argv[])
{
   cv::VideoWriter* videoWriter = new cv::VideoWriter(
                "C:/videos/desktop.avi", 
                 CV_FOURCC('D','I','V','3'), 
                 5, Size(1920, 1200), true);

   int frameCount = 0;

   while (frameCount < 100)
   {
      HWND hDsktopWindow = ::GetDesktopWindow();
      cv::Mat frame = hwnd2mat(hDsktopWindow);
      videoWriter->write(frame);
      ::Sleep(100);
      frameCount++;
   }

   delete videoWriter;
   return 0;
}

cv::Mat hwnd2mat(HWND hwnd)
{
   HDC hwindowDC, hwindowCompatibleDC;
   int height, width, srcheight, srcwidth;
   HBITMAP hbwindow;

   cv::Mat src;
   BITMAPINFOHEADER  bi;

   hwindowDC = GetDC(hwnd);
   hwindowCompatibleDC = CreateCompatibleDC(hwindowDC);

   SetStretchBltMode(hwindowCompatibleDC, COLORONCOLOR);

   RECT windowsize;    // get the height and width of the screen
   GetClientRect(hwnd, &windowsize);
   srcheight = windowsize.bottom;
   srcwidth = windowsize.right;
   height = windowsize.bottom / 1;  //change this to whatever size you want to resize to
   width = windowsize.right / 1;

   src.create(height, width, CV_8UC3);

   // create a bitmap
   hbwindow = CreateCompatibleBitmap(hwindowDC, width, height);
   bi.biSize = sizeof(BITMAPINFOHEADER);   
   bi.biWidth = width;
   bi.biHeight = -height;  //this is the line that makes it draw upside down or not
   bi.biPlanes = 1;
   bi.biBitCount = 32; 
   bi.biCompression = BI_RGB;
   bi.biSizeImage = 0;
   bi.biXPelsPerMeter = 0;
   bi.biYPelsPerMeter = 0;
   bi.biClrUsed = 0;
   bi.biClrImportant = 0;

   // use the previously created device context with the bitmap
   SelectObject(hwindowCompatibleDC, hbwindow);

   // copy from the window device context to the bitmap device context
   StretchBlt(hwindowCompatibleDC, 0, 0, width, height, hwindowDC, 0, 0,srcwidth, srcheight, SRCCOPY); 

   GetDIBits(hwindowCompatibleDC, hbwindow, 0, height, src.data, (BITMAPINFO*)&bi, DIB_RGB_COLORS);

   // avoid memory leak
   DeleteObject(hbwindow); DeleteDC(hwindowCompatibleDC); ReleaseDC(hwnd,hwindowDC);

   return src;
}

这样做的结果是,视频文件被创建并可以无错误地播放,但它只是纯灰色。桌面的位图似乎没有正确复制到cv::Mat框架中。我已经尝试了BITMAPINFOHEADER中无数的值组合,但都不起作用,老实说,我不知道我在做什么。我知道opencv有转换功能,但我甚至不知道我想要转换成什么。

感谢任何帮助!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-11-16 20:24:15

我不知道这是不是最好的方法,所以评论或替代解决方案仍然是受欢迎的。

它看起来像是为了GetDIBits(https://msdn.microsoft.com/en-us/library/windows/desktop/dd144879(v=vs.85%29.aspx)要工作,请使用cv::Mat有为4通道,即CV_8UC4,就像我修改之前的hwnd2mat的原始代码。如果不是CV_8UC4,没有数据被复制(GetDIBits返回0个被复制的扫描线),这就是为什么我的avi是灰色的。因此,第一个更改是将src cv::Mat创建为4通道:

代码语言:javascript
复制
src.create(height, width, CV_8UC4);

但是对于我正在尝试创建的divx编码的avi文件,帧应该是3声道的(不要问我为什么)。在调用GetDIBits()之后,我添加了对opencv转换函数的调用,如下所示:

代码语言:javascript
复制
cv::Mat dst;
dst.create(height, width, CV_8UC3); 
cv::cvtColor(src, dst, CV_RGBA2RGB);

然后我从hwnd2mat返回dst,而不是src。对cvtColor的调用删除了alpha通道(RGBA中的A),并且dst仅以R、G、B通道结束。

票数 1
EN

Stack Overflow用户

发布于 2021-02-26 17:35:09

你可以从GetDIBits获取没有alpha通道的位图,并将其直接写入cv::VideoWriter。只需将biBitCount更改为24即可。将Mat format保留为CV_8IC3。这对我很有效。Src.create(高度、宽度、CV_8UC3);

bi.biBitCount = 24;//这是要更改的位置

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40618340

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档