在调试C ++程序OpenCV的,我想看看我的GDB下的程序的图像,我的意思是我想可视化GDB下的数据。 幸运的是我有:
- GDB用Python支持;
- 我已经安装了Python 2.7.4,numpy的库,和OpenCV正式发布2.4.4;
- 我已经安装了Python接口文件“cv2.pyd”我的python的site-packages文件夹中。
现在,我可以运行一个纯Python脚本加载和显示的图像。 但我的问题是当我试图表明从GDB的图像。 (该图像是在我的C ++程序)
#include <opencv/cv.h>
#include <opencv/highgui.h>
using namespace cv;
...
Mat orgImg = imread("1.jpg", CV_LOAD_IMAGE_GRAYSCALE);
然后,我设置一个断点后,再GDB断点处,我在GDB的命令行运行这样的命令
source test.py
该test.py是一个Python脚本,尽量展现的图像:
import gdb
import cv2
import numpy
class PlotterCommand(gdb.Command):
def __init__(self):
super(PlotterCommand, self).__init__("plot",
gdb.COMMAND_DATA,
gdb.COMPLETE_SYMBOL)
def invoke(self, arg, from_tty):
args = gdb.string_to_argv(arg)
v = gdb.parse_and_eval(args[0])
t = v.type.strip_typedefs()
print t
a = numpy.asarray(v)
cv2.namedWindow('debugger')
cv2.imshow('debugger',a)
cv2.waitKey(0)
PlotterCommand()
在那之后,我只需运行命令
plot orgImg
但是GDB得到一个错误:
cv::Mat
Python Exception <type 'exceptions.TypeError'> mat data type = 17 is not supported:
Error occurred in Python command: mat data type = 17 is not supported
Error occurred in Python command: mat data type = 17 is not supported
你看,GDB下的Python对象是“CV ::垫”,但它无法转换为正确的python对象显现。 任何人都可以帮我吗? 谢谢。
编辑:我尝试创建它们使用CV(未CV2)更简单的脚本,但它仍然无法正常工作:
import gdb
import cv2.cv as cv
class PlotterCommand(gdb.Command):
def __init__(self):
super(PlotterCommand, self).__init__("plot",
gdb.COMMAND_DATA,
gdb.COMPLETE_SYMBOL)
def invoke(self, arg, from_tty):
args = gdb.string_to_argv(arg)
v = gdb.parse_and_eval(args[0])
a = cv.CreateImageHeader((v['cols'],v['rows']), cv.IPL_DEPTH_8U, 1)
cv.SetData(a, v['data'])
cv.NamedWindow('debugger')
cv.ShowImage('debugger', a)
cv.WaitKey(0)
PlotterCommand()
上面的代码不作为语句“cv.SetData(A,V [‘数据’])”并没有真正做一个缓冲区地址分配工作。
在“V”是CV ::垫,其具有内容的表示:
{flags = 1124024320, dims = 2, rows = 44, cols = 37, data = 0x3ef2d0 '\377' <repeats 200 times>..., refcount = 0x3ef92c, datastart = 0x3ef2d0 '\377' <repeats 200 times>..., dataend = 0x3ef92c "\001", datalimit = 0x3ef92c "\001", allocator = 0x0, size = {p = 0x22fe10}, step = {p = 0x22fe38, buf = {37, 1}}}
所以,你看“数据”字段是原始缓冲区指针,但我不知道如何将这个gdb.Value转移到一个Python缓冲区类型。
我现在已经解决了这个问题,这里是剩余一些小问题的解决方案(见下文)
假设你有这样的C ++代码:
#include <opencv/cv.h>
#include <opencv/highgui.h>
using namespace cv;
...
Mat img = imread("1.jpg", CV_LOAD_IMAGE_GRAYSCALE);
...
当GDB调试下的代码,我想看看内存中的数据“IMG”的样子。 由于GDB和OpenCV,它们都有Python接口,所以这里是Python脚本漂亮(我发布的GPLv3下的脚本代码)
在这之前,你需要1,GDB与Python启用2,OpenCV的Python接口(在Windows下,它是一个文件cv2.pyd)3,安装python,numpy的
############################################################
#filename: cvplot.py
import gdb
import cv2.cv as cv
import sys
class PlotterCommand(gdb.Command):
def __init__(self):
super(PlotterCommand, self).__init__("plot",
gdb.COMMAND_DATA,
gdb.COMPLETE_SYMBOL)
def invoke(self, arg, from_tty):
args = gdb.string_to_argv(arg)
# generally, we type "plot someimage" in the GDB commandline
# where "someimage" is an instance of cv::Mat
v = gdb.parse_and_eval(args[0])
# the value v is a gdb.Value object of C++
# code's cv::Mat, we need to translate to
# a python object under cv2.cv
image_size = (v['cols'],v['rows'])
# print v
# these two below lines do not work. I don't know why
# channel = gdb.execute("call "+ args[0] + ".channels()", False, True)
# channel = v.channels();
CV_8U =0
CV_8S =1
CV_16U=2
CV_16S=3
CV_32S=4
CV_32F=5
CV_64F=6
CV_USRTYPE1=7
CV_CN_MAX = 512
CV_CN_SHIFT = 3
CV_MAT_CN_MASK = (CV_CN_MAX - 1) << CV_CN_SHIFT
flags = v['flags']
channel = (((flags) & CV_MAT_CN_MASK) >> CV_CN_SHIFT) + 1
CV_DEPTH_MAX = (1 << CV_CN_SHIFT)
CV_MAT_DEPTH_MASK = CV_DEPTH_MAX - 1
depth = (flags) & CV_MAT_DEPTH_MASK
IPL_DEPTH_SIGN = 0x80000000
cv_elem_size = (((4<<28)|0x8442211) >> depth*4) & 15
if (depth == CV_8S or depth == CV_16S or depth == CV_32S):
mask = IPL_DEPTH_SIGN
else:
mask = 0
ipl_depth = cv_elem_size*8 | mask
img = cv.CreateImageHeader(image_size, ipl_depth, channel)
# conver the v['data'] type to "char*" type
char_type = gdb.lookup_type("char")
char_pointer_type =char_type.pointer()
buffer = v['data'].cast(char_pointer_type)
# read bytes from inferior's memory, because
# we run the opencv-python module in GDB's own process
# otherwise, we use memory corss processes
buf = v['step']['buf']
bytes = buf[0] * v['rows'] # buf[0] is the step? Not quite sure.
inferior = gdb.selected_inferior()
mem = inferior.read_memory(buffer, bytes)
# set the img's raw data
cv.SetData(img, mem)
# create a window, and show the image
cv.NamedWindow('debugger')
cv.ShowImage('debugger', img)
# the below statement is necessory, otherwise, the Window
# will hang
cv.WaitKey(0)
PlotterCommand()
############################################################
上面的脚本添加一个新的GDB命令“暗算”,显示内存中的数据CV ::垫。 现在,你可以简单地输入:“源cvplot.py”这个脚本加载到GDB,然后键入:“暗算IMG”,显示CV ::垫在OpenCV中的窗口,让GDB继续,只是关闭调试窗口。
BTW:我发现了一个问题,如果我在脚本源取消注释“#打印V”,那么这个脚本会抱怨这样的消息并中止:
Python Exception <type 'exceptions.UnicodeEncodeError'> 'ascii' codec can't encode characters in position 80-100: ordinal not in range(128):
Error occurred in Python command: 'ascii' codec can't encode characters in position 80-100: ordinal not in range(128)
但是,如果我运行命令直接在GDB的命令行“打印IMG”,它显示:
$2 = {flags = 1124024320, dims = 2, rows = 243, cols = 322, data = 0xb85020 "\370\362èèé?èè?èé?è?è?èèèèèèè\372\357èèèèèèèèèèèèèèè?è?èèèè???èè?èéèèè?èè??èèèéèééèèèèèèèèèèèèèèèè?è?èèèèèèè?èèè?è"..., refcount = 0xb981c8, datastart = 0xb85020 "\370\362èèé?èè?èé?è?è?èèèèèèè\372\357èèèèèèèèèèèèèèè?è?èèèè???èè?èéèèè?èè??èèèéèééèèèèèèèèèèèèèèèè?è?èèèèèèè?èèè?è"..., dataend = 0xb981c6 "\255\272\001", datalimit = 0xb981c6 "\255\272\001", allocator = 0x0, size = {p = 0x22fe64}, step = {p = 0x22fe8c, buf = {322, 1}}}
我不知道如何解决这个问题,但我肯定可以看到它是有些问题了Python尝试将原始缓冲区正常的文本解码。 (我使用的WinXP)
非常感谢Tromey,Andre_,Pmuldoon他们在GDB IRC样的帮助,也感谢许宁的大力帮助和建议,解决方案还张贴在GDB的maillist 在GDB的maillist后 ,我也想贡献这OpenCV的社区可视化在存储器的OpenCV图像或矩阵从GDB漂亮打印机
您需要inferior.read_memory至像素图的内容从被调试程序转移到gdb的过程。 也许看看它有类似的功能,以显示数据QImage的Qt Creator的实现。