This is the mail archive of the gdb@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Visualize in memory OpenCV image or matrix from GDB pretty printers


Hi, I'm pleased to share the script to show an in memory cv::Mat or Images when debugging.
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(ninghui8673@126.com) for great help and suggestion.

Yuanhui Zhang







Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]