简体   繁体   English

调试c ++程序时出现GDB cv :: Mat python对象问题

[英]GDB cv::Mat python object issue when debugging a c++ program

When debugging a C++ OpenCV program, I'd like to see an image in my program under GDB, I mean I would like to visualize the data under GDB. 在调试C ++ OpenCV程序时,我想在我的程序中看到GDB下的图像,我的意思是我想在GDB下可视化数据。 Luckily I have: 幸运的是我有:

  1. GDB with python support; 支持python的GDB;
  2. I have installed python 2.7.4, numpy library, and opencv official release 2.4.4; 我已经安装了python 2.7.4,numpy库和opencv官方发行版2.4.4;
  3. I have installed the python interface file "cv2.pyd" to my python's site-packages folder. 我已经将python接口文件“cv2.pyd”安装到我的python的site-packages文件夹中。

Now, I can run a pure python script which load and show an image. 现在,我可以运行一个加载并显示图像的纯python脚本。 But my issue comes when I try to show an image from GDB. 但是当我尝试从GDB显示图像时,我的问题出现了。 (The image is in my C++ program) (图像在我的C ++程序中)

#include <opencv/cv.h>
#include <opencv/highgui.h>
using namespace cv; 
...
Mat orgImg = imread("1.jpg", CV_LOAD_IMAGE_GRAYSCALE);

Then I set a breakpoint after that, then GDB hit the breakpoint, I run such command in GDB's command line 然后我在那之后设置一个断点,然后GDB点击断点,我在GDB的命令行中运行这样的命令

source test.py

The test.py is a python script which try to show an image: 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()

After that, I just run the command 之后,我只是运行命令

plot orgImg

But GDB get an error: 但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

You see, the python object under GDB is "cv::Mat", but it can not to converted to a correct python object to show. 你看,GDB下的python对象是“cv :: Mat”,但它无法转换为正确的python对象来显示。 Anyone can help me? 有人可以帮帮我吗? Thanks. 谢谢。

EDIT: I try to create a more simple script which use cv (not cv2), but it still not work: 编辑:我尝试创建一个更简单的脚本使用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()

The above code does not work as the statement "cv.SetData(a, v['data'])" does not really do an buffer address assignment. 上面的代码不起作用,因为语句“cv.SetData(a,v ['data'])”并没有真正进行缓冲区地址分配。

The "v" is a representation of cv::Mat, which has the contents: “v”是cv :: Mat的表示,其内容如下:

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

So, you see the "data" field is the raw buffer pointer, but I'm not sure how to transfer this gdb.Value to a python buffer type. 所以,你看到“data”字段是原始缓冲区指针,但我不知道如何将这个gdb.Value传递给python缓冲区类型。

I have solved this problem now, here is the solution with some minor issue remaining(see later) 我现在已经解决了这个问题,这里有一些小问题的解决方案(见后文)

Suppose you have such C++ code: 假设你有这样的C ++代码:

#include <opencv/cv.h>
#include <opencv/highgui.h>
using namespace cv; 
...
Mat img = imread("1.jpg", CV_LOAD_IMAGE_GRAYSCALE);
...

When debugging those code under GDB, I would like to see how the in memory data "img" looks like. 在GDB下调试这些代码时,我想看看内存数据“img”是怎样的。 Thanks to GDB and OpenCV, both of them have Python interface, so here is the python pretty script (I released the script code under GPLv3) 感谢GDB和OpenCV,它们都有Python接口,所以这里是python pretty脚本(我在GPLv3下发布了脚本代码)

Before that, you need 1, GDB with python enabled 2, OpenCV python interface (under Windows, it is one file cv2.pyd) 3, install python, numpy 在此之前,你需要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()
############################################################

The script above add a new GDB command "plot" to show the in memory data cv::Mat. 上面的脚本添加了一个新的GDB命令“plot”来显示内存数据cv :: Mat。 Now, you can simply type: "source cvplot.py" to load this script to GDB, then type: "plot img" to show the cv::Mat in OpenCV's Window, to let GDB continue, just close the debugger window. 现在,您只需键入:“source cvplot.py”将此脚本加载到GDB,然后键入:“plot img”以在OpenCV的窗口中显示cv :: Mat,让GDB继续,只需关闭调试器窗口即可。

BTW: I found one issue, if I uncomment "# print v" in the script source, then this script will complain such message and abort: 顺便说一句:我发现了一个问题,如果我在脚本源中取消注释“#print 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)

But if I run the command "print img" directly in the GDB's command line, it shows: 但是如果我直接在GDB的命令行中运行命令“print 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}}}

I'm not sure how to fix this, but surely I can see it was some issue that python try to decode the raw buffer to normal text. 我不知道如何解决这个问题,但我肯定可以看到python尝试将原始缓冲区解码为普通文本的问题。 (I'm using WinXP) (我正在使用WinXP)

Many thanks to Tromey, Andre_, Pmuldoon for their kind help in GDB IRC, also thanks to Hui Ning for great help and suggestion, the solution also posted in GDB maillist Post in GDB maillist , also I would like to contribute this to OpenCV community Visualize in memory OpenCV image or matrix from GDB pretty printers 非常感谢Tromey,Andre_,Pmuldoon在GDB IRC的帮助,也感谢Hui Ning的大力帮助和建议,该解决方案也发布在GDB maillist Post的GDB maillist中 ,我也想将此贡献给OpenCV社区Visualize在内存OpenCV图像或GDB漂亮的打印机矩阵

You need inferior.read_memory to transfer pixmap contents from the debugged program into the gdb process. 您需要inferior.read_memory将pixmap内容从调试程序传输到gdb进程。 Maybe check out Qt Creator implementation which has a similar feature to show QImage data. 也许查看Qt Creator实现,它具有类似的功能来显示QImage数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM