Interfaces » DIPlib-OpenCV interface module

Functions to convert images to and from OpenCV.

The dip_opencv namespace defines the functions needed to convert between OpenCV cv::Mat objects and DIPlib dip::Image objects.

We define a class dip_opencv::ExternalInterface so that output images from DIPlib can yield an OpenCV image. The function dip_opencv::MatToDip encapsulates (maps) an OpenCV image in a DIPlib image; dip_opencv::DipToMat does the opposite, mapping a DIPlib image as an OpenCV image.

Limitations

OpenCV is more limited in how the pixel data is stored, and consequently not all DIPlib images can be mapped as an OpenCV image. These are the limitations:

  • The maximum number of channels in OpenCV is CV_CN_MAX (equal to 512 in my copy). DIPlib tensor elements are mapped to channels, but the tensor shape is lost. The tensor stride must be 1.

  • OpenCV recognizes the following types (depths): 8-bit and 16-bit signed and unsigned ints, 32-bit signed ints, and 32-bit and 64-bit floats. Thus, dip::DT_UINT32 cannot be mapped. We choose to map it to 32-bit signed ints, with the potential problem that the upper half of the unsigned range is mapped to negative values (all modern systems use two’s complement). dip::DT_BIN is mapped to an 8-bit unsigned integer, see the note below. 64-bit integer images cannot be mapped and throw an exception.

  • Complex pixel values are mapped to CV_32FC2 or CV_64FC2 – a 2-channel float cv::Mat array. Consequently, complex-valued tensor images cannot be mapped.

  • cv::Mat objects can store arrays of any dimensionality larger than 2, but OpenCV functionality is mostly limited to 2D images. Therefore, we only map 2D dip::Image objects in a cv::Mat array. 0D or 1D images will have singleton dimensions appended to force them to be 2D.

  • In OpenCV, the image rows must be contiguous (i.e. the x-stride must be equal to the number of tensor elements), and the y-stride must be positive. This matches DIPlib’s default, but if the dip::Image object has strides that don’t match OpenCV’s requirement (e.g. after extracting a non-contiguous subset of pixels, or calling dip::Image::Mirror or dip::Image::Rotation90), an exception will be thrown. Use dip::Image::ForceNormalStrides to copy the image into a suitable order for mapping. Alternatively, use dip_opencv::CopyDipToMat.

Namespaces

namespace dip_opencv
The dip_opencv namespace contains the interface between OpenCV 2 (or later) and DIPlib.

Classes

class dip_opencv::ExternalInterface
This class is the dip::ExternalInterface for the OpenCV interface.

Functions

auto dip_opencv::MatToDip(cv::Mat const& mat, bool forceUnsigned = false) -> dip::Image
Creates a DIPlib image around an OpenCV cv::Mat, without taking ownership of the data.
auto dip_opencv::DipToMat(dip::Image const& img) -> cv::Mat
Creates an OpenCV cv::Mat object around a DIPlib image, without taking ownership of the data.
auto dip_opencv::CopyDipToMat(dip::Image const& img) -> cv::Mat
Creates an OpenCV cv::Mat object from a DIPlib image by copy.
void dip_opencv::FixBinaryImageForDip(dip::Image& img)
Fixes the binary image img to match expectations of DIPlib (i.e. only the bottom bit is used).
void dip_opencv::FixBinaryImageForOpenCv(dip::Image& img)
Fixes the binary image img to match expectations of OpenCV (i.e. all bits have the same value).

Function documentation

dip::Image dip_opencv::MatToDip(cv::Mat const& mat, bool forceUnsigned = false)

Creates a DIPlib image around an OpenCV cv::Mat, without taking ownership of the data.

This function maps a cv::Mat object to a dip::Image object. The dip::Image object will point to the data in the cv::Mat, which must continue existing until the dip::Image is deleted or stripped. The output dip::Image is protected to prevent accidental reforging, unprotect it using dip::Image::Protect.

An empty cv::Mat produces a non-forged dip::Image.

If the OpenCV image mat has depth CV_32S (32-bit signed integer), and forceUnsigned is true, then the output dip::Image will be of type dip::DT_UINT32, instead of dip::DT_SINT32.

For a “binary” OpenCV image (these are images of type CV_8U with pixel values of 0 and 255), the mapped DIPlib image is of type dip::DT_UINT8, because this function cannot know if the input mat was used as an 8-bit unsigned integer image or as a binary image. The simplest way to obtain a binary DIPlib image is to threshold the output of MatToDip. However, this leads to an image that doesn’t share the data segment with the original mat:

cv::Mat bin_mat = cv::threshold(...);                 // This is a "binary" OpenCV image
dip::Image bin_dip = dip_opencv::MatToDip( bin_mat ); // This is a dip::DT_UINT8 DIPlib image, not dip::DT_BIN
bin_dip = bin_dip > 0;

There currently is no simple solution to creating a dip::DT_BIN image that encapsulates the data from a cv::Mat image. However, one can encapsulate the data of a binary dip::Image in a cv::Mat, see the example in dip_opencv::FixBinaryImageForOpenCv.

cv::Mat dip_opencv::DipToMat(dip::Image const& img)

Creates an OpenCV cv::Mat object around a DIPlib image, without taking ownership of the data.

This function maps a dip::Image object to a cv::Mat object. The cv::Mat object will point to the data in the dip::Image, which must continue existing until the cv::Mat is deleted.

A non-forged dip::Image produces an empty cv::Mat.

There are many limitations to the images that can be mapped by a cv::Mat, see the description in the documentation to the module: DIPlib-OpenCV interface. You can also use dip_opencv::CopyDipToMat instead.

cv::Mat dip_opencv::CopyDipToMat(dip::Image const& img)

Creates an OpenCV cv::Mat object from a DIPlib image by copy.

A non-forged dip::Image produces an empty cv::Mat.

If the image has more than two dimensions, or is a complex-valued tensor image, no copy can be made; an exception will be thrown.

void dip_opencv::FixBinaryImageForDip(dip::Image& img)

Fixes the binary image img to match expectations of DIPlib (i.e. only the bottom bit is used).

The input image is expected to be binary. See dip_opencv::FixBinaryImageForOpenCv for a use case.

void dip_opencv::FixBinaryImageForOpenCv(dip::Image& img)

Fixes the binary image img to match expectations of OpenCV (i.e. all bits have the same value).

The input image is expected to be binary. The data segment for the image is modified such that it is no longer useful for use in DIPlib, but becomes useful for use in OpenCV.

dip::Image bin_dip = dip::Threshold(...);          // This is a DIPlib binary image
cv::Mat bin_mat = dip_opencv::DipToMat( bin_dip ); // This is an OpenCV CV_8U image with values 0 and 1
// use bin_dip with DIPlib functions here...
dip_opencv::FixBinaryImageForOpenCv( bin_dip );    // Now both bin_dip and bin_mat have values 0 and 255
// use bin_mat with OpenCV functions here...
dip_opencv::FixBinaryImageForDip( bin_dip );       // Now both bin_dip and bin_mat have values 0 and 1
// use bin_dip with DIPlib functions here...