1

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. Luckily I have:

  1. GDB with python support;
  2. I have installed python 2.7.4, numpy library, and opencv official release 2.4.4;
  3. I have installed the python interface file "cv2.pyd" to my python's site-packages folder.

Now, I can run a pure python script which load and show an image. But my issue comes when I try to show an image from GDB. (The image is in my C++ program)

#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

source test.py

The test.py is a python script which try to show an image:

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:

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. Anyone can help me? Thanks.

EDIT: I try to create a more simple script which use cv (not cv2), but it still not work:

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.

The "v" is a representation of cv::Mat, which has the contents:

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

2 Answers 2

2

I have solved this problem now, here is the solution with some minor issue remaining(see later)

Suppose you have such C++ code:

#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. 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)

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

############################################################
#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. 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.

BTW: I found one issue, if I uncomment "# print v" in the script source, then this script will complain such message and abort:

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:

$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. (I'm using 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 communityVisualize in memory OpenCV image or matrix from GDB pretty printers

Sign up to request clarification or add additional context in comments.

3 Comments

thank you for your script! But now opencv can only be installed as version3.x by pip3 which is used by python3 (which gdb uses by default). And cv2.cv is no longer available for OpenCV 3.x. So your script no longer works. Any idea to workaround? @ollydbg23
I think it is possible to create a new Python debug script which only use the new OpenCV Python interface, I will see whether I can have some spare time to implement.
Hi, @ScottYang, there are many such script which does not depend on the cv2 python module, you can have a look at this one: github.com/cuekoo/GDB-ImageWatch I see it only depends on numpy for display. Also, I also have an updated script released in year 2015, which is also not depend on cv2, see this site: sourceforge.net/projects/visualdebugger
1

You need inferior.read_memory to transfer pixmap contents from the debugged program into the gdb process. Maybe check out Qt Creator implementation which has a similar feature to show QImage data.

1 Comment

Hi, jamba, many thanks, I have asked on GDB IRC for my question and they also suggest using the inferior.read_memory function. In-fact, I have solved my problem, but my python code is not quite good because it still need some code to determine the dimension and the pixmap contents staring address and size, I will post them if I solved all the problems.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.