The Image Debugger The Image Debugger
A utility for simple printf-style debugging of images in Win32 C/C++ applications.
(and maybe Linux someday...)


* About

"The Image Debugger" is a programmer's utility to make debugging of Win32 applications that use images and grid data easier.  Examples of such applications include 3D games and visualization applications, as well as grid-based numerical PDE simulation codes. "The Image Debugger" could even conceivably be used to debug dense matrices.   The code is for Windows only for now, but periodically interest in a Linux port surfaces. If someone is interested in working on it (or a Mac version) please contact me at the email address below.

Often when creating graphical applications you have a chunk of memory that you know is supposed to look some certain way.  Unfortunately debuggers don't typically have a way to view that memory as an image, and so it's a real pain to figure out whether the image is correct or not.  That's where "The Image Debugger" comes in.  The typical solution -- if looking at the raw numbers in a debugger is not sufficient -- is to write a bit of code that will dump the data to a file, which can then be looked at using something like Matlab, or if you already have a graphical app, you can write some code to splat some images up on the screen on top of the actual graphical output you're trying to generate.  Either way it takes some effort.  And often it's a real hassle if you're working with double-buffered graphics, because if you want to see drawing as it's happening you have to switch to drawing on the front buffer, and even then if you're stopped at a breakpoint in the debugger and your window gets partially covered, you lose the image.

With "The Image Debugger" your data pops up in a separate window with none of those problems and with just a single line of code.   That's all it takes!  You can go from a bare bones "hello world" console application to visual output with just one line of code.   Basically you can think of this utility as a "printf" for images. So aside from debugging images, one thing you could use imdebug for, for example, would be as a really quick-and-dirty front end for a ray tracer. You write the ray-tracer, then you can make one call to imdebug to show the results.

But debugging is the primary purpose for imdebug. To debug a simple variable, x, one way is to toss a  'printf("%d\n", x)' at a strategic location in your code.   With The Image Debugger if you have an 128x128 RGB image in img, you can simply "printf" it with a call like 'imdebug("rgb w=128 h=128 %p", img)' .   For more details see the Usage section below.

* Screenshots

Here's a screen capture of The Image Debugger's output viewer application.

A screenshot of the Image Debugger


(NOTE: the rest of the screenshots are from an older version of imdebug, but the functionality  of the latest version is pretty similar.)

These next few annotated screen shots explain some of the status messages and UI elements.

Status messages give image info.

Another example screenshot.


The status also gives you pixel information. 

Scale and bias controls


* Installation

First download either the src or bin distribution.  Then to install, just unzip the files into a temp directory.   Then copy these files into the following locations:

FILE
INSTALL LOCATION
imdebug.h Put someplace where your compiler knows to look for include files.
imdebug.lib Put someplace where your compiler knows to look for library files.
imdebug.dll
imdbgdisplay.exe
Put someplace on your path, or in the same dir as the app you're debugging.

If you download the src package you'll find precompiled versions of the binaries in the "lib" directory.

That's all there is to installation!

The following headers are also available to facilitate displaying different image types:

* Usage
There are two parts to usage: calling imdebug from your code, and using the displayer to look at the output from your application.

1. Using The Image Debugger in your code

The first thing to do is put this in the file you want to debug:
 #include <imdebug.h>

The next step is to call it.  The one function exported from the imdebug DLL has this prototype:
 void imdebug(const char *format, ...);

That doesn't tell you a whole lot.  But basically that's the same argument list as printf(): a format string followed by a variable number of arguments.  The operation of imdebug is similar to printf.  The format string contains all the information about how to parse the rest of the arguments passed to the function.  The format string is basically a snippet of code in a mini-language that I devised.

Before going into the format syntax ins and outs, let's just take a look at a few usage examples (from testapp.cpp distributed in the source zip above).  Here are the declarations of the images we're going to try to display:

unsigned char testRGB[16*17*3];  // 16x17  3 8-bit channels
unsigned char testRGBA[16*17*4];  // 16x17  4 8-bit channels
unsigned short testRGB16[16*17*3];// 16x17  3 16-bit channels
float testRGBf[16*17*3]; // 16x17  3 32-bit float channels
unsigned char testBigRGBA[512*512*4]; // 512x512  4 8-bit chan

Now here's a bunch of different examples of ways to call imdebug.  Basically the minimum requirement is that you specify the width and height of your image, how many channels it has, and how many bits are in each channel.

The first example does just that:
imdebug("rgb w=%d h=%d %p", 16, 17, testRGB);
The 'rgb' says this is a 3 channel,  RGB format image.  You could also say 'bgr' if that's the order of your images channels.  8 bits per channel is assumed if nothing is specified.  The 'w=' and 'h=' statements tell imdebug the width and height of the image.  The actual values could be entered directly in the format string, like 'w=16 h=17'  but it's also possible to use the '%d' specifier to tell imdebug to get the value from an input argument instead.  Finally the '%p' indicates the image pointer argument.

Here's another example
imdebug("rgb rbga=__gg w=%d h=%d %p", 16, 17, testRGB);
This is just like the last one exept for the swizzling statement "rbga=__gg".   This tells imdebug to remap the input channels when displaying the image.  An '_' indicates a channel should be discarded.  In this case we see the green input value will be used both as an alpha channel and as the green channel, while red and blue channels will just be ignored.  Note that that's "rBGa" not "rGBa".  Originally when I typed it I made a typo, but Imdebug can interpret the statement either way.  If I had typed the latter, then imdebug would map the green input to the blue and alpha channels instead of green and alpha.

To specify the bit-depth of your channels use the 'b=' statement:
imdebug("rgb rbga=gggg  b=32f w=%d h=%d %p", 16, 17, testRGBf);
The 'f' indicates floating point values instead of integer values.  
Using '*auto' tells imdebug to autoscale (and bias) the values in the floating point image to a [0,1) range for output. Useful if you're looking at non-image floating point data which isn't in the [0,1) range:
imdebug("rgb rbga=gggg *auto b=32f w=%d h=%d %p", 16, 17, testRGBf);
Here are some other examples:
imdebug("rgb rbga=__gg b=16 w=%d h=%d %p", 16, 17, testRGB16);
imdebug("rgb rbga=gggg w=%d h=%d %p", 16, 17, testRGB);
imdebug("lum b=32f w=%d h=%d %p", 16*3, 17, testRGBf);
imdebug("rgba  w=%d h=%d %p", 512, 512, testBigRGBA);

And finally here's the syntax description from the imdebug.h.  It's not necessarily all 100% correct or 100% tested.  If something doesn't work let me know.

 VARIABLE SPEC:
  %d  -  int
  %f  -  float
  %s  -  string
  %p  -  picture (pointer to raw image data)
 
 INPUT FORMAT SPEC:
  rgb
  bgr
  abgr
  rgba...   - specify input image channel order
  lum       - 1-channel image: lumninance
  luma      - 2-channel image: lumninance + alpha
  #7        - Generic 7-channel image
  ---> (default is rgb)

  b=8       - size of all channels is 8 bits
  b=5,6,5   - size of channels is 5bits(R) 6bits(G) 5bits(B)
  b=32f     - size of all channels is 32 bits, float format
  ---> (default is b=8)

 OUTPUT FORMAT SPEC:
  rgba=rg__ - just display the red and green chanels
  rgba=aaa_ - display alpha as grayscale
  lum=g     - display green as grayscale
  rgba=#0512 - map channels by number
  ---> (default is 1-1 mapping with no translation or swizzling)

 ATTRIBUTE SPEC:
  w=23      - width  is 23 (default 0)
  h=17      - height is 17 (default 0)
  rs=1      - skip 1 row after every row  (default 0)
  cs=2      - skip 2 columns after every column (default 0)
  t='img2'  - title to put in displayer titlebar

 SCALE AND BIAS:
  *1.2      - scale by 1.2
  /1.2      - scale by 1/1.2
  +128      - bias  by 128
  -0.5      - bias  by -0.5
  *auto     - automatically scale & bias based on max & min values
  --> Default is scale=1 and bias=0
  --> Output value is computed by first scaling, then biasing, i.e.
                 out = (in*scale)+bias,
       the same order as with OpenGL glPixelTransfer functions.

  Order of specifiers is mostly not important, but channel swizzeling should come after input format specifier.
  (i.e. do "rgb bgr=rgb",   not "bgr=rgb  rgb")

  If no image is specified (with '%p'), then the previous
  image data is used.




If you have installed the header file and .lib file where your compiler can find them, then compiling your app with imdebug should be just like compiling without.  You shouldn't have to do anything special to get it to link.   The header file uses a special "#pragma comment" to tell the linker to link with the DLL, so you don't have to add it explicitly to your link command.  (Recent versions of GLUT use this technique too).

Using imdebug with OpenGL 

Here's an example of some utility functions for looking at OpenGL textures using imdebug:

Mark Harris and I have put together imdebug utility functions for OpenGL: imdebuggl.h. The main imdebug function in this header is :

imdebugTexImage{f}(target,myTextureID,level,format).
There are also functions that read the color, depth, and stencil out of the current frame buffer and dump those pixels to the imdebug window.

The header is for C++ only. 

Using imdebug with Direct3d9

Mark Harris contributed this minimal header for using imdebug with Direct3d: imdebugd3d9.h.

2. Using the Output Viewer 

When you call the imdebug() function, the imdebug.dll launches the output viewer, imdbgdisplay.exe (show in the screenshots above) and sends it a copy of the image data that you passed in as the '%p' argument.  Once the output viewer app has the data, the app can make whatever changes it wants; the viewer's local copy will not change.  (For the curious, this inter-process communication is accomplished using a memory-mapped file).  

Repeated calls to imdebug() cause the viewer to buffer up the images.  You can use the GUI to navigate and inspect the most recently output images. The history holds up to 10 images initially, but is user-configurable.

The main GUI functions are as follows:

Mouse drag translate image around
Mouse wheel zoom image in and out
Ctrl+Mouse wheel navigate back and forth in the history buffer
Up  Down navigate back and forth in the history buffer
PgUp PgDn also navigates, but skips directly to the next or previous
image whose title matches the current image.
(Image titles are set by putting a t='a title' in the format string.
Ctrl+G toggle the pixel grid lines on and off
Ctrl+F toggle flipping in the Y direction
Ctrl+B
toggle background type (solid gray or checkerboard)
Ctrl+I Block new images coming from the app (ignore output from app)
-
zoom out
=
zoom in
/ rescale image to fit in window
Shift+0 - Shift+9
zoom to preset magnifications
(Shift+1=100% ... Shift+9=900%, Shift+0=1000%)
Ctrl+1 - Ctrl+6 change color channels being displayed


* Bugs
There are a few known bugs and also many features that could make things even more groovy.

Top on the list are:

Known Bugs

  • The row stride and column stride settings (rs=,cs=) need work.  I think they're currently broken. You'll have to use densely packed data for now.
  • Can't handle non-native endian data.  For 8-bit channels, of course you can just call your RGBA image ABGR and you're set.  But for 16-, 32-, and 64- bit channels there's trouble.
  • I'm probably not handling the distinction between signed and unsigned data types correctly, but I haven't really had much need for such a thing..
  • Copy-image-to-clipboard and save-image-to-file functionality not implemented.

Desiderata

  • The ability to control the channel selection and swizzling from the GUI would be handy.
  • A way to change to other backgrounds in the viewer.  Either provide a larger selection of built-in backgrounds or a way to load an external image to use as a background.  Often that checkboard background can look way too much like the data you're trying to see.
  • "Pixel watch".  The ability to click on one or more pixels of an image and have those values appear in a list.  Then you could see what's happening to a value over time without having to make sure the mouse is over the right pixel.
  • Integration into development environments so that no source code modification is necesary. Perhaps a plugin for Visual Studio or Eclipse?

* History
Dec 29, 2005 Moved project to BerliOS.
Also at some point not too long ago I fixed a bug with the tooltip messages that Mark Harris found. It caused the reported pixel values to be incorrect in some cases.
Aug 30, 2003 Version 1.13-beta
Fixed a couple of bugs with images past the buffer size getting dropped, and with the blocking mode causing long delays.
Aug 18, 2003 Version 1.12-beta
Fixed bug with images getting dropped when sent rapidly back-to-back.
Aug 7, 2003
Version 1.1-beta.
Added some more UI and a "linked image" mode that syncs all image changes so that if you zoom and scale one image, all images with the same title will be zoomed and scaled the same way.
Aug 4, 2003
Version 1.0-beta.
Ported GUI front-end from straight Win32 to FOX toolkit.
FOX allows me to handle status and tooltip help more nicely, and support image load and save. It also enabled me to use nice UI controls for scale and bias, rather than the cheesy static bitmaps I had that didn't respond in any way.
Using FOX also means that imdebug can now be ported over to Linux/Unix pretty easily.
Some other specific new features added:
  • "Link Image" mode.  In this mode, when you drag or zoom or change scale and bias on any image, the same changes are also made to all other images with the same title currently in the history buffer.  This makes it easier to go back and forth to compare differences between different instances of the same image. (Similar but slightly different from the old "Propagate Scale&Bias mode")
  • "Replace Images" mode. In this mode when a new image is recieved with a particular title, like 'foo', that image overwrites the last image with that title.  This way if you imdebug an image titled 'bar' once early on and then imdebug 'foo' 100 times in a loop, 'bar' will remain in the history buffer, along with the most recent version of 'foo'.
  • "Hold on image" mode.  Causes the display window not to automatically jump to the the most recent image.  Particularly useful with "Replace Images" mode.
  • Navigation by title.  Using PgUp and PgDn now takes you back and forth directly to the previous and next images with same title, skipping all images in between.  Just like getting on the express train!  Using Up and Down arrows takes you on the "local train" with all  the stops along the way (like PgUp and PgDown used to).
  • Tooltips!  You now get the pixel info directly under your mouse so you don't have to look down at the statusbar constantly.  You can flip back and forth between two versions of the same image now using PgDn/PgUp, and if you leave your mouse in place you can see the change in values in the tooltip.
Apr 4, 2003
Version 0.954b.
Fixed "alpha" on "channels" menu. Now alpha displays as grayscale.
Apr 2, 2003
Version 0.953b.
Added a "channels" menu, basically to allow turning off the alpha channel interactively.  If alpha is all 0, you can't see the other data, which is annoying.  Of course you can specify "rgba=rgb_" in your format string, but you'd like to be able to get the same effect on the fly, and now you can.
Mar 7, 2003
Version 0.952b.
Fixed aligment of images in the window when "flip" is checked.
Fixed auto-scaling of images that are all one color.
Feb 23, 2003
Version 0.951b.
Added option to automatically copy the scale & bias of a tagged image to the next image with the same tag. Currently it's overridden by any specific scale or bias set on the image itself using the format string.
Feb 18, 2003
Version 0.95b.
Added button to set scale and bias back to identity.
Changed "Ready" message to give info on image (resolution, bit depth, etc.)
Feb 17, 2003
Version 0.942b.
Fixed parsing of bias syntax in format string.
Added some UI to allow interactive munging of scale and bias.
Jan 26, 2003
Version 0.94b.
-Added somewhat meaningful error status messages for some cases.
-Increased memory mapped file limit be able to handle RGBA images of 32f  2048x2048.
-Added dialog to change number of images saved in history buffer.
-Fixed bug with flipped images not getting the status correct.
-Fixed error trying to allocate negative memory when window made too small.
-Made it so status message isn't set to "Ready" so often when it could say something useful.
-Made status message indicate which values are mapped to which output channels.
-Added option for reusing/sharing the display window so you don't end up with like 23 "Image Debugger Display" windows hanging around all the time.
-Added t='label' to format string so you can give images intelligible labels that will make it easier to distinguish which of 10 all black images is the one you're looking for.
-Added big red "BLOCK" status indicator to let you know when the displayer is not listening (in case you accidentally hit Ctrl-I or something)
Sept 19, 2002
Version 0.931b.
I think I fixed the clipboard Edit->Copy problem.  Maybe.  It worked for me, anyway, though I can't say why for sure.
Sept 15, 2002
Version 0.93b.
Added state save and restore using windows registry. (remebers window position and checked menu items)
Sept 13, 2002
Version 0.921b.
Reports errors when imdbgdisplay not found.
Added alt-left and alt-right keys for navigating images.
Sept 11, 2002
Version 0.92b.
Added support for packed bit formats like 5,6,5.  Will work as long as the total bits are a multiple of 8, which most real formats are.
Added support for independent scaling and biasing on a per-chanel basis, like OpenGL allows.
Sept 10, 2002 Version 0.91b.
Added the '#8' type format specifications for dealing with data having more than 4 channels.  Just something that I had forgotten to include in the parser.
Sept 9, 2002 Version 0.9b
First release.

* Download

The Image Debugger is now hosted on berliOS, so check there for the most recent releases, or get code directly from the repository using subversion.
Version 1.13 is available from the link below, but it may not be the latest. The 1.x versions all use the FOX toolkit for the GUI rather than raw Win32.

The older Image Debugger version 0.954b can be downloaded from the links below:
  • Binary only distribution:       imdebug-0.954b-bin.zip
    This has everything you need to use The Image Debugger:  
imdebug.h  -  header to #include in your app
imdebug.dll  -  dll to link with your app (note this happens automatically)
imdebug.lib  -  export library necessary for compiling your app agains the dll.
imdbgdisplay.exe -  the output viewer application.  (Launched automatically when you call imdebug())
testapp.exe -  a very basic test program made with OpenGL/GLUT that spits out a few images in its display function and draws a lame-looking teapot in its GL window.  You may need to grab the GLUT dlls to get it to run.
  • Binaries + full source code:     imdebug-0.954b-src.zip
    This has everything the binary only distribution has, plus all the source code.  It also includes project files for MSVC++ 6.0, as well as a makefile that works with Microsoft's NMAKE.

* Acknowledgements
Thanks to the developers of the FOX Toolkit and especially Jeroen van der Zijp, for his helpful replies on the foxgui-users mailing list.  I've worked with a number of GUI toolkits, and I have to say FOX is one of the nicer ones I've tried.  The library has a nice feel to it (even though the messaging system is kind of difficult to get the hang of).  The documentation is a bit sparse, but the source code itself is quite clean and readable for the times when you can't figure out what you need in the doc.  And there are a good number of example programs to go from, where you often find exactly the code you need to steal.

Thanks to Jeffrey Richter and Charles Petzold, without whose books (this one and that one) there's no way I could have figured out how to do the original imdebug (i.e. figure out how to write a straight Win32 C program that uses memory mapped files to communicate inter-process data).  Thanks also to Willem van Schaik who wrote "VisualPNG".  The image display code in the original straight Win32 imdbgdisplay.exe (versions v0.9b-v0.954b)  were based initally off of his source code. More info at Willem's website here.

Thanks to the person over at  http://www.codeproject.com (I think!) whose comment about an image debugger got me thinking about this idea.  I got excited because when I saw him use "image" and "debug" in the same sentence, the first thought I had was that he had written something like the utility I ended up writing.  It turned out, though, that his program was of a somewhat more limited scope.   I'm not sure what his name was, and I haven't been able to find the link again since then.

Thanks to Andrew Z. whose one followup to my post on unccs.graphics was all the convincing I needed to go and write this, and thanks to Mark Harris for his copious and useful suggestions.


* Contact

The Image Debugger was developed by me, William Baxter, mostly while a PhD student at the University of North Carolina at Chapel Hill in the CS department. I'm currently working for OLM Digital in Tokyo, Japan [warning -- Flash-heavy link]. If you're interested, have a look at the other projects I've worked on.

If you find this software useful, or make any improvements, please let me know.  If you have patches you'd like to contribute by all means please send 'em in!

<EMAIL ADDRESS> You can contact me by by sending email to my last name @cs.unc.edu.  Or by going to my feedback page.

Happy Image Debugging!