【OpenCV】imshow函数的简单分析
imshow()函数是OpenCV中用于显示图像的核心函数,本文详细分析了其在Windows平台下的实现过程。首先,imshow()函数会检查窗口是否存在,若存在则直接显示图像;若不存在,则创建新窗口并显示图像。接着,函数通过showImage_()处理图像数据,包括图像格式转换、垂直翻转等操作,以确保图像显示方向正确。最后,函数通过InvalidateRect()标记窗口区域为“无效”,强制窗口
·
目录
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);
}
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)