<div dir="ltr"><div><div><div><div><div><div><div><div>Hello Steve, Matthew and all<br><br></div>It works. The matrix inverts properly and the ROI lands exactly where it should. Thank you very much for your help.<br><br></div><div>Tiny little note: ImagePositionPatient's first two elements must be flipped too to account for the X,Y->col, row correspondence, otherwise the offset is not added properly.<br></div><div><br></div><div>Steve, thank you for the pointer to the DICOM documentation, I have gone through that a couple of times and tried to confirm my understanding with earlier questions. I think I got the gist of it but getting the elements of the matrix right was the "problem". <br><br></div><div>All the best<br></div><div>AA<br></div><div><br></div></div></div></div></div></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Sep 13, 2016 at 7:20 PM, Steve Pieper <span dir="ltr"><<a href="mailto:pieper@isomics.com" target="_blank">pieper@isomics.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Hi Athanasios - <div><br></div><div>It's very likely that your data is not sheared, which you can check by seeing if the cross product of the in plane (row and column from Image Orientation Patient) vectors is parallel to the line you have plotted (as noted before it may point the same way or the opposite way).</div><div><br></div><div>It's not clear to me from your question where you obtained the ROI , but it's also very likely that your ROI is in the same pixel space as the MR, in which case it would share the same matrix from pixel to patient spaces.  If it turns out they have different sampling grids then you may need to resample one or the other.  If the data files have valid headers this is a fairly trivial operation to do with the GUI in Slicer or you could write some code to do it. </div><div><br></div><div>Maybe the easiest if for you to read through the DICOM documentation for background.</div><div><br></div><div><a href="http://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.7.6.2" target="_blank">http://dicom.nema.org/medical/<wbr>dicom/current/output/html/<wbr>part03.html#sect_C.7.6.2</a><br></div><div><br></div><div>Hope that helps,</div><div>Steve</div></div><div class="HOEnZb"><div class="h5"><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Sep 13, 2016 at 8:58 AM, Athanasios Anastasiou <span dir="ltr"><<a href="mailto:athanastasiou@gmail.com" target="_blank">athanastasiou@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Hello Matthew & Steven<div><br></div><div>Alright, I am not sure what to make of this because the ImagePositionPatient for the part of the scan I am interested in seems to be a vector that cuts across the space diagonally. I am trying to take Steve's viewpoint here, as it looks like the "easiest" too (just rotate the "track" to align to one of the axes).</div><div><br></div><div>The values of ImagePositionPatient are:</div><div><br></div><div><div>array([[-127.773 , -105.599 ,  -94.5758],</div><div>       [-127.841 , -106.584 ,  -90.1855],</div><div>       [-127.91  , -107.569 ,  -85.7951],</div><div>       [-127.978 , -108.554 ,  -81.4048],</div><div>       [-128.046 , -109.539 ,  -77.0145],</div><div>       [-128.115 , -110.524 ,  -72.6241],</div><div>       [-128.183 , -111.509 ,  -68.2338],</div><div>       [-128.251 , -112.494 ,  -63.8435],</div><div>       [-128.32  , -113.479 ,  -59.4531],</div><div>       [-128.388 , -114.464 ,  -55.0628],</div><div>       [-128.456 , -115.449 ,  -50.6725]])</div></div><div><br></div><div>And the 3d plot of that is available further below</div><div><br></div><div><img src="cid:ii_15723892a9e9e920" alt="Inline image 1" style="margin-right:0px" height="267" width="562"></div><div><br></div><div>They are all regular (good) and all intermediate slice thicknesses are the same (double good).</div><div><br></div><div>Now, the "trouble" with this is that this represents the direction of one of the axes. Let's call it the Z axis. The other two define a plane that is perpendicular to this direction. I can rotate the axes so that this "Z" is aligned with one of the Zs in space.</div><div><br></div><div>The other thing that is a bit of a "problem" here of course is the third dimension of my ROI data. Because so far, in my preliminary tests, I have been ignoring it. This means, that just by looking at X,Y, I may have been seeing something that is distorted. And looking at this track, I may be seeing something that is thinner on the vertical projection than it really is although the increases in 2/3 axes are small.</div><div><br></div><div>Can I please ask the following:</div><div><br></div><div>1) Am I right to assume that the ROI data are perpendicular to this "track"?</div><div><br></div><div>2) All I have to do now then, is workout a rotation around Z and Y (or, 2/3 axes) to make this track parallel to one of the axes (?) and then apply that transformation to the ROIs so that, when I set them on the image (which is always properly alligned), it appears to be properly aligned. (By the looks of this, -45 deg around Z, -45 around Y and I am there.</div><div><br></div><div>3) How does the DICOM rotation data relate to this track? (If at all).</div><div><br></div><div>4) Is there an API (or part of an API) for a [DICOM Data Type].getPixel or [DICOM Data Type].getVoxel kind of operation? Even if it is via a class ecosystem that is making sense within the context of Slicer or other piece of software. The problem here is that I don't have a volumetric DICOM (Multiple images single file). I have a ROI DICOM that references individual images. So, I build my own volume aware data type (based on pydicom) that will implement its getVoxel method and is aware of a few other things I am going to be doing with these volumes. But if this is already done somewhere, maybe I could re-use it (?).</div><span><div><br></div><div>Looking forward to hearing from you<br></div><div>AA</div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div></span></div><div><div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Sep 8, 2016 at 9:37 PM, Athanasios Anastasiou <span dir="ltr"><<a href="mailto:athanastasiou@gmail.com" target="_blank">athanastasiou@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><p dir="ltr">Hello Matthew & Steven</p>
<p dir="ltr">Thank you for your email. Of course I am missing the third column :( I am paying too much attention on the two numbers I am after right now, to bring the contour right where it should be when plotting it over the image.</p>
<p dir="ltr">Thank you for your help, I will have another go at establishing the matrix with the helpful comments provided here.</p>
<p dir="ltr">All the best<span><font color="#888888"><br>
AA</font></span></p><div><div>
<div class="gmail_extra"><br><div class="gmail_quote">On 6 Sep 2016 18:25, "Matthew Brett" <<a href="mailto:matthew.brett@gmail.com" target="_blank">matthew.brett@gmail.com</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi,<br>
<br>
On Tue, Sep 6, 2016 at 6:34 AM, Steve Pieper <<a href="mailto:pieper@isomics.com" target="_blank">pieper@isomics.com</a>> wrote:<br>
> Hi Athanasios -<br>
><br>
> To get the scan direction you'll need to look at the relative<br>
> ImagePositionPatient points from slice to slice.  Note that the scan<br>
> direction is not always the cross product of the row and column orientations<br>
> since the scan may go in the other direction from a right handed cross<br>
> product or the slices can be sheared (or even at arbitrary locations)..<br>
> There are lots of other things that can happen too, like irregular spacing,<br>
> missing slices, etc, but usually just normalizing the vector between your<br>
> origin and any slice in the scan will be what you want.<br>
><br>
> This code will give you an idea:<br>
><br>
> <a href="https://github.com/Slicer/Slicer/blob/master/Modules/Scripted/DICOMPlugins/DICOMScalarVolumePlugin.py#L195-L216" rel="noreferrer" target="_blank">https://github.com/Slicer/Slic<wbr>er/blob/master/Modules/Scripte<wbr>d/DICOMPlugins/DICOMScalarVolu<wbr>mePlugin.py#L195-L216</a><br>
><br>
<br>
>From your code, you are missing a valid third column for your affine.<br>
I believe that column will be all zeros from your code. This is what<br>
the later part of the DICOM orientation page is talking about, and<br>
what Steve is referring to as the "slice direction".<br>
<br>
Steve is quite right that the slice direction need not be the<br>
cross-product of the first two, and the DICOM information can often<br>
tell you what that slice direction vector is, but assuming for a<br>
moment that it is the cross product, and that you are looking at the<br>
first slice of the volume, then you'd want something like:<br>
<br>
"""<br>
import numpy as np<br>
<br>
ImageOrientationPatient = [0.999857, 0.00390641, 0.0164496,<br>
                           -0.00741602, 0.975738, 0.218818]<br>
<br>
ImagePositionPatient = [-127.773, -105.599, -94.5758]<br>
<br>
PixelSpacing = [0.4688, 0.4688]<br>
<br>
slice_spacing = 3.0  # ?<br>
<br>
# Make F array from DICOM orientation page<br>
F = np.fliplr(np.reshape(ImageOrie<wbr>ntationPatient, (2, 3)).T)<br>
rotations = np.eye(3)<br>
rotations[:, :2] = F<br>
# Third direction cosine from cross-product of first two<br>
rotations[:, 2] = np.cross(F[:, 0], F[:, 1])<br>
# Add the zooms<br>
zooms = np.diag(PixelSpacing + [slice_spacing])<br>
<br>
# Make the affine<br>
affine = np.diag([0., 0, 0, 1])<br>
affine[:3, :3] = rotations.dot(zooms)<br>
affine[:3, 3] = ImagePositionPatient<br>
<br>
np.set_printoptions(precision=<wbr>4, suppress=True)<br>
print(affine)<br>
"""<br>
<br>
But - Steve's suggestion is more general - this code is just to give<br>
you an idea.<br>
<br>
Best,<br>
<br>
Matthew<br>
______________________________<wbr>_________________<br>
Neuroimaging mailing list<br>
<a href="mailto:Neuroimaging@python.org" target="_blank">Neuroimaging@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/neuroimaging" rel="noreferrer" target="_blank">https://mail.python.org/mailma<wbr>n/listinfo/neuroimaging</a><br>
</blockquote></div></div>
</div></div></blockquote></div><br></div>
</div></div></blockquote></div><br></div>
</div></div></blockquote></div><br></div>