开发调试工具ImageWatch-查看内存中的图像

  1. 开发调试工具ImageWatch
    1. ImageWatch简介
    2. 给VisualStudio安装ImageWatch插件
    3. 调试模式下打开显示ImageWatch窗口
    4. 查看内存中的图像
    5. 其他基本功能
    6. 协议
    7. 后记

开发调试工具ImageWatch

最近工作中在做离屏渲染相关的内容,将渲染结果保存在内存中,然后通过网络传输到远端设备上。离屏渲染通过ReadPixels的方式将渲染的结果直接扔到了内存中,不会创建窗口和在窗口上绘制出来。在调试过程中发现远端设备显示的图像不正确,需要定位问题。由于懒得引入UI及编写代码来创建窗口,想起大学时做图像识别时使用过的调试工具ImageWatch,用它我们可以直接调试内存中的图像。

ImageWatch简介

ImageWatch是一个VisualStudio插件,能够让我们在调试一个OpenCV程序时,直观地看到内存中的图像,并能直接在调试界面中做一系列的图像操作。

ImageWatch最开始是用于OpenCV的,但是如果它只做成支持OpenCV的形式,我们也不会选它了。ImageWatch是支持扩展的,我们可以编写配置让它支持自定义类型的内存形式。帮助文档的EXTENSIBILITY章节的内容详细描述了自定义的使用方法。

当然,如果只是简单地用来调试调试内存中的图像,不打算拓展它,我们也不需要专门写一套配置文件。

所有ImageWatch能做的,可以参考它的官方帮助文档: https://imagewatch.azurewebsites.net/ImageWatchHelp/ImageWatchHelp.htm

给VisualStudio安装ImageWatch插件

联网状态直接下载(推荐,自动匹配VS版本): VisualStudio菜单 -> 扩展 -> 管理扩展 -> 联机 -> 在右上角的搜索栏中直接搜索Image Watch,下载即可。

脱机下载:
老版本:https://marketplace.visualstudio.com/items?itemName=VisualCPPTeam.ImageWatch
VS2017:https://marketplace.visualstudio.com/items?itemName=VisualCPPTeam.ImageWatch2017
VS2019:https://marketplace.visualstudio.com/items?itemName=VisualCPPTeam.ImageWatch2019
下载后双击安装即可。

调试模式下打开显示ImageWatch窗口

进入程序调试后,ImageWatch的窗口不会自动打开(不用时我们也可以关闭这个窗口)。

通过:VisualStudio菜单 -> 视图 -> 其他窗口 -> Image Watch,即可显示ImageWatch窗口。

查看内存中的图像

ReadPixels拿出来的是裸内存的渲染结果图,是一段图像的内存,是没有图像的宽度高度、图像类型等等属性数据的,直接拿着这样一块内存给ImageWatch是没法显示的(废话,给谁都显示不了)。

我们先来看看ImageWatch针对裸内存图像数据的操作指令:

  • @mem(address, type, channels, width, height, stride)

address:图像内存地址,一般是个指针。 type:像素数据类型,如果是一张颜色图一般会是UINT8,如果是一张深度图一般会是FLOAT16。 channels:通道个数,如果是一张带透明的颜色图一般是4,如果是一张深度图一般是1。 width:图像宽度,像素。 height:图像高度,像素。 stride:图像中一行像素的内存长度,针对一些没有对齐好的像素宽度,内存中有可能会存在Padding数据用来做对齐,我们在读取完一行的像素后,要跳过这些Padding数据才能读取下一行。stride的值一般为width*channels+padding。

现在,假设我们准备就绪,有以下的这些伪代码:

1
2
3
4
5
6
7
8
9
10
11
// Framebuffer size
uint32_t fbWidth = 640;
uint32_t fbHeight = 480;
...
uint8_t* raw = new uint8_t[fbWidth * fbHeight];
...
while (!exit) {
...
raw = ReadPixels(...);
...
}

假设我们ReadPixels取出的是最终渲染的Color Attachment上的图像数据,数据类型是RGBA,那么我们在ImageWatch窗口里的监视模式下(选中Watch),输入下面的操作指令:

  • @mem(raw, UINT8, 4, fbWidth, fbHeight, fbWidth*4)

就能在右侧的显示中看到我们内存中的图像数据了,放大到最大还可以看到每个像素上的RGBA值。

其他基本功能

@mem操作的结果可以认为是一张能被ImageWatch正确识别的图像类型,我们可以把@mem的输出结果作为其他操作的输入。

ImageWatch还支持的一些基本操作有:

  • **@band(img, number)**提取输入图像中第number通道的图像。
  • **@thresh(img, threshold)**对输入图像做二值化处理,大于阈值的将像素赋值为1,小于阈值的将像素赋值为0。
  • **@clamp(img, min, max)**用给定的最小值和最大值对输入图像做截断。
  • **@abs(img)**将输入图像中的像素取绝对值。
  • **@scale(img, factor)**将输入图像中的所有像素的像素值乘以factor。
  • **@norm8(img)@norm16(img)**将输入图像的像素值乘以1/255、1/65535。
  • **@fliph(img)@flipv(img)@flipd(img)**将输入图像沿水平、垂直、对角线方向进行翻转。
  • **@rot90(img)@rot180(img)@rot270(img)**将输入图像沿顺时针方向旋转90度、180度、270度。
  • **@diff(img0, img1)**输入图像0和1,逐像素执行img0–img1得到输出图像。
  • **@file(path)**从指定路径中加载图片,例如从D盘的temp文件夹下加载test.png:@file(“d:\temp\debug.png”)。

比如,我们想在ImageWatch的窗口里直接对ReadPixels出来的结果做一下水平镜像,我们就可以用下面的操作指令来达到目的:

  • @fliph(@mem(raw, UINT8, 4, fbWidth, fbHeight, fbWidth*4))

协议

本文以上内容遵循CC BY-ND 4.0协议,署名-禁止演绎。

转载请注明出处:https://tis.ac.cn/blog/kongdeyou/imagewatch/
并署名:kongdeyou(https://tis.ac.cn/blog/author/kongdeyou/)

后记

2021年1月24日 周日 阴

还有大约2.5周才到春节

完稿于2021年1月25日13:20

原始链接:https://blog.kdyx.net/blog/kongdeyou/imagewatch/

版权声明: "CC BY-NC-ND 4.0" 署名-不可商用-禁止演绎 转载请注明原文链接及作者信息,侵权必究。

×

喜欢或有帮助?赞赏下作者呗!