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

This code demonstrates how it is possible to copy a whole ImageView content into another one.

This code demonstrates how it is possible to copy a whole ImageView content into another one.

#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>
#include <iolink/VariantDataValueFactory.h>
#include <iolink/metadata/MetadataNodeFactory.h>
#include <iolink/metadata/MetadataNodeHelper.h>
#include <iolink/view/ImageViewFactory.h>
using namespace iolink;
std::shared_ptr<ImageView>
createImageView()
{
const VectorXu64 shape = VectorXu64{10, 20, 30};
const DataType dt = DataTypeId::VEC3_UINT8;
// create an image view in CPU memory
std::shared_ptr<ImageView> image = ImageViewFactory::allocate(shape, dt);
// set some properties (not exhaustive)
image->setAxesInterpretation(AxesInterpretationId::IMAGE_SEQUENCE);
image->setImageInterpretation(ImageInterpretation::RGB);
image->setAlpha(false);
image->setSpatialOrigin(VectorXd{1.0, 2.0, 3.0});
image->setSpatialSpacing(VectorXd{0.1, 0.2, 0.3});
image->setSpatialUnit("mm");
// create some metadata
std::shared_ptr<MetadataNode> rootNode = MetadataNodeFactory::create("root", nullptr);
MetadataNodeHelper::createPath(rootNode, "level1/data1", VariantDataValueFactory::create("value1"));
MetadataNodeHelper::createPath(rootNode, "level1/data2", VariantDataValueFactory::create("value2"));
MetadataNodeHelper::createPath(rootNode, "level2/data3", VariantDataValueFactory::create("value3"));
image->setMetadata(rootNode);
// write some data (anything)
RegionXu64 fullRegion = RegionXu64::createFullRegion(shape);
std::vector<uint8_t> buffer(image->dataType().byteCount() * fullRegion.elementCount());
std::iota(buffer.begin(), buffer.end(), 0);
image->writeRegion(fullRegion, buffer.data());
return image;
}
void
copyImageView(std::shared_ptr<ImageView> imageSrc, std::shared_ptr<ImageView> imageDst)
{
// when source image origin is not controlled, we should check if we have READ capability
// this test is not mandatory, but it is a good practice to check if we can read the source image
if (!imageSrc->support(ImageCapability::READ))
{
throw std::runtime_error("Source image does not have READ capability");
}
// check if destination image has WRITE and RESHAPE capability
if (!imageDst->support(ImageCapability::WRITE | ImageCapability::RESHAPE))
{
throw std::runtime_error("Destination image does not have WRITE and RESHAPE capability");
}
// destination image is reshaped to the same shape and data type as the source image
imageDst->reshape(imageSrc->shape(), imageSrc->dataType());
// properties are copied from source to destination
imageDst->setProperties(imageSrc->properties());
// metadata are copied from source to destination
if (imageSrc->metadata())
imageDst->setMetadata(imageSrc->metadata()->clone());
// there are 2 ways to copy the content, it depends on both the source and destination capabilities
// We should theoretically also check the layout of both images, to make sure they are compatible (see Indexer)
if (imageSrc->support(ImageCapability::MEMORY_ACCESS) && imageDst->support(ImageCapability::MEMORY_ACCESS))
{
// a copy buffer to buffer is always more efficient, but only available if both images have MEMORY_ACCESS capability
size_t bufferSize = imageSrc->bufferSize();
const void* srcPtr = imageSrc->bufferReadOnly();
void* dstPtr = imageDst->buffer();
std::copy_n(reinterpret_cast<const uint8_t*>(srcPtr), bufferSize, reinterpret_cast<uint8_t*>(dstPtr));
}
else
{
// copy pixels/voxels one shot
// this is the fastest way to copy the whole image but it can require a lot of memory
// a copy chunk by chunk could be more memory efficient
RegionXu64 fullRegion = RegionXu64::createFullRegion(imageSrc->shape());
// dimension a buffer to store the whole image temporarily
std::vector<uint8_t> buffer(imageSrc->dataType().byteCount() * fullRegion.elementCount());
// read/write pixels/voxels
imageSrc->readRegion(fullRegion, buffer.data());
imageDst->writeRegion(fullRegion, buffer.data());
}
}
int
main(int argc, char** argv)
{
// create an ImageView with some content
std::shared_ptr<ImageView> imageSource = createImageView();
// create an ImageView with any shape and data type
std::shared_ptr<ImageView> imageDestination = ImageViewFactory::allocate(VectorXu64{1, 1}, DataTypeId::FLOAT);
// copy the content of the source image into the destination image
copyImageView(imageSource, imageDestination);
std::cout << imageDestination->toString() << std::endl;
std::cout << imageDestination->properties()->toString() << std::endl;
std::cout << imageDestination->metadata()->toString() << std::endl;
return EXIT_SUCCESS;
}