GDB cv :: Mat python对象在调试C++程序时的问题

问题描述:

在调试C++ OpenCV程序时,我想在GDB下的程序中看到一个图像,我的意思是我希望在GDB下可视化数据。幸运的是我有:GDB cv :: Mat python对象在调试C++程序时的问题

  1. GDB with python support;
  2. 我已经安装了python 2.7.4,numpy库和opencv官方发布的2.4.4;
  3. 我已经将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 ['data'])“并不真正做缓冲区地址分配。

的“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的蟒蛇接口(在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 ::垫。 现在,您只需键入:“source cvplot.py”将该脚本加载到GDB,然后键入:“plot img”以显示OpenCV窗口中的cv :: Mat,以让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) 

但是,如果我运行命令“打印IMG “直接在GDB的命令行,它表明:

$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}}} 

我不知道如何解决这个问题,但我肯定可以看到它是有些问题是巨蟒试图将原始缓冲区,以普通文本解码。 (我使用的WinXP)

非常感谢Tromey,Andre_,Pmuldoon他们在GDB IRC样的帮助,也感谢许宁的大力帮助和建议,解决方案还张贴在GDB的maillist Post in GDB maillist,我也愿意喜欢为OpenCV社区做出贡献Visualize in memory OpenCV image or matrix from GDB pretty printers

+1

好的,完整的解决方案被添加,感谢您的建议。 – ollydbg23 2013-12-09 15:14:27

您需要使用inferior.read_memory将调试程序的pixmap内容传输到gdb进程。也许可以查看Qt Creator实现,它具有类似的功能来显示QImage数据。

+1

嗨,jamba,非常感谢,我在GDB IRC上询问了我的问题,他们还建议使用inferior.read_memory函数。事实上,我已经解决了我的问题,但是我的python代码不太好,因为它仍然需要一些代码来确定尺寸和像素内容的凝视地址和大小,如果我解决了所有问题,我会发布它们。 – ollydbg23 2013-04-30 06:27:32