LibCarna Version 3.4.0
Loading...
Searching...
No Matches
VolumeGridHelper.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010 - 2016 Leonid Kostrykin
3 *
4 * Chair of Medical Engineering (mediTEC)
5 * RWTH Aachen University
6 * Pauwelsstr. 20
7 * 52074 Aachen
8 * Germany
9 *
10 *
11 * Copyright (C) 2021 - 2025 Leonid Kostrykin
12 *
13 */
14
15#ifndef VOLUMEGRIDHELPER_H_6014714286
16#define VOLUMEGRIDHELPER_H_6014714286
17
19#include <LibCarna/LibCarna.hpp>
26#include <memory>
27#include <cmath>
28
34namespace LibCarna
35{
36
37namespace helpers
38{
39
40
41
42// ----------------------------------------------------------------------------------
43// VolumeGridHelperBase
44// ----------------------------------------------------------------------------------
45
52{
53
54public:
55
60 const static std::size_t DEFAULT_MAX_SEGMENT_BYTESIZE = 2 * 300 * 300 * 300;
61
67 VolumeGridHelperBase( const base::math::Vector3ui& nativeResolution );
68
73
78
85 virtual void releaseGeometryFeatures() = 0;
86
90 struct LIBCARNA Spacing
91 {
95 explicit Spacing( const base::math::Vector3f& units );
96
101 };
102
106 struct LIBCARNA Extent
107 {
111 explicit Extent( const base::math::Vector3f& units );
112
117 };
118
133 virtual base::Node* createNode( unsigned int geometryType, const Spacing& spacing ) const = 0;
134
149 virtual base::Node* createNode( unsigned int geometryType, const Extent& extent ) const = 0;
150
153 template< typename LoadIntensitiesFunction >
154 void loadIntensities( const LoadIntensitiesFunction& intensityData );
155
156protected:
157
163 virtual void loadIntensities( const std::function< float( const base::math::Vector3ui& ) >& intensityData ) = 0;
164
165}; // VolumeGridHelperBase
166
167
168template< typename LoadIntensitiesFunction >
169void VolumeGridHelperBase::loadIntensities( const LoadIntensitiesFunction& intensityData )
170{
171 loadIntensities( static_cast< const std::function< float( const base::math::Vector3ui& ) >& >
172 (
173 [&intensityData]( const base::math::Vector3ui& loc ) -> float
174 {
175 return intensityData( loc );
176 }
177 )
178 );
179}
180
181
182
183// ----------------------------------------------------------------------------------
184// VolumeGridHelper
185// ----------------------------------------------------------------------------------
186
217template< typename SegmentIntensityVolumeType, typename SegmentNormalsVolumeType >
219 : public VolumeGridHelperBase
220 , public details::VolumeGridHelper::IntensityComponent< SegmentIntensityVolumeType, SegmentNormalsVolumeType >
221 , public details::VolumeGridHelper:: NormalsComponent< SegmentIntensityVolumeType, SegmentNormalsVolumeType >
222{
223
225
227 typedef details::VolumeGridHelper:: NormalsComponent< SegmentIntensityVolumeType, SegmentNormalsVolumeType > NormalsComponent;
228
232 std::unique_ptr< base::VolumeGrid< SegmentIntensityVolumeType, SegmentNormalsVolumeType > > myGrid;
233
234public:
235
236 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
237
251
255 const std::size_t maxSegmentBytesize;
256
261
266
271
276
281
291 virtual void releaseGeometryFeatures() override;
292
297
298 virtual base::Node* createNode( unsigned int geometryType, const Spacing& spacing ) const override;
299
300 virtual base::Node* createNode( unsigned int geometryType, const Extent& extent ) const override;
301
303
304protected:
305
306 virtual base::math::Vector3ui gridResolution() const override;
307
319 virtual void loadIntensities( const std::function< float( const base::math::Vector3ui& ) >& intensityData ) override;
320
321private:
322
324 ( unsigned int geometryType
325 , const Spacing& spacing
326 , const Extent& extent ) const;
327
328 static base::math::Vector3ui computeMaxSegmentSize
330 , std::size_t maxSegmentBytesize );
331
332}; // VolumeGridHelper
333
334
335template< typename SegmentIntensityVolumeType, typename SegmentNormalsVolumeType >
337 ( const base::math::Vector3ui& nativeResolution, std::size_t maxSegmentBytesize )
338{
339 const float maxSideLengthF = std::pow
340 ( maxSegmentBytesize / static_cast< float >( sizeof( typename SegmentIntensityVolumeType::Voxel ) ), 1.f / 3 );
341 const unsigned int maxSideLength = base::math::makeEven( base::math::round_ui( maxSideLengthF ), -1 );
342
343 /* We subtract the redundant texels from effective segment size.
344 * Note that this causes the effective maximum segment size to be odd.
345 */
346 return base::math::Vector3ui( maxSideLength - 1, maxSideLength - 1, maxSideLength - 1 );
347}
348
349
350template< typename SegmentIntensityVolumeType, typename SegmentNormalsVolumeType >
352 ( const base::math::Vector3ui& nativeResolution
353 , std::size_t maxSegmentBytesize )
354 : VolumeGridHelperBase( nativeResolution )
355 , maxSegmentBytesize( maxSegmentBytesize )
356 , maxSegmentSize( computeMaxSegmentSize( nativeResolution, maxSegmentBytesize ) )
357 , partitioningX( nativeResolution.x(), maxSegmentSize.x() )
358 , partitioningY( nativeResolution.y(), maxSegmentSize.y() )
359 , partitioningZ( nativeResolution.z(), maxSegmentSize.z() )
360 , resolution( partitioningX.totalSize(), partitioningY.totalSize(), partitioningZ.totalSize() )
361{
362 const base::math::Vector3ui segmentCounts
367 NormalsComponent::setGrid( *myGrid );
368
369 LIBCARNA_FOR_VECTOR3UI( segmentCoord, myGrid->segmentCounts )
370 {
371 /* Here we add the redundant texels to the buffer size considerations.
372 */
373 const base::math::Vector3ui segmentSize
374 ( segmentCoord.x() + 1 == myGrid->segmentCounts.x() ? partitioningX.tailSize : partitioningX.regularPartitionSize + 1
375 , segmentCoord.y() + 1 == myGrid->segmentCounts.y() ? partitioningY.tailSize : partitioningY.regularPartitionSize + 1
376 , segmentCoord.z() + 1 == myGrid->segmentCounts.z() ? partitioningZ.tailSize : partitioningZ.regularPartitionSize + 1 );
377
378 IntensityComponent::initializeSegment( myGrid->segmentAt( segmentCoord ), segmentSize );
379 NormalsComponent ::initializeSegment( myGrid->segmentAt( segmentCoord ), segmentSize );
380 }
381}
382
383
384template< typename SegmentIntensityVolumeType, typename SegmentNormalsVolumeType >
386{
387 IntensityComponent::releaseGeometryFeatures();
388 NormalsComponent ::releaseGeometryFeatures();
389}
390
391
392template< typename SegmentIntensityVolumeType, typename SegmentNormalsVolumeType >
394 ( const std::function< float( const base::math::Vector3ui& ) >& data )
395{
396 releaseGeometryFeatures();
397 LIBCARNA_FOR_VECTOR3UI( coord, resolution )
398 {
399 const bool outOfNativeBounds
400 = coord.x() >= nativeResolution.x()
401 || coord.y() >= nativeResolution.y()
402 || coord.z() >= nativeResolution.z();
403 const float intensity = outOfNativeBounds ? 0 : data( coord );
404 myGrid->template setVoxel< typename base::VolumeGrid< SegmentIntensityVolumeType, SegmentNormalsVolumeType >::IntensitySelector >( coord, intensity );
405 }
406 NormalsComponent::computeNormals();
407}
408
409
410template< typename SegmentIntensityVolumeType, typename SegmentNormalsVolumeType >
416
417
418template< typename SegmentIntensityVolumeType, typename SegmentNormalsVolumeType >
420 ( unsigned int geometryType, const Spacing& spacing, const Extent& extent ) const
421{
422 /* Compute the extent of a regular grid segment, taking the redundant texels into account. Regular segments have
423 * `regularPartitionSize + 1` texels per dimension which is due to the redundant pixels.
424 */
425 const base::math::Vector3f regularSegmentExtent = extent.units.cwiseMin( base::math::Vector3f
426 ( spacing.units.x() * partitioningX.regularPartitionSize
427 , spacing.units.y() * partitioningY.regularPartitionSize
428 , spacing.units.z() * partitioningZ.regularPartitionSize ) );
429
430 /* Create pivot node that centers its children.
431 *
432 * Suppose the following example grid layout, where p is the absolute center and
433 * q is the center of the first segment:
434 *
435 * o-------o-------o---o
436 * | q | | |
437 * o-------o-------o---o
438 * | | p | |
439 * o-------o-------o---o
440 * | | | |
441 * o-------o-------o---o
442 *
443 * Each segment is rendered around its local center. Thus, the translation T
444 * required to center the volume geometry in the origin, corresponds to:
445 *
446 * T = -p + q
447 */
448 base::Node* const pivot = new base::Node();
449 pivot->localTransform = base::math::translation4f( ( regularSegmentExtent - extent.units ) / 2 );
450 pivot->setMovable( false );
451
452 /* Create geometry nodes for all grid segments.
453 */
454 LIBCARNA_FOR_VECTOR3UI( segmentCoord, myGrid->segmentCounts )
455 {
456 const base::VolumeSegment< SegmentIntensityVolumeType, SegmentNormalsVolumeType >& segment = myGrid->segmentAt( segmentCoord );
457
458 /* Compute extent of particular grid segment.
459 */
460 const bool isTailX = segmentCoord.x() + 1 == myGrid->segmentCounts.x();
461 const bool isTailY = segmentCoord.y() + 1 == myGrid->segmentCounts.y();
462 const bool isTailZ = segmentCoord.z() + 1 == myGrid->segmentCounts.z();
463 const base::math::Vector3ui& volumeSize = segment.intensities().size; // includes redundant pixels (only along non-tail axes)
464 const base::math::Vector3f segmentExtent
465 ( isTailX ? ( volumeSize.x() - 1 ) * spacing.units.x() : regularSegmentExtent.x()
466 , isTailY ? ( volumeSize.y() - 1 ) * spacing.units.y() : regularSegmentExtent.y()
467 , isTailZ ? ( volumeSize.z() - 1 ) * spacing.units.z() : regularSegmentExtent.z() );
468
469 /* Create geometry node for particular grid segment.
470 */
471 base::Geometry* const geom = new base::Geometry( geometryType );
472 pivot->attachChild( geom );
473 IntensityComponent::attachTexture( *geom, segment );
474 NormalsComponent ::attachTexture( *geom, segment );
475 geom->setMovable( false );
476 geom->setBoundingVolume( new base::BoundingBox( 1, 1, 1 ) );
477 geom->localTransform
479 ( segmentCoord.x() * regularSegmentExtent.x() - ( isTailX ? ( regularSegmentExtent.x() - segmentExtent.x() ) / 2 : 0 )
480 , segmentCoord.y() * regularSegmentExtent.y() - ( isTailY ? ( regularSegmentExtent.y() - segmentExtent.y() ) / 2 : 0 )
481 , segmentCoord.z() * regularSegmentExtent.z() - ( isTailZ ? ( regularSegmentExtent.z() - segmentExtent.z() ) / 2 : 0 ) )
482 * base::math::scaling4f( segmentExtent );
483 }
484
485 /* We're done.
486 */
488 , "VolumeGridHelper computed "
489 + base::text::lexical_cast< std::string >( 8 * sizeof( typename SegmentIntensityVolumeType::Voxel ) )
490 + "bit grid data using "
491 + base::text::lexical_cast< std::string >( myGrid->segmentCounts.x() ) + "×"
492 + base::text::lexical_cast< std::string >( myGrid->segmentCounts.y() ) + "×"
493 + base::text::lexical_cast< std::string >( myGrid->segmentCounts.z() ) + " segments" );
494 return pivot;
495}
496
497
498template< typename SegmentIntensityVolumeType, typename SegmentNormalsVolumeType >
500 ( unsigned int geometryType, const Spacing& spacing ) const
501{
502 const base::math::Vector3f extent = (
503 nativeResolution.cast< int >() - base::math::Vector3i( 1, 1, 1 )
504 ).cast< float >().cwiseProduct( spacing.units );
505 return createNode( geometryType, spacing, Extent( extent ) );
506}
507
508
509template< typename SegmentIntensityVolumeType, typename SegmentNormalsVolumeType >
511 ( unsigned int geometryType, const Extent& extent ) const
512{
513 const base::math::Vector3f spacing = extent.units.cast< float >().cwiseQuotient(
514 ( nativeResolution.cast< int >() - base::math::Vector3i( 1, 1, 1 ) ).cast< float >()
515 );
516 return createNode( geometryType, Spacing( spacing ), extent );
517}
518
519
520template< typename SegmentIntensityVolumeType, typename SegmentNormalsVolumeType >
522{
523 return resolution;
524}
525
526
527
528} // namespace LibCarna :: helpers
529
530} // namespace LibCarna
531
532#endif // VOLUMEGRIDHELPER_H_6014714286
Defines LibCarna::base::BoundingBox.
Defines LibCarna::base::Geometry.
Contains forward-declarations.
Defines LibCarna::base::Node.
Defines LibCarna::helpers::details::VolumeGridHelper.
Defines LibCarna::base::VolumeGrid.
Defines LibCarna::base::VolumeSegment.
Represents an association.
Defines a Geometry minimal boundary box.
Defines scene graph leafs. Instances of this class represent visible geometry that can be rendered....
Definition Geometry.hpp:63
void setBoundingVolume(BoundingVolume *boundingVolume)
Sets boundingVolume as the minimum boundary volume of this node. Supply nullptr for boundingVolume to...
@ debug
Indicates messages that might be of interest when searching bugs.
Definition Log.hpp:91
Defines the inner node of a scene graph. Implements a spatial scene element that is allowed to have c...
Definition Node.hpp:48
void attachChild(Spatial *child)
Attaches child to this node in and takes it's possession.
static Log & instance()
Returns the only instance from class InstanceType.
void setMovable(bool movable)
Sets whether this spatial may be displaced w.r.t. it's parent through user interaction....
math::Matrix4f localTransform
Defines the location, rotation and scale of this spatial in relation to it's parent....
Definition Spatial.hpp:135
Defines type-parameters-independent VolumeGridHelper base interface.
VolumeGridHelperBase(const base::math::Vector3ui &nativeResolution)
Instantiates.
static const std::size_t DEFAULT_MAX_SEGMENT_BYTESIZE
Default maximum memory size of a single segment volume, 50 megabytes approximately....
const base::math::Vector3ui nativeResolution
Holds the original resolution of the loaded data.
virtual ~VolumeGridHelperBase()
Does nothing.
virtual void releaseGeometryFeatures()=0
Releases all previously acquired textures. Invoke this method when the volume data changes.
virtual base::Node * createNode(unsigned int geometryType, const Spacing &spacing) const =0
Creates renderable representation of the underlying grid, that can be put anywhere in the scene graph...
virtual base::Node * createNode(unsigned int geometryType, const Extent &extent) const =0
Creates renderable representation of the underlying grid, that can be put anywhere in the scene graph...
virtual void loadIntensities(const std::function< float(const base::math::Vector3ui &) > &intensityData)=0
Updates the data of the volume grid.
void loadIntensities(const LoadIntensitiesFunction &intensityData)
Computes the partitioning of volumetric data and the corresponding normal map. Also creates scene nod...
const std::size_t maxSegmentBytesize
Maximum memory size of a single segment volume.
const details::VolumeGridHelper::Partionining partitioningX
Describes the partitioning along the x-axis.
const details::VolumeGridHelper::Partionining partitioningZ
Describes the partitioning along the z-axis.
virtual base::Node * createNode(unsigned int geometryType, const Spacing &spacing) const override
Creates renderable representation of the underlying grid, that can be put anywhere in the scene graph...
VolumeGridHelper(const base::math::Vector3ui &nativeResolution, std::size_t maxSegmentBytesize=DEFAULT_MAX_SEGMENT_BYTESIZE)
Creates a new base::VolumeGrid object. Initializes the segments of the grid so that the totally cover...
virtual void loadIntensities(const std::function< float(const base::math::Vector3ui &) > &intensityData) override
Updates the data of the volume grid.
const base::math::Vector3ui resolution
Holds the effective resolution, i.e. the resolution covered by the grid.
virtual void releaseGeometryFeatures() override
Releases all previously acquired textures. Invoke this method when the volume data changes,...
const base::math::Vector3ui maxSegmentSize
The maximum effective resolution of a single grid segment.
base::VolumeGrid< SegmentIntensityVolumeType, SegmentNormalsVolumeType > & grid() const
References the underlying grid.
const details::VolumeGridHelper::Partionining partitioningY
Describes the partitioning along the y-axis.
Defines the helpers::VolumeGridHelper component that maintains intensity volume data.
Defines the helpers::VolumeGridHelper component that computes and maintains normal maps.
void setGrid(base::VolumeGrid< SegmentIntensityVolumeType, SegmentNormalsVolumeType > &grid)
Sets the grid that computeNormals operates on.
Defines LibCarna::base::math namespace and LIBCARNA_FOR_VECTOR3UI.
#define LIBCARNA_FOR_VECTOR3UI(vecName, vecLimit)
Loops vecName over all where is vecLimit.
Definition math.hpp:745
Eigen::Matrix< signed int, 3, 1 > Vector3i
Defines vector.
Definition math.hpp:202
Eigen::Matrix< float, 3, 1 > Vector3f
Defines vector.
Definition math.hpp:200
ScalarType makeEven(ScalarType x, int s)
Returns if is even and if is odd, where . The data type of must be integral.
Definition math.hpp:625
unsigned int round_ui(ScalarType x)
Rounds x to the closest . Either the data type of must be unsigned or .
Definition math.hpp:598
Matrix4f translation4f(float x, float y, float z)
Returns matrix that translates homogeneous coordinates.
Definition math.hpp:275
Eigen::Matrix< unsigned int, 3, 1 > Vector3ui
Defines vector.
Definition math.hpp:203
#define NON_COPYABLE
Marks the class that it is placed in as non-copyable.
Specifies the extent of the whole dataset.
Extent(const base::math::Vector3f &units)
Instantiates.
base::math::Vector3f units
Holds the extent of the whole dataset in units.
Specifies the spacing between two succeeding voxel centers.
Spacing(const base::math::Vector3f &units)
Instantiates.
base::math::Vector3f units
Holds the spacing between two succeeding voxel centers.
Computes the partitioning that VolumeGridHelper uses along one dimension.
std::size_t partitionsCount() const
Tells the total partitions number.
std::size_t tailSize
Holds the resolution of the last partition that may also be 0.
std::size_t regularPartitionSize
Holds the always odd, effective resolution of a single regular partition.