Skip to content

Conversation

@adler-j
Copy link
Member

@adler-j adler-j commented Jun 20, 2018

It seems we had some minor (but notable in some cases) errors with the geometry descriptions.


# TODO: WE CURRENTLY IGNORE THE OFFSETS DUE TO FLYING FOCAL SPOT
source_offsets = np.array([offset_x, offset_y, offset_z]).T
# Make a parallel beam geometry with flat detector
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong comment

src_radius = src_radius + np.mean(offset_radial)
angles = angles - np.mean(offset_angular)

# print(np.mean(offset_angular))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove print

@kohr-h
Copy link
Member

kohr-h commented Jun 21, 2018

I guess this isn't quite ready for review yet

@adler-j
Copy link
Member Author

adler-j commented Jun 21, 2018

Its reviewable, just some minor stuff to fix.

@adler-j adler-j force-pushed the mayo_improvements branch from 219f485 to bd7cb07 Compare June 21, 2018 14:33
Copy link
Member

@kohr-h kohr-h left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not too familiar with the conventions, so I can't say anything about correctness. But still one thing I should understand but don't.


# TODO: WE CURRENTLY IGNORE THE OFFSETS DUE TO FLYING FOCAL SPOT
source_offsets = np.array([offset_x, offset_y, offset_z]).T
if 1:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this is for development only?
If not, I'm not in favor of "parking" backup code like this. Better make an issue and post the old code there for reference. It's also in the git history anyway.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll remove it.

source_offsets = np.array([offset_x, offset_y, offset_z]).T
if 1:
# Apply only mean of offsets
src_radius = src_radius + np.mean(offset_radial)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get this. How could this ever work before if it's a vector? In the old version, src_rad_offset must have been a vector, and with it all 3 offsets as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically the offsets are weird, so I decided to just go for their means. Before we did not do anything about it (src_rad_offset was unused) which gave some slight errors, since apparently the "offsets" are not zero-centered.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay. What I was puzzled about was that in the old version, src_radius became a vector (after adding offset_radial), then it was used to compute offset_[xyz], each of which also was a vector then, and the final source_offsets stacked them to a matrix. I don't see how that made sense.

Anyhow, for some other PR.

@adler-j adler-j force-pushed the mayo_improvements branch from 0cda683 to 5098fad Compare June 25, 2018 08:32
@adler-j
Copy link
Member Author

adler-j commented Jun 25, 2018

With some further small fixes, it now actually looks like this does the right thing, and there are no magic numbers!

A note to future readers (e.g myself in a year): The tags "SpiralPitchFactor" and "TableFeedPerRotation" are slightly bugged and not to be trusted.

@adler-j
Copy link
Member Author

adler-j commented Jun 28, 2018

Could use a final review on this

Copy link
Member

@aringh aringh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, but honestly I am not too familiar with the dicom format and with the mayo-data.

data_array /= 1024.0
# Convert from storage type to densities
# TODO: Optimize these computations
hu_values = (dataset.RescaleSlope * data_array +
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now I will reveal my lack of knowledge in this field: what is the difference between this hu_values and the hu_factor on line 57?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hu_values is an array (basically the image) while hu_factor is an integer specifying how to rescale values.

Basically DICOM stores everything as positive integers, and then has information on how to convert this into usable stuff by rescaling. That's what I do here. I also follow up by moving from HU values to densities (of water) since the values are much easier to work with later on.

Copy link
Member

@kohr-h kohr-h left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor comments, but largely good to go.

As before, I assume the code is correct. It does make sense on a high level.

src_radius / (src_radius + det_radius))

# Convert offset to odl defintions
offset_along_axis = (offset_along_axis +
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not +=?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to keep this as a "unified" assignment. I'd actually prefer to replace the "old" offset_along_axis to something like "mean_offset_along_axis_for_ffz". It's also more honest.

if len(datasets) > 1:
slice_distance = np.abs(
np.array(datasets[1].DataCollectionCenterPatient)[2] -
np.array(datasets[0].DataCollectionCenterPatient)[2])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

np.array shouldn't be necessary?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DataCollectionCenterPatient[2] is a string.

Although I guess float would make more sense.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, definitely. I thought it was a list.

min_pt[2] -= 0.5 * slice_distance
max_pt[2] = -np.array(datasets[-1].DataCollectionCenterPatient)[2]
max_pt[2] += 0.5 * pixel_thickness
max_pt[2] += 0.5 * slice_distance
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the overall logic of computing the min/max in the z axis? Does it go from -(patient z in dataset 0) to 0, adjusted by half a slice distance in each direction?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, maybe a comment could make that more obvious, I had to think about it for a second. Maybe also the review markup was a bit to blame.

# Apply only mean of offsets
src_radius = src_radius + np.mean(offset_radial)
offset_along_axis = np.mean(offset_axial) * (
src_radius / (src_radius + det_radius))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on why the multiplication with the magnification factor? (Which BTW would be a good name for a temp variable, to clarify things a bit.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try to write this down, but overall this really needs a whiteboard

offset_y = (np.sin(angles_offset) * (-src_rad_offset) -
np.sin(angles) * (-src_radius))
offset_z = offset_axial
# Correct the angular sampling according to corrections
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't really say anything

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

angles[0] / (2 * np.pi) * pitch)
# For unknown reasons, mayo does not include the tag
# "TableFeedPerRotation", which is what we want.
# Instead we manually compute the pitch
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great comment!


# TODO: WE CURRENTLY IGNORE THE OFFSETS DUE TO FLYING FOCAL SPOT
source_offsets = np.array([offset_x, offset_y, offset_z]).T
# TODO: Implement proper handling of flying focal spot
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about you write # TODO(adler-j)? Then people looking at this know whom to ask without doing a git blame.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do!

@adler-j
Copy link
Member Author

adler-j commented Jun 28, 2018

Fixed comments, merge after CI.

@adler-j adler-j merged commit 6a18fb0 into odlgroup:master Jun 28, 2018
@adler-j adler-j deleted the mayo_improvements branch June 28, 2018 09:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants