使用 OpenCV 在同一窗口中显示多个图像

Posted

技术标签:

【中文标题】使用 OpenCV 在同一窗口中显示多个图像【英文标题】:Display multiple image in same window with OpenCV 【发布时间】:2012-06-01 12:38:36 【问题描述】:

我有三个可以通过硬件自动同步的火线摄像机,我正在尝试捕获帧,将它们保存到我的硬盘中并在窗口中显示它们。

一切正常,但目前,我只能同时在三个不同的窗口中显示帧

我想在单个窗口中显示框架,但我不知道该怎么做。 在link 有 cvShowManyImages() 函数,但您必须同时传递三帧,但我有一个 for() 循环,可以一次考虑一帧。

这是我正在使用的代码:

  for ( int j = 0; j < k_numImages; j++ )
    
        // Display the timestamps for all cameras to show that the image
        // capture is synchronized for each image
        for ( unsigned int i = 0; i < numCameras; i++ )
        
            Image image;
            error = ppCameras[i]->RetrieveBuffer( &image );
            if (error != PGRERROR_OK)
            
                PrintError( error );
                return -1;
            
            IplImage* destImage = ConvertImageToOpenCV(&image);
            char titolo[50];
            sprintf(titolo, "titolo%d", i);
            cvShowImage(titolo, destImage);
            waitKey(1);
        
   

它运行良好,但为每个相机创建了不同的窗口,而 我想在同一个窗口中显示所有相机帧

你能帮帮我吗?

编辑:这是 ConvertImageToOpenCV() 函数。

IplImage* ConvertImageToOpenCV(Image* pImage)

    IplImage* cvImage = NULL;
    bool bColor = true;
    CvSize mySize;
    mySize.height = pImage->GetRows();
    mySize.width = pImage->GetCols();

    switch ( pImage->GetPixelFormat() )
    
        case PIXEL_FORMAT_MONO8:     cvImage = cvCreateImageHeader(mySize, 8, 1 );
                                     cvImage->depth = IPL_DEPTH_8U;
                                     cvImage->nChannels = 1;
                                     bColor = false;
                                     break;
        case PIXEL_FORMAT_411YUV8:   cvImage = cvCreateImageHeader(mySize, 8, 3 );
                                     cvImage->depth = IPL_DEPTH_8U;
                                     cvImage->nChannels = 3;
                                     break;
        case PIXEL_FORMAT_422YUV8:   cvImage = cvCreateImageHeader(mySize, 8, 3 );
                                     cvImage->depth = IPL_DEPTH_8U;
                                     cvImage->nChannels = 3;
                                     break;
        case PIXEL_FORMAT_444YUV8:   cvImage = cvCreateImageHeader(mySize, 8, 3 );
                                     cvImage->depth = IPL_DEPTH_8U;
                                     cvImage->nChannels = 3;
                                     break;
        case PIXEL_FORMAT_RGB8:      cvImage = cvCreateImageHeader(mySize, 8, 3 );
                                     cvImage->depth = IPL_DEPTH_8U;
                                     cvImage->nChannels = 3;
                                     break;
        case PIXEL_FORMAT_MONO16:    cvImage = cvCreateImageHeader(mySize, 16, 1 );
                                     cvImage->depth = IPL_DEPTH_16U;
                                     cvImage->nChannels = 1;
                                     bColor = false;
                                     break;
        case PIXEL_FORMAT_RGB16:     cvImage = cvCreateImageHeader(mySize, 16, 3 );
                                     cvImage->depth = IPL_DEPTH_16U;
                                     cvImage->nChannels = 3;
                                     break;
        case PIXEL_FORMAT_S_MONO16:  cvImage = cvCreateImageHeader(mySize, 16, 1 );
                                     cvImage->depth = IPL_DEPTH_16U;
                                     cvImage->nChannels = 1;
                                     bColor = false;
                                     break;
        case PIXEL_FORMAT_S_RGB16:   cvImage = cvCreateImageHeader(mySize, 16, 3 );
                                     cvImage->depth = IPL_DEPTH_16U;
                                     cvImage->nChannels = 3;
                                     break;
        case PIXEL_FORMAT_RAW8:      cvImage = cvCreateImageHeader(mySize, 8, 3 );
                                     cvImage->depth = IPL_DEPTH_8U;
                                     cvImage->nChannels = 3;
                                     break;
        case PIXEL_FORMAT_RAW16:     cvImage = cvCreateImageHeader(mySize, 8, 3 );
                                     cvImage->depth = IPL_DEPTH_8U;
                                     cvImage->nChannels = 3;
                                     break;
        case PIXEL_FORMAT_MONO12:    printf("Not supported by OpenCV");
                                     bColor = false;
                                     break;
        case PIXEL_FORMAT_RAW12:     printf("Not supported by OpenCV");
                                     break;
        case PIXEL_FORMAT_BGR:       cvImage = cvCreateImageHeader(mySize, 8, 3 );
                                     cvImage->depth = IPL_DEPTH_8U;
                                     cvImage->nChannels = 3;
                                     break;
        case PIXEL_FORMAT_BGRU:      cvImage = cvCreateImageHeader(mySize, 8, 4 );
                                     cvImage->depth = IPL_DEPTH_8U;
                                     cvImage->nChannels = 4;
                                     break;
        case PIXEL_FORMAT_RGBU:      cvImage = cvCreateImageHeader(mySize, 8, 4 );
                                     cvImage->depth = IPL_DEPTH_8U;
                                     cvImage->nChannels = 4;
                                     break;
        default: printf("Some error occured...\n");
                 return NULL;
    

    if(bColor) 
        if(!bInitialized)
        
            colorImage.SetData(new unsigned char[pImage->GetCols() * pImage->GetRows()*3], pImage->GetCols() * pImage->GetRows()*3);
            bInitialized = true;
        

        pImage->Convert(PIXEL_FORMAT_BGR, &colorImage); //needs to be as BGR to be saved

        cvImage->width = colorImage.GetCols();
        cvImage->height = colorImage.GetRows();
        cvImage->widthStep = colorImage.GetStride();

        cvImage->origin = 0; //interleaved color channels

        cvImage->imageDataOrigin = (char*)colorImage.GetData(); //DataOrigin and Data same pointer, no ROI
        cvImage->imageData         = (char*)(colorImage.GetData());
        cvImage->widthStep      = colorImage.GetStride();
        cvImage->nSize = sizeof (IplImage);
        cvImage->imageSize = cvImage->height * cvImage->widthStep;
    
    else
    
        cvImage->imageDataOrigin = (char*)(pImage->GetData());
        cvImage->imageData         = (char*)(pImage->GetData());
        cvImage->widthStep         = pImage->GetStride();
        cvImage->nSize             = sizeof (IplImage);
        cvImage->imageSize         = cvImage->height * cvImage->widthStep;

        //at this point cvImage contains a valid IplImage
     
    return cvImage;

【问题讨论】:

【参考方案1】:

由于显而易见的原因,我无法测试下面的代码,但它说明了一种方法:

for ( int j = 0; j < k_numImages; j++ )

    // Display the timestamps for all cameras to show that the image
    // capture is synchronized for each image

    IplImage* destImage[3]; // A-ha moment

    for ( unsigned int i = 0; i < numCameras; i++ )
    
        Image image;
        error = ppCameras[i]->RetrieveBuffer( &image );
        if (error != PGRERROR_OK)
        
            PrintError( error );
            return -1;
        

        /* Since ConvertImageToOpenCV() doesn't copy the image data,
         * we need to do that ourselves, because when this loop is done Image 
         * is destroyed and the data is lost.
         */
        IplImage* tmp = ConvertImageToOpenCV(&image);
        destImage[i] = cvCreateImage(cvGetSize(tmp), tmp->depth, tmp->nChannels);
        cvCopy(tmp, destImage[i], NULL); 

        char titolo[50];
        sprintf(titolo, "titolo%d", i);
    

    cvShowManyImages("all", 3, destImage[0], destImage[1], destImage[2]);
    waitKey(0);

    // when you finish using them, release the allocated resources to prevent memory leaks
    cvReleaseImage(&destImage[0]);
    cvReleaseImage(&destImage[1]);
    cvReleaseImage(&destImage[2]);                 

这个想法是创建一个 IplImage* 数组来存储相机检索到的图像,因此在循环之后您可以访问所有这 3 个图像并能够在单个窗口上显示它们。

编辑:

总结一下私聊,问题是cvShowManyImages() 拍摄彩色(三通道)图像,而他的相机返回的是灰度(单通道)图像。解决方案是简单地更改cvShowManyImages() 的实现,从:

DispImage = cvCreateImage( cvSize(100 + size*w, 60 + size*h), 8, 3 );

收件人:

DispImage = cvCreateImage( cvSize(100 + size*w, 60 + size*h), 8, 1 );

【讨论】:

非常感谢您的提示!我试过了,它编译但是当我运行它时,我得到这个错误:“OpenCV 错误:断言失败 可能是因为 cvShowManyImages() 对图像使用了不同的尺寸?目前,从相机拍摄的图像为 1200x1800 像素 我只是读了代码,你的函数没有复制数据,它只是复制指针,即函数复制数据在内存中的内存地址,而不是数据本身.我更新了我的代码,你最好再看看它。 灰度正常。闪烁效果通过在 cvShowManyImages() 之后调用 cvWaitKey() 来解决:这是我第一次更新答案引起的错误。 非常感谢,卡尔!你太棒了!

以上是关于使用 OpenCV 在同一窗口中显示多个图像的主要内容,如果未能解决你的问题,请参考以下文章

无法同时显示五个 Mat 图像(C++、OpenCV)

c ++ opencv在窗口上显示图像

Opencv - 如何使用与多个线程共享的 imshow() 方法相同的窗口

如何从同一图像中检测多个人脸?

如何清除openCV中的窗口内容

OpenCV读取图像创建窗口显示图像