2

我正在尝试编写一个程序,将 4 个视频组合成一个视频,将它们排列成 2x2 网格。下面是相关代码:

void CombineVideoApp::on_GoButton_clicked()
{
    std::string Video1Name = Video1Path.toUtf8().constData();
    std::string Video2Name = Video2Path.toUtf8().constData();
    std::string Video3Name = Video3Path.toUtf8().constData();
    std::string Video4Name = Video4Path.toUtf8().constData();

    int VideoWidth = 640;
    int VideoHeight = 360;

    cv::Mat Video1Frame, Video2Frame, Video3Frame, Video4Frame; // Creating Mat objects to store the captured frames
    cv::Mat Video1Shrunk, Video2Shrunk, Video3Shrunk, Video4Shrunk; //Creating Mat objects to store the shrunk frames
    cv::Mat FullCombinedVideo(VideoWidth,VideoHeight, Video1Shrunk.type()); //Creating Mat object to store the combined video
    cv::Mat CombinedVideoTop(VideoWidth, VideoHeight/2, Video1Shrunk.type());
    cv::Mat CombinedVideoBottom(VideoWidth, VideoHeight/2, Video1Shrunk.type());


    cv::VideoCapture Video1(Video1Name);
    cv::VideoCapture Video2(Video2Name);
    cv::VideoCapture Video3(Video3Name);
    cv::VideoCapture Video4(Video4Name);



    double Video1FrameCount = Video1.get(CV_CAP_PROP_FRAME_COUNT);
    double Video2FrameCount = Video2.get(CV_CAP_PROP_FRAME_COUNT);
    double Video3FrameCount = Video3.get(CV_CAP_PROP_FRAME_COUNT);
    double Video4FrameCount = Video4.get(CV_CAP_PROP_FRAME_COUNT);

    double CombinedFrameTopCount = min(Video1FrameCount, Video2FrameCount);
    double CombinedFrameBottomCount = min(Video3FrameCount, Video4FrameCount);
    double CombinedFrameCount = min(CombinedFrameBottomCount, CombinedFrameTopCount);

    Video1.set(CV_CAP_PROP_FRAME_COUNT, CombinedFrameCount);
    Video2.set(CV_CAP_PROP_FRAME_COUNT, CombinedFrameCount);
    Video3.set(CV_CAP_PROP_FRAME_COUNT, CombinedFrameCount);
    Video4.set(CV_CAP_PROP_FRAME_COUNT, CombinedFrameCount);


    for(;;)
    {
        Video1 >> Video1Frame;
        Video2 >> Video2Frame;
        Video3 >> Video3Frame;
        Video4 >> Video4Frame;

        cv::resize(Video1Frame, Video1Shrunk, Size((VideoWidth/2), (VideoHeight/2)));
        cv::resize(Video2Frame, Video2Shrunk, Size((VideoWidth/2), (VideoHeight/2)));
        cv::resize(Video3Frame, Video3Shrunk, Size((VideoWidth/2), (VideoHeight/2)));
        cv::resize(Video4Frame, Video4Shrunk, Size((VideoWidth/2), (VideoHeight/2)));

        Video1Shrunk.copyTo(CombinedVideoTop(Rect(0,0,Video1Shrunk.cols,Video1Shrunk.rows)));
        Video2Shrunk.copyTo(CombinedVideoTop(Rect(Video1Shrunk.cols,0,Video2Shrunk.cols,Video2Shrunk.rows)));
        Video3Shrunk.copyTo(CombinedVideoBottom(Rect(0,0,Video3Shrunk.cols,Video3Shrunk.rows)));
        Video4Shrunk.copyTo(CombinedVideoBottom(Rect(Video3Shrunk.cols,0,Video4Shrunk.cols,Video4Shrunk.rows)));

        CombinedVideoTop.copyTo(FullCombinedVideo(Rect(0,0,CombinedVideoTop.cols, CombinedVideoTop.rows)));
        CombinedVideoBottom.copyTo(FullCombinedVideo(Rect(0,CombinedVideoTop.rows, CombinedVideoBottom.cols,CombinedVideoBottom.rows)));


        std::string FinalFilePath = CombinedVideo.toUtf8().constData();
        cv::VideoWriter CombinedWriter(FinalFilePath, CV_FOURCC('D', 'I', 'V', 'X'),10,cvSize(FullCombinedVideo.cols, FullCombinedVideo.rows));

        CombinedWriter << FullCombinedVideo;

    }


}

该程序编译没有问题,但是当我实际尝试运行它时,我收到以下错误:

OpenCV Error: Assertion failed (0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows) in Mat, file /tmp/OpenCV-2.4.3/modules/core/src/matrix.cpp, line 322
Qt has caught an exception thrown from an event handler. Throwing
exceptions from an event handler is not supported in Qt. You must
reimplement QApplication::notify() and catch all exceptions there.

The program has unexpectedly finished.

谁能告诉我这里有什么问题?我完全被难住了。我试图打开的视频文件是 .avi 格式,我使用的是 QtCreator、OpenCV 2.4.3,并在 OSX Snow Leopard 上运行它。

谢谢

4

3 回答 3

2

将帧写入视频文件很容易,这里有几个示例

棘手的部分是将 4 个帧组装成一个,因此以下代码演示了如何做到这一点,并且考虑到所有帧都可以具有任意大小:

// Load 4 images from the disk
cv::Mat img1 = cv::imread("test1.jpg");
cv::Mat img2 = cv::imread("test2.jpg");
cv::Mat img3 = cv::imread("test3.jpg");
cv::Mat img4 = cv::imread("test4.jpg");

// Make sure they have been loaded successfully
if (img1.empty() || img2.empty() || img3.empty() || img4.empty())
{
    std::cout << "!!! Failed to load one of the images\n";
    return -1;
}

/* Make sure they are compatible: same type, depth and # channels */

if ( (img1.type() != img2.type()) ||
     (img3.type() != img4.type()) ||
     (img1.type() != img4.type()) )
{
    std::cout << "!!! The depth doesn't match!\n";
    return -1;
}

if ( (img1.depth() != img2.depth()) ||
     (img3.depth() != img4.depth()) ||
     (img1.depth() != img4.depth()) )
{
    std::cout << "!!! The depth doesn't match!\n";
    return -1;
}

if ( (img1.channels() != img2.channels()) ||
     (img3.channels() != img4.channels()) ||
     (img1.channels() != img4.channels()) )
{
    std::cout << "!!! Number of channels doesn't match!\n";
    return -1;
}

// Create the destination image based on the size of the loaded images
//  _________
// |    |    |
// |_1__|_2__|
// |    |    |
// |_3__|_4__|

/* As the input images might have different sizes, we need to make sure
 * to create an output image that is big enough to store all of them.
 */

// Compute the width of the output image
int row1_size = img1.size().width + img2.size().width;
int row2_size = img3.size().width + img4.size().width;
int new_width = std::max(row1_size, row2_size);

// Compute the height of the output image
int col1_size = img1.size().height + img3.size().height;
int col2_size = img2.size().height + img4.size().height;
int new_height = std::max(col1_size, col2_size);

// Create the destination image
cv::Mat dst_img(cv::Size(new_width, new_height), img1.type(), cv::Scalar(0, 0, 0));
std::cout << "dst: size " << dst_img.size().width << "x" << dst_img.size().height << std::endl;

/* Copy the pixels of the input images to the destination */

//  _________
// |    |    |
// |_1__|    |
// |         |
// |_________|
img1.copyTo(dst_img(cv::Rect(0, 0, img1.cols, img1.rows))); 

//  _________
// |    |    |
// |_1__|_2__|
// |         |
// |_________|    
img2.copyTo(dst_img(cv::Rect(img1.size().width, 0, img2.cols, img2.rows)));

//  _________
// |    |    |
// |_1__|_2__|
// |    |    |
// |_3__|____|    
img3.copyTo(dst_img(cv::Rect(0, 
                             std::max(img1.size().height, img2.size().height), 
                             img3.cols, 
                             img3.rows)));

//  _________
// |    |    |
// |_1__|_2__|
// |    |    |
// |_3__|_4__|    
img4.copyTo(dst_img(cv::Rect(img3.size().width, 
                             std::max(img1.size().height, img2.size().height), 
                             img4.cols, 
                             img4.rows)));

// For testing purposes, display it on the screen
cv::imshow("Test", dst_img);
cv::waitKey(0);

这些是用于测试的图像尺寸:64x64、128x128、256x256 和 320x320

结果

在此处输入图像描述

于 2013-02-04T01:06:36.570 回答
0

使用 ffmpeg(或 libav),它是完成此任务的合适工具,而且执行速度更快。

请参阅: FFMPEG 2 视频在 1 帧中并排转码?

于 2013-02-03T22:50:54.573 回答
0

正如 opencv 所说,您的 ROI(感兴趣区域)错误。

可能您有一个错误,因此您有一个从 -1 开始或超出宽度/高度结​​束的区域。

要么在调试器中检查这些,要么打印坐标并查看哪个是错误的。

于 2013-02-03T23:00:52.947 回答