Skip to content

Commit

Permalink
Merge pull request pixmeo#57 from spalte/VolumeROIAPI
Browse files Browse the repository at this point in the history
Volume ROI Classes
  • Loading branch information
rossetantoine committed Feb 15, 2015
2 parents e80898f + fe6af36 commit a39026d
Show file tree
Hide file tree
Showing 39 changed files with 2,177 additions and 813 deletions.
5 changes: 4 additions & 1 deletion OsiriXClasses/CPR/CPRGeneratorRequest.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@
N3Vector _origin;
N3Vector _directionX;
N3Vector _directionY;

N3Vector _directionZ;

CGFloat _pixelSpacingX;
CGFloat _pixelSpacingY;

Expand All @@ -110,8 +111,10 @@
@property (nonatomic, readwrite, assign) N3Vector origin;
@property (nonatomic, readwrite, assign) N3Vector directionX;
@property (nonatomic, readwrite, assign) N3Vector directionY;
@property (nonatomic, readwrite, assign) N3Vector directionZ; // if this is N3VectorZero, it defaults to the cross product of the X and Y directions
@property (nonatomic, readwrite, assign) CGFloat pixelSpacingX; // mm/pixel
@property (nonatomic, readwrite, assign) CGFloat pixelSpacingY;
@property (nonatomic, readwrite, assign) CGFloat pixelSpacingZ; // maps to slabSampleDistance

@property (nonatomic, readwrite, assign) CPRProjectionMode projectionMode;

Expand Down
3 changes: 2 additions & 1 deletion OsiriXClasses/CPR/CPRGeneratorRequest.m
Original file line number Diff line number Diff line change
Expand Up @@ -215,11 +215,12 @@ @implementation CPRObliqueSliceGeneratorRequest : CPRGeneratorRequest
@synthesize origin = _origin;
@synthesize directionX = _directionX;
@synthesize directionY = _directionY;
@synthesize directionZ = _directionZ;
@synthesize pixelSpacingX = _pixelSpacingX;
@synthesize pixelSpacingY = _pixelSpacingY;
@synthesize pixelSpacingZ = _slabSampleDistance;
@synthesize projectionMode = _projectionMode;


+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key
{
NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
Expand Down
56 changes: 23 additions & 33 deletions OsiriXClasses/CPR/CPRHorizontalFillOperation.m
Original file line number Diff line number Diff line change
Expand Up @@ -111,24 +111,19 @@ - (void)_linearInterpolatingFill
vectorTransform.m41 = vectorTransform.m42 = vectorTransform.m43 = 0.0;
N3VectorApplyTransformToVectors(vectorTransform, volumeNormals, _width);

if ([_volumeData aquireInlineBuffer:&inlineBuffer]) {
for (y = 0; y < _height; y++) {
if ([self isCancelled]) {
break;
}

for (x = 0; x < _width; x++) {
_floatBytes[y*_width + x] = CPRVolumeDataLinearInterpolatedFloatAtVolumeVector(&inlineBuffer, volumeVectors[x]);
}

N3VectorAddVectors(volumeVectors, volumeNormals, _width);
}
} else {
memset(_floatBytes, 0, _height * _width * sizeof(float));
[_volumeData aquireInlineBuffer:&inlineBuffer];
for (y = 0; y < _height; y++) {
if ([self isCancelled]) {
break;
}

for (x = 0; x < _width; x++) {
_floatBytes[y*_width + x] = CPRVolumeDataLinearInterpolatedFloatAtVolumeVector(&inlineBuffer, volumeVectors[x]);
}

N3VectorAddVectors(volumeVectors, volumeNormals, _width);
}

[_volumeData releaseInlineBuffer:&inlineBuffer];

free(volumeVectors);
free(volumeNormals);
}
Expand All @@ -152,24 +147,19 @@ - (void)_nearestNeighborFill
vectorTransform.m41 = vectorTransform.m42 = vectorTransform.m43 = 0.0;
N3VectorApplyTransformToVectors(vectorTransform, volumeNormals, _width);

if ([_volumeData aquireInlineBuffer:&inlineBuffer]) {
for (y = 0; y < _height; y++) {
if ([self isCancelled]) {
break;
}

for (x = 0; x < _width; x++) {
_floatBytes[y*_width + x] = CPRVolumeDataNearestNeighborInterpolatedFloatAtVolumeVector(&inlineBuffer, volumeVectors[x]);
}

N3VectorAddVectors(volumeVectors, volumeNormals, _width);
}
} else {
memset(_floatBytes, 0, _height * _width * sizeof(float));
[_volumeData aquireInlineBuffer:&inlineBuffer];
for (y = 0; y < _height; y++) {
if ([self isCancelled]) {
break;
}

for (x = 0; x < _width; x++) {
_floatBytes[y*_width + x] = CPRVolumeDataNearestNeighborInterpolatedFloatAtVolumeVector(&inlineBuffer, volumeVectors[x]);
}

N3VectorAddVectors(volumeVectors, volumeNormals, _width);
}

[_volumeData releaseInlineBuffer:&inlineBuffer];


free(volumeVectors);
free(volumeNormals);
}
Expand Down
5 changes: 4 additions & 1 deletion OsiriXClasses/CPR/CPRMPRDCMView.m
Original file line number Diff line number Diff line change
Expand Up @@ -2679,7 +2679,10 @@ - (N3AffineTransform)pixToDicomTransform // converts points in the DCMPix's coor
pixToDicomTransform.m31 = orientation[6];
pixToDicomTransform.m32 = orientation[7];
pixToDicomTransform.m33 = orientation[8];


// Because Dicom uses Center rule and DCMPix uses Top-Left Rule
pixToDicomTransform = N3AffineTransformConcat(N3AffineTransformMakeTranslation(-.5, -.5, 0), pixToDicomTransform);

#ifndef NDEBUG
if( isnan( pix.pixelSpacingX) || isnan( pix.pixelSpacingY) || pix.pixelSpacingX <= 0 || pix.pixelSpacingY <= 0 || pix.pixelSpacingX > 1000 || pix.pixelSpacingY > 1000)
NSLog( @"******* CPR pixel spacing incorrect for pixToSubDrawRectTransform");
Expand Down
22 changes: 17 additions & 5 deletions OsiriXClasses/CPR/CPRObliqueSliceOperation.m
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,12 @@ - (void)main
origin = self.request.origin;
leftDirection = N3VectorScalarMultiply(N3VectorNormalize(self.request.directionX), self.request.pixelSpacingX);
downDirection = N3VectorScalarMultiply(N3VectorNormalize(self.request.directionY), self.request.pixelSpacingY);
inSlabNormal = N3VectorScalarMultiply(N3VectorNormalize(N3VectorCrossProduct(leftDirection, downDirection)), [self _slabSampleDistance]);

if (N3VectorEqualToVector(self.request.directionZ, N3VectorZero)) {
inSlabNormal = N3VectorScalarMultiply(N3VectorNormalize(N3VectorCrossProduct(leftDirection, downDirection)), [self _slabSampleDistance]);
} else {
inSlabNormal = N3VectorScalarMultiply(N3VectorNormalize(self.request.directionZ), [self _slabSampleDistance]);
}

_floatBytes = malloc(sizeof(float) * pixelsWide * pixelsHigh * pixelsDeep);
vectors = malloc(sizeof(N3Vector) * pixelsWide);
fillVectors = malloc(sizeof(N3Vector) * pixelsWide);
Expand Down Expand Up @@ -311,7 +315,11 @@ - (CGFloat)_slabSampleDistance

- (NSUInteger)_pixelsDeep
{
return MAX(self.request.slabWidth / [self _slabSampleDistance], 0) + 1;
#if CGFLOAT_IS_DOUBLE
return MAX(round(self.request.slabWidth / [self _slabSampleDistance]), 1.0);
#else
return MAX(roundf(self.request.slabWidth / [self _slabSampleDistance]), 1.0f);
#endif
}

- (N3AffineTransform)_generatedVolumeTransform
Expand All @@ -324,8 +332,12 @@ - (N3AffineTransform)_generatedVolumeTransform

leftDirection = N3VectorScalarMultiply(N3VectorNormalize(self.request.directionX), self.request.pixelSpacingX);
downDirection = N3VectorScalarMultiply(N3VectorNormalize(self.request.directionY), self.request.pixelSpacingY);
inSlabNormal = N3VectorScalarMultiply(N3VectorNormalize(N3VectorCrossProduct(leftDirection, downDirection)), [self _slabSampleDistance]);

if (N3VectorEqualToVector(self.request.directionZ, N3VectorZero)) {
inSlabNormal = N3VectorScalarMultiply(N3VectorNormalize(N3VectorCrossProduct(leftDirection, downDirection)), [self _slabSampleDistance]);
} else {
inSlabNormal = N3VectorScalarMultiply(N3VectorNormalize(self.request.directionZ), [self _slabSampleDistance]);
}

volumeOrigin = N3VectorAdd(self.request.origin, N3VectorScalarMultiply(inSlabNormal, (CGFloat)([self _pixelsDeep] - 1)/-2.0));

volumeTransform = N3AffineTransformIdentity;
Expand Down
64 changes: 31 additions & 33 deletions OsiriXClasses/CPR/CPRProjectionOperation.m
Original file line number Diff line number Diff line change
Expand Up @@ -63,39 +63,37 @@ - (void)main
pixelsPerPlane = _volumeData.pixelsWide * _volumeData.pixelsHigh;
floatBytes = malloc(sizeof(float) * pixelsPerPlane);

if ([_volumeData aquireInlineBuffer:&inlineBuffer]) {
memcpy(floatBytes, CPRVolumeDataFloatBytes(&inlineBuffer), sizeof(float) * pixelsPerPlane);
switch (_projectionMode) {
case CPRProjectionModeMIP:
for (i = 1; i < _volumeData.pixelsDeep; i++) {
if ([self isCancelled]) {
break;
}
vDSP_vmax(floatBytes, 1, (float *)CPRVolumeDataFloatBytes(&inlineBuffer) + (i * pixelsPerPlane), 1, floatBytes, 1, pixelsPerPlane);
}
break;
case CPRProjectionModeMinIP:
for (i = 1; i < _volumeData.pixelsDeep; i++) {
if ([self isCancelled]) {
break;
}
vDSP_vmin(floatBytes, 1, (float *)CPRVolumeDataFloatBytes(&inlineBuffer) + (i * pixelsPerPlane), 1, floatBytes, 1, pixelsPerPlane);
}
break;
case CPRProjectionModeMean:
for (i = 1; i < _volumeData.pixelsDeep; i++) {
if ([self isCancelled]) {
break;
}
floati = i;
vDSP_vavlin((float *)CPRVolumeDataFloatBytes(&inlineBuffer) + (i * pixelsPerPlane), 1, &floati, floatBytes, 1, pixelsPerPlane);
}
break;
default:
break;
}
}
[_volumeData releaseInlineBuffer:&inlineBuffer];
[_volumeData aquireInlineBuffer:&inlineBuffer];
memcpy(floatBytes, CPRVolumeDataFloatBytes(&inlineBuffer), sizeof(float) * pixelsPerPlane);
switch (_projectionMode) {
case CPRProjectionModeMIP:
for (i = 1; i < _volumeData.pixelsDeep; i++) {
if ([self isCancelled]) {
break;
}
vDSP_vmax(floatBytes, 1, (float *)CPRVolumeDataFloatBytes(&inlineBuffer) + (i * pixelsPerPlane), 1, floatBytes, 1, pixelsPerPlane);
}
break;
case CPRProjectionModeMinIP:
for (i = 1; i < _volumeData.pixelsDeep; i++) {
if ([self isCancelled]) {
break;
}
vDSP_vmin(floatBytes, 1, (float *)CPRVolumeDataFloatBytes(&inlineBuffer) + (i * pixelsPerPlane), 1, floatBytes, 1, pixelsPerPlane);
}
break;
case CPRProjectionModeMean:
for (i = 1; i < _volumeData.pixelsDeep; i++) {
if ([self isCancelled]) {
break;
}
floati = i;
vDSP_vavlin((float *)CPRVolumeDataFloatBytes(&inlineBuffer) + (i * pixelsPerPlane), 1, &floati, floatBytes, 1, pixelsPerPlane);
}
break;
default:
break;
}

volumeTransform = N3AffineTransformConcat(_volumeData.volumeTransform, N3AffineTransformMakeScale(1.0, 1.0, 1.0/(CGFloat)_volumeData.pixelsDeep));
_generatedVolume = [[CPRVolumeData alloc] initWithFloatBytesNoCopy:floatBytes pixelsWide:_volumeData.pixelsWide pixelsHigh:_volumeData.pixelsHigh pixelsDeep:1
Expand Down
13 changes: 4 additions & 9 deletions OsiriXClasses/CPR/CPRStraightenedView.m
Original file line number Diff line number Diff line change
Expand Up @@ -1148,15 +1148,10 @@ - (void)generator:(CPRGenerator *)generator didGenerateVolume:(CPRVolumeData *)v

for (i = 0; i < self.curvedVolumeData.pixelsDeep; i++)
{
if ([self.curvedVolumeData aquireInlineBuffer:&inlineBuffer]) {
newPix = [[DCMPix alloc] initWithData:(float *)CPRVolumeDataFloatBytes(&inlineBuffer) + (i*self.curvedVolumeData.pixelsWide*self.curvedVolumeData.pixelsHigh) :32
:self.curvedVolumeData.pixelsWide :self.curvedVolumeData.pixelsHigh :self.curvedVolumeData.pixelSpacingX :self.curvedVolumeData.pixelSpacingY
:0.0 :0.0 :0.0 :NO];
} else {
assert(0);
newPix = [[DCMPix alloc] init];
}
[self.curvedVolumeData releaseInlineBuffer:&inlineBuffer];
[self.curvedVolumeData aquireInlineBuffer:&inlineBuffer];
newPix = [[DCMPix alloc] initWithData:(float *)CPRVolumeDataFloatBytes(&inlineBuffer) + (i*self.curvedVolumeData.pixelsWide*self.curvedVolumeData.pixelsHigh) :32
:self.curvedVolumeData.pixelsWide :self.curvedVolumeData.pixelsHigh :self.curvedVolumeData.pixelSpacingX :self.curvedVolumeData.pixelSpacingY
:0.0 :0.0 :0.0 :NO];

[newPix setImageObjectID: [[[self windowController] originalPix] imageObjectID]];
[newPix setSourceFile: [[[self windowController] originalPix] sourceFile]];
Expand Down
13 changes: 4 additions & 9 deletions OsiriXClasses/CPR/CPRStretchedView.m
Original file line number Diff line number Diff line change
Expand Up @@ -820,15 +820,10 @@ - (void)generator:(CPRGenerator *)generator didGenerateVolume:(CPRVolumeData *)v

for (i = 0; i < self.curvedVolumeData.pixelsDeep; i++)
{
if ([self.curvedVolumeData aquireInlineBuffer:&inlineBuffer]) {
newPix = [[DCMPix alloc] initWithData:(float *)CPRVolumeDataFloatBytes(&inlineBuffer) + (i*self.curvedVolumeData.pixelsWide*self.curvedVolumeData.pixelsHigh) :32
:self.curvedVolumeData.pixelsWide :self.curvedVolumeData.pixelsHigh :self.curvedVolumeData.pixelSpacingX :self.curvedVolumeData.pixelSpacingY
:0.0 :0.0 :0.0 :NO];
} else {
assert(0);
newPix = [[DCMPix alloc] init];
}
[self.curvedVolumeData releaseInlineBuffer:&inlineBuffer];
[self.curvedVolumeData aquireInlineBuffer:&inlineBuffer];
newPix = [[DCMPix alloc] initWithData:(float *)CPRVolumeDataFloatBytes(&inlineBuffer) + (i*self.curvedVolumeData.pixelsWide*self.curvedVolumeData.pixelsHigh) :32
:self.curvedVolumeData.pixelsWide :self.curvedVolumeData.pixelsHigh :self.curvedVolumeData.pixelSpacingX :self.curvedVolumeData.pixelSpacingY
:0.0 :0.0 :0.0 :NO];

[newPix setImageObjectID: [[[self windowController] originalPix] imageObjectID]];
[newPix setSourceFile: [[[self windowController] originalPix] sourceFile]];
Expand Down
23 changes: 7 additions & 16 deletions OsiriXClasses/CPR/CPRTransverseView.m
Original file line number Diff line number Diff line change
Expand Up @@ -604,22 +604,13 @@ - (void)generator:(CPRGenerator *)generator didGenerateVolume:(CPRVolumeData *)v

for( int i = 0; i < self.generatedVolumeData.pixelsDeep; i++)
{
if ([self.generatedVolumeData aquireInlineBuffer:&inlineBuffer])
{
newPix = [[DCMPix alloc] initWithData:(float *)CPRVolumeDataFloatBytes(&inlineBuffer) + (i*self.generatedVolumeData.pixelsWide*self.generatedVolumeData.pixelsHigh) :32
:self.generatedVolumeData.pixelsWide :self.generatedVolumeData.pixelsHigh :self.generatedVolumeData.pixelSpacingX :self.generatedVolumeData.pixelSpacingY
: -self.generatedVolumeData.pixelSpacingX*self.generatedVolumeData.pixelsWide/2.
: -self.generatedVolumeData.pixelSpacingY*self.generatedVolumeData.pixelsHigh/2.
: 0
:NO];
}
else
{
assert(0);
newPix = [[DCMPix alloc] init];
}

[self.generatedVolumeData releaseInlineBuffer:&inlineBuffer];
[self.generatedVolumeData aquireInlineBuffer:&inlineBuffer];
newPix = [[DCMPix alloc] initWithData:(float *)CPRVolumeDataFloatBytes(&inlineBuffer) + (i*self.generatedVolumeData.pixelsWide*self.generatedVolumeData.pixelsHigh) :32
:self.generatedVolumeData.pixelsWide :self.generatedVolumeData.pixelsHigh :self.generatedVolumeData.pixelSpacingX :self.generatedVolumeData.pixelSpacingY
: -self.generatedVolumeData.pixelSpacingX*self.generatedVolumeData.pixelsWide/2.
: -self.generatedVolumeData.pixelSpacingY*self.generatedVolumeData.pixelsHigh/2.
: 0
:NO];

float orientation[ 6];
[self.generatedVolumeData getOrientation:orientation];
Expand Down
Loading

0 comments on commit a39026d

Please sign in to comment.