目录

1.imshow()

imshow()函数用于将imread()函数读取的cv::Mat进行显示和播放,是OpenCV中的另一个核心函数。我的平台是windows10,这里分析的是window.cpp中的cv::imshow()函数

void cv::imshow( const String& winname, InputArray _img )
{
    CV_TRACE_FUNCTION();

    const Size size = _img.size();
    CV_Assert(size.width>0 && size.height>0);
    {
    	// 获取窗口锁
        cv::AutoLock lock(cv::getWindowMutex());
        // 清理已经关闭的窗口
        cleanupClosedWindows_();
        auto& windowsMap = getWindowsMap();
        auto i = windowsMap.find(winname);
        if (i != windowsMap.end()) // 找到窗口
        {
            auto ui_base = i->second;
            if (ui_base)
            {
                auto window = std::dynamic_pointer_cast<UIWindow>(ui_base);
                if (!window)
                {
                    CV_LOG_ERROR(NULL, "OpenCV/UI: invalid window name: '" << winname << "'");
                }
                // 输出图像
                return window->imshow(_img);
            }
        }
        /* 没有找到窗口,新建窗口后再输出图像 */
        auto backend = getCurrentUIBackend(); // 创建界面后端的智能指针static std::shared_ptr<UIBackend> 
        if (backend)
        {
        	// 根据windows名称创建一个window,尺寸为AUTO_SIZE(自适应大小)
            auto window = backend->createWindow(winname, WINDOW_AUTOSIZE);
            if (!window)
            {
                CV_LOG_ERROR(NULL, "OpenCV/UI: Can't create window: '" << winname << "'");
                return;
            }
            // 在windowsMap中插入新建的window
            windowsMap.emplace(winname, window);
            // 
            return window->imshow(_img);
        }
    }

	// ...
}

window->imshow()函数调用的是window_w32.cpp中的imshow()函数

void imshow(InputArray image) CV_OVERRIDE
{
    auto window_ptr = window_.lock();
    CV_Assert(window_ptr);
    CvWindow& window = *window_ptr;
    Mat image_mat = image.getMat();
    showImage_(window, image_mat);
}

showImage_()函数

static void showImage_(CvWindow& window, const Mat& image)
{
    AutoLock lock(window.mutex);

    SIZE size = { 0, 0 };
    int channels = 0;
    void* dst_ptr = 0;
    const int channels0 = 3;
    bool changed_size = false; // philipg

    if (window.image)
    {
        // if there is something wrong with these system calls, we cannot display image...
        if (!icvGetBitmapData(window, size, channels, dst_ptr))
            return;
    }

    if (size.cx != image.cols || size.cy != image.rows || channels != channels0)
    {
        changed_size = true;

        uchar buffer[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)];
        BITMAPINFO* binfo = (BITMAPINFO*)buffer;
		// 删除旧图像资源
        DeleteObject(SelectObject(window.dc, window.image));
        window.image = 0;

        size.cx = image.cols;
        size.cy = image.rows;
        channels = channels0;

        FillBitmapInfo(binfo, size.cx, size.cy, channels*8, 1);
		// 创建新的图像资源,DBI = Device Independent Bitmap
        window.image = SelectObject(window.dc,
                CreateDIBSection(window.dc, binfo, DIB_RGB_COLORS, &dst_ptr, 0, 0)
            );
    }
    
    {
    	// 将图像数据拷贝到DIB内存中
        cv::Mat dst(size.cy, size.cx, CV_8UC3, dst_ptr, (size.cx * channels + 3) & -4);
        // 将输入图像image转换为目标格式(通常是BGR->RGB或GRAY->RGB)
        convertToShow(image, dst, false);
        CV_Assert(dst.data == (uchar*)dst_ptr);
        // 垂直翻转图像,因为 GDI 的坐标系是 Y 轴向下,而 OpenCV 默认是 Y 轴向上;
		// 这样做的目的是让图像显示方向正确,不会倒置
        cv::flip(dst, dst, 0);
    }

    // only resize window if needed
    // 如果图像尺寸变化了,调用 icvUpdateWindowPos() 更新窗口大小,只进行窗口管理
    if (changed_size)
        icvUpdateWindowPos(window);
    /*  标记整个窗口区域为“无效”,强制下一次消息循环时触发重绘,
    	当窗口的消息循环接收到这个无效区域的通知后,它会在适当的时候生成并处理WM_PAINT消息,
    	WM_PAINT消息发送到指定的窗口(通过window.hwnd指定),从而间接导致窗口内容的更新
    */
    InvalidateRect(window.hwnd, 0, 0);
    // philipg: this is not needed and just slows things down
    //    UpdateWindow(window->hwnd);
}
Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐