IOLink 1.11.0
Loading...
Searching...
No Matches
customImageView.cpp

This code demonstrates how to create a custom implementation of an ImageView to generate a checkerboard.

This code demonstrates how to create a custom implementation of an ImageView to generate a checkerboard. The image itself won't be allocated in memory, but rather generated on-the-fly when requested.

#include <iomanip>
#include <iostream>
#include <numeric>
#include <vector>
#include <iolink/Error.h>
#include <iolink/UidGenerator.h>
#include <iolink/view/ImageView.h>
#include <iolink/view/ImageViewFactory.h>
using namespace iolink;
// Define a custom ImageView class that generates a checkerboard pattern
{
public:
CheckerboardImageView(size_t width, size_t height, size_t tileCountByRow, size_t tileCountByColumn)
: m_shape{width, height}
, m_tileSize{width / tileCountByRow, height / tileCountByColumn}
{
// generate the image properties
// here we initialize the image properties using UINT8 datatype
m_properties = ImageProperties::fromDataType(DataTypeId::UINT8);
// then we customize the properties
m_properties->imageInfo().setAxesInterpretation(AxesInterpretationId::IMAGE);
m_properties->imageInfo().setBitDepth(1); // 1 bit per pixel is enough for a checkerboard
m_properties->imageInfo().setAlpha(false); // no alpha channel
m_properties->imageInfo().setInterpretation(ImageInterpretation::BINARY); // black or white
m_properties->calibration().setUnit("cm"); // unit is centimeter
m_properties->calibration().setSpacing(Vector3d{0.1, 0.1, 1}); // pixel size is 0.1 cm
}
inline VectorXu64& shape() override { return m_shape; }
// datatype will always be UINT8
inline DataType dataType() override { return DataTypeId::UINT8; }
{
return ImageCapability::READ; // only READ capability is supported
// WRITE capability has no sense since the image is generated on-the-fly
// RESHAPE capability could be added to resize the image, but it's not implemented here
// MEMORY_ACCESS capability is not supported since the image is not allocated in memory
}
inline std::shared_ptr<const ImageProperties> properties() override { return m_properties; }
// no metadata for this image
inline std::shared_ptr<const MetadataNode> metadata() const override { return nullptr; }
// readRegion must be implemented since the image has READ capability
void readRegion(const RegionXu64& region, void* dst) override
{
// check if the region is valid (must be 2D in this case)
if (region.dimensionCount() != 2)
throw InvalidArgument("Invalid region size");
// check if the region is within the image bounds
if (!fullRegion.contains(region))
throw InvalidArgument("Region out of bounds");
const uint8_t valueBlack = 0;
const uint8_t valueWhite = 1;
uint8_t* ptr = reinterpret_cast<uint8_t*>(dst);
const VectorXu64& sizeReg = region.size();
// the checkboard pattern is generated by alternating black and white tiles
// but generation must take into account the region position in the whole image
for (size_t y = 0; y < sizeReg[1]; ++y)
{
for (size_t x = 0; x < sizeReg[0]; ++x)
{
// position of the pixel in the region
Vector2u64 positionRegion = Vector2u64{x, y};
// position of the pixel in the whole image
Vector2u64 positionImage = positionRegion + region.origin();
Vector2u64 tileId = positionImage / m_tileSize;
if ((tileId[0] + tileId[1]) % 2 == 0)
ptr[y * sizeReg[0] + x] = valueBlack;
else
ptr[y * sizeReg[0] + x] = valueWhite;
}
}
}
class ViewOriginImpl : public ViewOriginExtension
{
public:
ViewOriginImpl() = default;
uint64_t uid() const override
{
// to get a unique identifier, we use the UidGenerator class
return UidGenerator::generate();
}
size_t parentCount() const override
{
return 0; // no parent since the image is generated
}
std::shared_ptr<ViewOriginExtension> parent(size_t idx) const override { throw Error("No parent available"); }
ViewDataOrigin dataOrigin() const override
{
return ViewDataOrigin::GENERATED; // data are generated
}
std::string displayName() const override
{
return "Checkerboard"; // display name of the view
}
};
std::shared_ptr<Extension> extension(size_t id) override
{
// extensions are identified by an ID provided by the extension itself
if (id == ViewOriginExtension::EXTENSION_ID)
return std::make_shared<ViewOriginImpl>();
else
throw Error("Extension not available");
}
private:
VectorXu64 m_shape; // shape of the whole board
VectorXu64 m_tileSize; // size of each tile
std::shared_ptr<ImageProperties> m_properties;
};
// Display the content of uint8_t ImageView .
static void
displayImageContent(std::shared_ptr<ImageView> image)
{
const VectorXu64& shape = image->shape();
RegionXu64 fullRegion = RegionXu64::createFullRegion(image->shape());
std::vector<uint8_t> buffer(fullRegion.elementCount());
image->readRegion(fullRegion, buffer.data());
std::cout << "Image content: " << std::endl;
for (size_t j = 0; j < shape[1]; ++j)
{
for (size_t i = 0; i < shape[0]; ++i)
{
// use the indexer to access the pixel value
std::cout << std::setw(1) << static_cast<size_t>(buffer[i + j * shape[0]]) << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
int
main(int argc, char** argv)
{
// Create a checkerboard image with 8x8 tiles
// IOLink always manipulate shared pointers to images
std::shared_ptr<ImageView> checkerboard = std::make_shared<CheckerboardImageView>(20, 20, 4, 4);
// display some information about the image
std::cout << "Checkerboard image:" << std::endl;
std::cout << checkerboard->toString() << std::endl;
// display properties
std::cout << checkerboard->properties()->toString() << std::endl;
// display the view origin information
std::cout << checkerboard->viewOrigin()->toString() << std::endl;
// display image content
displayImageContent(checkerboard);
// extract a sub-region of this image
// no data is duplicated
RegionXu64 subRegion(VectorXu64{3, 3}, VectorXu64{9, 9});
std::shared_ptr<ImageView> subCheckerboard = ImageViewFactory::extractRegion(checkerboard, subRegion);
// display sub-image content
displayImageContent(subCheckerboard);
return EXIT_SUCCESS;
}
std::string displayName() const override
Returns the name of the current view to display.
Definition customImageView.cpp:122
size_t parentCount() const override
Returns the count of parents used to create the current view.
Definition customImageView.cpp:110
ViewDataOrigin dataOrigin() const override
Returns the data origin of current view.
Definition customImageView.cpp:117
uint64_t uid() const override
Returns an unique identifier for current view.
Definition customImageView.cpp:104
std::shared_ptr< ViewOriginExtension > parent(size_t idx) const override
Returns, for the given index, the viewOrigin extension of the parent used to create the current view.
Definition customImageView.cpp:115
Definition customImageView.cpp:21
std::shared_ptr< const ImageProperties > properties() override
Return the view's properties.
Definition customImageView.cpp:52
std::shared_ptr< const MetadataNode > metadata() const override
Return the root node of the metadata attached to this image.
Definition customImageView.cpp:55
void readRegion(const RegionXu64 &region, void *dst) override
Read a region of the image into a buffer.
Definition customImageView.cpp:58
DataType dataType() override
Return the data type of the samples of this image.
Definition customImageView.cpp:42
ImageCapabilitySet capabilities() const override
Return the capabilities of this image.
Definition customImageView.cpp:44
VectorXu64 & shape() override
Return the shape of the image, each component containing the size in this dimension.
Definition customImageView.cpp:39