Share via


Image Watch extensibility

Image Watch can be extended to display user-defined C/C++ image types. A suitable user-defined type must have a supported pixel format. For an introduction to Image Watch, see Image Watch.

Image Watch builds on Visual Studio’s Natvis framework to support user-defined types. A .natvis file is a debugger-friendly XML description of a C++ type: it contains the name of the type and a set of rules for how to display the type’s properties. In Image Watch, a .natvis file describes how to read the image width, height, pixel address, etc. from an image object.

Image Watch’s built-in OpenCV types, cv::Mat, CvMat, and _IplImage, are specified in a .natvis file called ImageWatchOpenCV.natvis which can be used as a reference when writing Image Watch extensions. ImageWatchOpenCV.natvis is part of the ImageWatch.vsix installer, which is just a .zip archive. You can simply rename it to ImageWatch.zip and extract the contents using your favorite zip tool.

Example 1: A simple 8bit RGB image

struct My8BitRGBImage 
{ 
    unsigned int ncols; 
    unsigned int nrows; 
    unsigned char* data; 
}; 

and its .natvis description

<?xml version="1.0" encoding="utf-8"?> 
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> 
  <UIVisualizer ServiceId="{A452AFEA-3DF6-46BB-9177-C0B08F318025}" Id="1"  
                MenuName="Add to Image Watch"/> 
  <Type Name="My8BitRGBImage"> 
    <UIVisualizer ServiceId="{A452AFEA-3DF6-46BB-9177-C0B08F318025}" Id="1" /> 
  </Type> 
  <Type Name="My8BitRGBImage"> 
    <Expand> 
      <Synthetic Name="[type]"> 
        <DisplayString>UINT8</DisplayString> 
      </Synthetic> 
      <Synthetic Name="[channels]"> 
        <DisplayString>RGB</DisplayString> 
      </Synthetic> 
      <Item Name="[width]">ncols</Item> 
      <Item Name="[height]">nrows</Item> 
      <Item Name="[data]">data</Item> 
      <Item Name="[stride]">ncols*3</Item> 
    </Expand> 
  </Type>   
</AutoVisualizer> 

Image Watch requires one <UIVisualizer> declaration per .natvis file, and two <Type> declarations per type. The first <Type> node has only a <UIVisualizer> child; the second one has an <Expand> child. Note that the <Expand> section is the only part that needs to be customized to support your image type. The <Expand> node must contain <Item> or <Synthetic> child elements with the following Name properties:

[type]: a channel type.

[channels]: the channel format. This can be either a number (= number of channels) or one of the supported format strings (which implies the number of channels).

[width]: the image width, in pixels

[height]: the image height, in pixels

[planes]: the number of planes. If omitted, a single plane is assumed (default for packed pixel layouts). Note that special YUV formats may require a specific number of planes (e.g. 2 for NV12, 3 for IYUV and YV12).

[data]: pointer to the beginning of the pixel data. For packed images, this is a single address. For planar images, a semicolon-delimited list with individual plane addresses may be specified (see Example 2 below). Otherwise, the address denotes the start of first plane, and planes are assumed to be consecutive in memory.

[stride]: number of bytes per pixel row. For planar images, this can be a semicolon-delimited list of strides for each plane. Otherwise, the same stride is used for all planes.

[range]: custom pixel value range for color mapping (optional). Two floating point values (min; max), separated by a semicolon. For example, “0; 4095” for 12bit images. If this parameter is omitted Image Watch assumes that pixels values lie within the default value range (for example, 0 … 65535 for UINT16).

The [type] and [channels] properties in Example 1 are <Synthetic>, since their values (UINT8, RGB) are not results of C++ expressions, but arbitrary text. In contrast, in Example 3 (below), [channels] is an <Item> element, since its value is a C++ debugger expression.

Every time the debugger is launched, Image Watch looks for .natvis files in %USERPROFILE%\My Documents\Visual Studio [Version]\Visualizers and parses them. Diagnostic information about this process is logged in ImageWatch.log in the Visualizers folder. Image Watch also logs errors during debugging if it cannot parse one of the above properties. To indicate that a property has a value that is not supported by Image Watch (e.g., channel type is 64bit integer), simply leave out the property completely (e.g. using <Synthetic>’s Conditional attribute). Images with missing properties are displayed as [invalid], but no error is logged. Likewise, images with complete but inconsistent properties (e.g. stride too small given width and pixel type) are shown as [invalid]. To indicate that your image is in a valid, but uninitialized state, set [width], [height] and [data] to zero. Image Watch displays these images as [noinit].

Example 2: A planar YUV image:

struct MyPlanarYUVImage 
{ 
    unsigned int ncols; 
    unsigned int nrows; 
    unsigned char* ydata; 
    unsigned char* udata; 
    unsigned char* vdata; 
}; 

and its .natvis description

<?xml version="1.0" encoding="utf-8"?> 
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> 
  <UIVisualizer ServiceId="{A452AFEA-3DF6-46BB-9177-C0B08F318025}" Id="1"  
                MenuName="Add to Image Watch"/> 
  <Type Name="MyPlanarYUVImage"> 
    <UIVisualizer ServiceId="{A452AFEA-3DF6-46BB-9177-C0B08F318025}" Id="1" /> 
  </Type> 
  <Type Name="MyPlanarYUVImage"> 
    <Expand> 
      <Synthetic Name="[type]"> 
        <DisplayString>UINT8</DisplayString> 
      </Synthetic> 
      <Synthetic Name="[channels]"> 
        <DisplayString>YUV</DisplayString> 
      </Synthetic> 
      <Item Name="[width]">ncols</Item> 
      <Item Name="[height]">nrows</Item> 
      <Item Name="[planes]">3</Item> 
      <Synthetic Name="[data]"> 
        <DisplayString>{(void*)ydata}; {(void*)udata}; {(void*)vdata}</DisplayString> 
      </Synthetic> 
      <Item Name="[stride]">ncols</Item> 
    </Expand> 
  </Type>   
</AutoVisualizer> 

Note the [planes] property is set to 3 in this example. Since our planes are not consecutive in memory, the [data] property has three semicolon-delimited addresses. [data] is a <Synthetic> item, since its value is a custom formatted string, not a C++ expression. Also note the (void*) cast: it is required to force the Visual Studio debugger to print an address only, not a string of characters (since the data pointers are of type unsigned char). This example assumes no row padding and all strides equal, therefore [stride] is simply ncols. Similarly to [data], [stride] can be either a single value, or delimited list of strides for each plane.

Example 3: C++ templates are supported as well. Here is a more general image template:

template <typename T> 

struct MyGenericImage 
{	 
    unsigned int ncols; 
    unsigned int nrows; 
    unsigned int nchannels; 

    T* data; 
}; 

and the corresponding .natvis definition:

<?xml version="1.0" encoding="utf-8"?> 
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> 
  <UIVisualizer ServiceId="{A452AFEA-3DF6-46BB-9177-C0B08F318025}" Id="1"  
                MenuName="Add to Image Watch"/> 
  <Type Name="MyGenericImage&lt;*&gt;"> 
    <UIVisualizer ServiceId="{A452AFEA-3DF6-46BB-9177-C0B08F318025}" Id="1" /> 
  </Type> 
  <Type Name="MyGenericImage&lt;*&gt;"> 
    <Expand> 
      <Synthetic Name="[type]" Condition='strcmp("unsigned char", "$T1") == 0'> 
        <DisplayString>UINT8</DisplayString> 
      </Synthetic> 
      <Synthetic Name="[type]" Condition='strcmp("float", "$T1") == 0'> 
        <DisplayString>FLOAT32</DisplayString> 
      </Synthetic> 
      <Item Name="[channels]">nchannels</Item> 
      <Item Name="[width]">ncols</Item> 
      <Item Name="[height]">nrows</Item> 
      <Item Name="[data]">data</Item> 
      <Item Name="[stride]">ncols*nchannels*sizeof($T1)</Item> 
    </Expand> 
  </Type> 
</AutoVisualizer> 

This .natvis definition supports MyGenericImage images with unsigned char or float pixels. Note the “*” wildcard syntax, the Condition attribute, and the $T1 reference to the template argument. Also, this example shows how to use Visual Studio’s debugger intrinsics strcmp() and sizeof() for processing C++ type names. For general information on templates in .natvis files, please refer to Visual Studio’s Natvis documentation.

See also