<br>Hi Mike,<br><br>I recently observed similar results using some microscope images (in tiff format). The solution for me was to have a program input to specify the "real" pixel spacing. Those input values were given to an itkChangeInformationImageFilter and the output of that filter was fed into the resampler (along with the transform and the spacing etc. from the ChangeInformationFilter), so that everything was in "real world coordinates". The output of the resampler was sent to the image writer.<br>
<br><a href="http://www.itk.org/Doxygen316/html/classitk_1_1ChangeInformationImageFilter.html">http://www.itk.org/Doxygen316/html/classitk_1_1ChangeInformationImageFilter.html</a><br><br>Let me know if you want an example src file.<br>
<br>Take care,<br>Darren<br><br><br><br><div class="gmail_quote">On Thu, Jun 4, 2009 at 6:22 AM, Michael Jackson <span dir="ltr"><<a href="mailto:mike.jackson@bluequartz.net">mike.jackson@bluequartz.net</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">I took the code directly from the RescaleExample5.cxx and just substituted my reader class in for the "itkImageFileReader" class and I still get a black image. The code is pasted below. The general characteristics of my image are:<br>
<br>
Input Size: 1292,968 (pixels)<br>
Input Origin: 46978.9,48347.8 (Microns)<br>
Input Spacing: 0.207987,0.207987 (Microns/pixel)<br>
Image Center: 47113.3,48448.5 (Microns)<br>
<br>
Is it possible my itkR3DImageIO class is not setting something correctly?<div class="im"><br>
<br>
const unsigned int Dimension = 2;<br>
typedef unsigned char InputPixelType;<br>
typedef unsigned char OutputPixelType;<br>
<br>
typedef itk::Image< InputPixelType, Dimension > InputImageType;<br>
typedef itk::Image< OutputPixelType, Dimension > OutputImageType;<br>
<br></div>
//typedef itk::ImageFileReader< InputImageType > ReaderType;<br>
typedef itkR3DImageIO ReaderType;<div class="im"><br>
typedef itk::ImageFileWriter< OutputImageType > WriterType;<br>
<br>
ReaderType::Pointer reader = ReaderType::New();<br>
WriterType::Pointer writer = WriterType::New();<br>
<br>
reader->SetFileName( argv[1] );<br></div>
reader->SetDatasetPath( argv[2]);<br>
writer->SetFileName( argv[3] );<br>
<br>
const double angleInDegrees = 45.0;// atof( argv[3] );<br>
const double scale = 0.5; //atof( argv[4] );<div class="im"><br>
<br>
typedef itk::ResampleImageFilter<<br>
InputImageType, OutputImageType > FilterType;<br>
<br>
FilterType::Pointer filter = FilterType::New();<br>
<br></div>
typedef itk::Similarity2DTransform< double > TransformType;<div class="im"><br>
TransformType::Pointer transform = TransformType::New();<br></div>
typedef itk::LinearInterpolateImageFunction<<div class="im"><br>
InputImageType, double > InterpolatorType;<br>
InterpolatorType::Pointer interpolator = InterpolatorType::New();<br>
<br>
filter->SetInterpolator( interpolator );<br>
<br>
filter->SetDefaultPixelValue( 0 );<br>
<br></div>
reader->Update();<div class="im"><br>
const InputImageType::SpacingType&<br>
spacing = reader->GetOutput()->GetSpacing();<br>
const InputImageType::PointType&<br>
origin = reader->GetOutput()->GetOrigin();<br>
InputImageType::SizeType size =<br>
reader->GetOutput()->GetLargestPossibleRegion().GetSize();<br>
<br>
filter->SetOutputOrigin( origin );<br>
filter->SetOutputSpacing( spacing );<br>
filter->SetSize( size );<br>
<br>
<br>
filter->SetInput( reader->GetOutput() );<br>
writer->SetInput( filter->GetOutput() );<br>
<br></div>
TransformType::InputPointType rotationCenter;<br>
rotationCenter[0] = origin[0] + spacing[0] * size[0] / 2.0;<br>
rotationCenter[1] = origin[1] + spacing[1] * size[1] / 2.0;<br>
transform->SetCenter( rotationCenter );<div class="im"><br>
const double degreesToRadians = atan(1.0) / 45.0;<br></div>
const double angle = angleInDegrees * degreesToRadians;<br>
transform->SetAngle( angle );<br>
<br>
transform->SetScale( scale );<br>
TransformType::OutputVectorType translation;<br>
<br>
translation[0] = 13.0;<br>
translation[1] = 17.0;<br>
<br>
transform->SetTranslation( translation );<div class="im"><br>
<br>
filter->SetTransform( transform );<br>
<br>
try<br>
{<br>
writer->Update();<br>
}<br>
catch( itk::ExceptionObject & excep )<br>
{<br></div>
std::cerr << "Exception catched !" << std::endl;<div class="im"><br>
std::cerr << excep << std::endl;<br>
}<br>
return EXIT_SUCCESS;<br></div><div class="im">
_________________________________________________________<br>
Mike Jackson <a href="mailto:mike.jackson@bluequartz.net" target="_blank">mike.jackson@bluequartz.net</a><br>
BlueQuartz Software <a href="http://www.bluequartz.net" target="_blank">www.bluequartz.net</a><br>
Principal Software Engineer Dayton, Ohio<br>
<br>
<br>
<br></div><div class="im">
On Jun 3, 2009, at 8:42 PM, Luis Ibanez wrote:<br>
<br>
</div><div><div></div><div class="h5"><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<br>
<br>
Hi Michael,<br>
<br>
<br>
We define as "Origin" of an image the physical coordinates of its<br>
pixel with index [0,0,0].<br>
<br>
Rotations, are performed by default, with respect to the origin<br>
of the coordinate system (the point with physical coordinates<br>
(0.0, 0.0, 0.0), which doesn't have to coincide with the first<br>
pixel of the image, nor with the central pixel of the image.<br>
<br>
In ITK we assume that your image is a representation of some<br>
physical reality (for example a patient's body), and therefore<br>
all transformations should be performed in the context of the<br>
physical coordinates, not the grid of pixels.<br>
<br>
The purpose of the "Origin" is that if you use your physical<br>
image acquisition device (microscope, telescope, CT scanner,<br>
MRI scanner, ultrasound device, lidar...) and you acquire<br>
images of different sections of an object that has a physical<br>
manifestation in the real world, then you should be able to<br>
recreate a mosaic of such real object by simply placing the<br>
images in a common coordinate system according to the coordinates<br>
of their origin.<br>
<br>
<br>
----<br>
<br>
<br>
In order to understand the behavior of the transformations,<br>
you should think of your image in the context of the physical<br>
coordinate system.<br>
<br>
If you want your image to rotate around the one of the pixel<br>
in one of the image corners the you should do the following:<br>
<br>
<br>
A) Compute the Index of that pixel<br>
<br>
B) Call image->TransformIndexToPhysicalPoint( index, point )<br>
to compute the physical coordinates corresponding to this<br>
pixel. This transformation will take into account the<br>
image origin, pixel spacing and image orientation.<br>
<br>
C) Call transform->SetCenter( point )<br>
to tell the transform that you want to use this point<br>
as the center of rotation.<br>
<br>
D) Connect the transform to the resample filter.<br>
<br>
E) call Update() in the resample filter.<br>
<br>
<br>
<br>
Please let us know if you still find any problem,<br>
<br>
<br>
Thanks,<br>
<br>
<br>
Luis<br>
<br>
<br>
<br>
---------------------------<br>
Michael Jackson wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Just to follow up with this, If I force my origins to be (0,0) then the rotation seems to work. So I guess I am not understanding what exactly the origins are? I have reread through several sections of the ITK guide and I thought I had it figured out. The origins of where the image is taken is actually stored in our data files so I just thought I would use that. The values are in Microns and are typically around the 48,000 to 50,000 range.<br>
Is there an implicit units (like mm) in vtkImage that I don't know about? I just can not get this figured out.<br>
Explanations are truly appreciated at this point.<br>
_________________________________________________________<br>
Mike Jackson <a href="mailto:mike.jackson@bluequartz.net" target="_blank">mike.jackson@bluequartz.net</a><br>
BlueQuartz Software <a href="http://www.bluequartz.net" target="_blank">www.bluequartz.net</a><br>
Principal Software Engineer Dayton, Ohio<br>
On Jun 3, 2009, at 5:50 PM, Michael Jackson wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
I am trying to rotate an image about the "upper left" corner. I had to write my own ImageSource derived class to read the data from and HDF5 file. I am pretty sure the "Hdf5 reader" works as I can create the ImageReader instance from it, read an image and write the image to disk as a tiff file.<br>
<br>
Where my code seems to be failing is in the application of an AffineTransformFilter. I am basically taking the code straight from one of the examples adapting it to use my ImageSource derived reader and running it. And I get the dreaded "black image". Here is the code and the output from the program. Oddly, if I switch the reader back to the usual ImageFileReader and read up a tiff image I get the correct result, so maybe my custom reader class is not quite correct?<br>
<br>
<br>
#define USE_MXA_FILE 1<br>
int main(int argc, char **argv) {<br>
int exampleAction =0;<br>
const unsigned int Dimension = 2;<br>
typedef unsigned char InputPixelType;<br>
typedef unsigned char OutputPixelType;<br>
<br>
typedef itk::Image< InputPixelType, Dimension > InputImageType;<br>
typedef itk::Image< OutputPixelType, Dimension > OutputImageType;<br>
<br>
#if USE_MXA_FILE<br>
typedef itkR3DImageIO ReaderType;<br>
#else<br>
typedef itk::ImageFileReader< InputImageType > ReaderType;<br>
#endif<br>
typedef itk::ImageFileWriter< OutputImageType > WriterType;<br>
<br>
ReaderType::Pointer reader = ReaderType::New();<br>
WriterType::Pointer writer = WriterType::New();<br>
<br>
reader->SetFileName( argv[1] );<br>
#if USE_MXA_FILE<br>
reader->SetDatasetPath(argv[2]);<br>
#endif<br>
reader->Update();<br>
writer->SetFileName( argv[3]);<br>
typedef itk::ResampleImageFilter<InputImageType, OutputImageType > FilterType;<br>
FilterType::Pointer filter = FilterType::New();<br>
typedef itk::AffineTransform< double, Dimension > TransformType;<br>
TransformType::Pointer transform = TransformType::New();<br>
<br>
typedef itk::NearestNeighborInterpolateImageFunction<InputImageType, double > InterpolatorType;<br>
InterpolatorType::Pointer interpolator = InterpolatorType::New();<br>
filter->SetInterpolator( interpolator );<br>
filter->SetDefaultPixelValue( 0 );<br>
const InputImageType::SpacingType& spacing = reader->GetOutput()- >GetSpacing();<br>
const InputImageType::PointType& origin = reader->GetOutput()- >GetOrigin();<br>
InputImageType::SizeType size = reader->GetOutput()- >GetLargestPossibleRegion().GetSize();<br>
filter->SetOutputOrigin( origin );<br>
filter->SetOutputSpacing( spacing );<br>
filter->SetSize( size );<br>
<br>
filter->SetInput( reader->GetOutput() );<br>
writer->SetInput( filter->GetOutput() );<br>
<br>
std::cout << "Input Size: " << size[0] << "," << size[1] << std::endl;<br>
std::cout << "Input Origin: " << origin[0] << "," << origin[1] << std::endl;<br>
std::cout << "Input Spacing: " << spacing[0] << "," << spacing[1] << std::endl;<br>
<br>
TransformType::OutputVectorType translation1;<br>
translation1[0] = -origin[0];<br>
translation1[1] = -origin[1];<br>
transform->Translate( translation1 );<br>
<br>
const double degreesToRadians = atan(1.0) / 45.0;<br>
transform->Rotate2D( -10.0 * degreesToRadians, false );<br>
<br>
TransformType::OutputVectorType translation2;<br>
translation2[0] = origin[0];<br>
translation2[1] = origin[1];<br>
transform->Translate( translation2, false );<br>
filter->SetTransform( transform );<br>
try<br>
{<br>
writer->Update();<br>
}<br>
catch( itk::ExceptionObject & excep )<br>
{<br>
std::cerr << "Exception caught !" << std::endl;<br>
std::cerr << excep << std::endl;<br>
}<br>
<br>
return EXIT_SUCCESS;<br>
}<br>
<br>
<br>
output:<br>
GenerateData()<br>
GenerateData()<br>
Input Size: 1292,968<br>
Input Origin: 46978.9,48347.8<br>
Input Spacing: 0.207987,0.207987<br>
GenerateData()<br>
<br>
Any help would be great.<br>
_________________________________________________________<br>
Mike Jackson <a href="mailto:mike.jackson@bluequartz.net" target="_blank">mike.jackson@bluequartz.net</a><br>
BlueQuartz Software <a href="http://www.bluequartz.net" target="_blank">www.bluequartz.net</a><br>
Principal Software Engineer Dayton, Ohio<br>
<br>
<br>
<br>
</blockquote>
_____________________________________<br>
Powered by <a href="http://www.kitware.com" target="_blank">www.kitware.com</a><br>
Visit other Kitware open-source projects at<br>
<a href="http://www.kitware.com/opensource/opensource.html" target="_blank">http://www.kitware.com/opensource/opensource.html</a><br>
Please keep messages on-topic and check the ITK FAQ at: <a href="http://www.itk.org/Wiki/ITK_FAQ" target="_blank">http://www.itk.org/Wiki/ITK_FAQ</a><br>
Follow this link to subscribe/unsubscribe:<br>
<a href="http://www.itk.org/mailman/listinfo/insight-users" target="_blank">http://www.itk.org/mailman/listinfo/insight-users</a><br>
</blockquote></blockquote>
<br>
_____________________________________<br>
Powered by <a href="http://www.kitware.com" target="_blank">www.kitware.com</a><br>
<br>
Visit other Kitware open-source projects at<br>
<a href="http://www.kitware.com/opensource/opensource.html" target="_blank">http://www.kitware.com/opensource/opensource.html</a><br>
<br>
Please keep messages on-topic and check the ITK FAQ at: <a href="http://www.itk.org/Wiki/ITK_FAQ" target="_blank">http://www.itk.org/Wiki/ITK_FAQ</a><br>
<br>
Follow this link to subscribe/unsubscribe:<br>
<a href="http://www.itk.org/mailman/listinfo/insight-users" target="_blank">http://www.itk.org/mailman/listinfo/insight-users</a><br>
</div></div></blockquote></div><br>