Getting Started with CVBpy

Rendering the Image

When testing a image processing algorithms we usually want to see the result rendered in some sort of UI as verifying pixel one by one is cumbersome work.We are lucky that this can be done easily through numpy using pyplot.

import matplotlib.pyplot as plt
...
plt.imshow(np_image, cmap="gray")

See also

This provides a simple method to visualize your image data.

But what if the plotted image pop-up is not enough, as an actual interactive custom UI is required.
E.g you may also want to render some custom stuff on top of the image to visualize your results
or some controls to receive user input.

UI libraries usually define their own image/buffer formats optimized for on screen rendering. This format usually does not match the image format provided by a streaming device. So at least one low level copy of the image data is required.

How does it look like in a real example? E.g using PyQt5 as UI framework.

The following steps can be used to copy a mono :cvb: image into an ARGB QImage optimized for rendering. Similar steps are required to copy into an OpenGl texture for instance.

  1. Load a mono image from file.
cvbMonoImage = cvb.Image(cvb.install_path() + "/tutorial/Clara.bmp")
  1. Link the image buffer into a format suitable for on screen drawing (no copy).
cvbRGBImage = cvb.Image.from_images(cvb.MappingOption.LinkPixels, [cvbMonoImage.planes[0].map(), cvbMonoImage.planes[0].map(), cvbMonoImage.planes[0].map()])
  1. Create a numpy array that matches the buffer layout of QImage (includes an alpha channel).
npImage = numpy.empty([cvbMonoImage.height, cvbMonoImage.width, 4], numpy.uint8, order="C")
npImage.fill(255) # initialize the alpha channel
  1. Create a QImage as view into the numpy array (no copy).
qImage = QImage(npImage.data, npImage.shape[1], npImage.shape[0], npImage.strides[0], QImage.Format_ARGB32_Premultiplied)
  1. Create a :cvb: image as view into the numpy array (no copy).
cvbWrappedImage = cvb.WrappedImage.from_buffer(npImage)
  1. Use :cvb:'s optimized copy routine to copy the data to the buffer owned by the numpy array.
cvbRGBImage.copy(cvbWrappedImage)

This is the only step that copies data and therefore the only potentially expensive step.

  1. Use a QPainter to render into the image.
painter = QPainter()
painter.begin(qImage)
painter.setBrush(QBrush(Qt.red))
painter.setPen(Qt.NoPen)
painter.drawRect(48, 83, 109, 25)
painter.end()

8 Show the image in a QLabel.

app = QApplication(sys.argv)

lb = QLabel()
lb.setPixmap(QPixmap.fromImage(qImage))
lb.setAlignment(Qt.AlignCenter)
lb.show() 

sys.exit(app.exec_())

(rendering QImage actually requires another internal copy, but I prefer to keep it simple :wink: )

image

Please note that this is not the most elegant or most efficient way to draw an image into a QWidget, but the most illustrative.

1 Like