Used if voxel coordinates are not necessary and voxel operations are local. (LUT, windowing, some color model changes, thresholding, inversion, arithmetics on voxel data, etc.).
Advantages:
Fast image data access by pointer incrementation
Short implementation
Disadvantages:
Voxel coordinates are not directly available
Neighbour voxels are only available with precautions
Not very useful for complicated algorithms
Precautions necessary because pages could reach outside the image, i.e., voxels outside the image might be processed.
Example 4.1. Implementing a Page-Based Algorithm
template <typename DATATYPE> void AddExample::calculateOutputSubImage(TSubImage<DATATYPE> *outSubImg, int /*outIndex*/, TSubImage<DATATYPE> *inSubImg1, TSubImage<DATATYPE> *inSubImg2) { // Get pointers to memory buffers of input and output subimage. DATATYPE* outSubImgVP_beg = outSubImg->getImagePointer(outSubImg->getBox().v1); DATATYPE* outSubImgVP_end = outSubImg->getImagePointer(outSubImg->getBox().v2); DATATYPE* inSubImg1VP = inSubImg1->getImagePointer(inSubImg1->getBox().v1); DATATYPE* inSubImg2VP = inSubImg2->getImagePointer(inSubImg2->getBox().v1); // Loop over all voxels in memory buffers even if pages reache outside the image. for (DATATYPE* outSubImgVP = outSubImgVP_beg; outSubImgVP <= outSubImgVP_end; outSubImgVP++, inSubImg1VP++, inSubImg2VP++) { (*outSubImgVP) = (*inSubImg1VP) + (*inSubImg2VP); } }
Useful for all pixel-based algorithms already mentioned in Section 4.2.1, “Page-Based Concept” (LUT, windowing, some color model changes,
thresholding, inversion, arithmetics) or if voxel coordinates are
essential and operations are local (rasterization of implicit Objects,
SubImage
, etc.), e.g.
mlAddExampleOp
.
Advantages:
Fast access by 6 nested loops and pointer incrementation in inner loop
Voxel coordinates are available
Conceptually good implementation, recommended for page processing
Disadvantages:
Neighbor voxels only available with precautions
Not very useful for advanced algorithms
Example 4.2. Implementing a Voxel-Based Algorithm
template <typename DATATYPE> void PosExample::calculateOutputSubImage(TSubImage<DATATYPE> *outSubImg, int outIndex, TSubImage<DATATYPE> *inSubImg) { // Get extent of output image and clamp the extent of the box of outSubImg // against // it to be sure that no voxels outside the image are processed. SubImageBox box = outSubImg->getValidRegion(); // Iterate over all valid voxels of inSubImg and outSubImg. ImageVector p = box.v1; for (p.u = box.v1.u; p.u <= box.v2.u; ++p.u) { for (p.t = box.v1.t; p.t <= box.v2.t; ++p.t) { for (p.c = box.v1.c; p.c <= box.v2.c; ++p.c) { for (p.z = box.v1.z; p.z <= box.v2.z; ++p.z) { for (p.y = box.v1.y; p.y <= box.v2.y; ++p.y) { // Get/Set position of row starts as pointers to memory // positions in inSubImg and outSubImg buffers. p.x = box.v1.x; DATATYPE* iP = inSubImg ->getImagePointer(p); DATATYPE* oP = outSubImg->getImagePointer(p); // Process all voxels in row with pointers. Be sure to // include last voxel in row with "<= box.v2.x", because // v2 is still part of box region. for (; p.x <= box.v2.x; ++p.x) { *oP = calcFromIp(p.x, *iP); // Calculate voxel from position & input ++iP; ++oP; // Move input and output pointer forward } } } } } } }
See Section 3.1.9, “Implementing calculateOutputSubImage()”, Section 7.2.3, “Examples with Registered Voxel Types” and programming examples released with MeVisLab for further examples.
Useful for arbitrary 2D algorithms. The page extent is set to
slice extent, or for calculations of an output page, the entire input
slice is requested in
calculateInputSubImageBox()
.
Advantages:
Very fast random access (with getValue/setValue or like page-based or voxel-based concept)
Easy to implement
Paging still works fine if x and y extents are not too large
Disadvantages:
PageExt == SliceExt: can easily degenerate and become very expensive (e.g., on large mammograms or satellite images), also page extent is propagated to appended images
InputTile == SliceExt, output page is normal: many slice requests become necessary to compose the output slice
Consider whether e.g., the VirtualVolume
or a kernel-based concept could replace this concept to avoid these
disadvantages.
Example 4.3. Implementing a Slice-Based Algorithm
void SliceFilter::calculateOutputImageProperties(int /*outIndex*/, PagedImage* outImage) { // Set extent of pages in z, c, t and u dimension to 1. // Thus only axial slices will be calculated by the module. // Avoid too small pages. ImageVector pExt = getInputImage(0)->getPageExtent(); if (pExt.x < 64){ pExt.x = 64; } if (pExt.y < 64){ pExt.y = 64; } outImage->setPageExtent(ImageVector(pExt.x, pExt.y, 1,1,1,1)); } SubImageBox SliceFilter::calculateInputSubImageBox(int /*inIndex*/, const SubImageBox& outSubImgBox, int /*outIndex*/) { // Request slice with image x/y extent. All other // parameters are given by the page extent. SubImageBox inBox = outSubImgBox; inBox.v1.x = 0; inBox.v1.y = 0; inBox.v2.x = getInputImage(0)->getImageExtent().x-1; inBox.v2.y = getInputImage(0)->getImageExtent().y-1; return inBox; }
An important class of image filters is based on the so-called kernel-based image filtering. This class is used when a fixed region around a voxel is needed to calculate output voxel (edge detector operations, morphological operations, noise filters, smoothing, texture filters, etc.).
Advantages:
Fast access to kernel range in 6D is possible with paging so it fits well into page concept
Many algorithm categories can be implemented
Disadvantages:
Base class is a bit more complex
Image borders require consideration (supported by base classes, though)
See Kernel Progamming for more information.
© 2024 MeVis Medical Solutions AG