File Coverage

blib/lib/PDL/Demos/Transform_demo.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package PDL::Demos::Transform_demo;
2              
3 1     1   205 use PDL::Graphics::Simple;
  0            
  0            
4             use PDL::Transform;
5             require File::Spec;
6             use Carp;
7              
8             sub info {('transform', 'Coordinate transformations (Req.: PDL::Graphics::Simple)')}
9              
10             sub init {'
11             use PDL::Graphics::Simple;
12             '}
13              
14             # try and find m51.fits
15             my @f = qw(PDL Demos m51.fits);
16             our $m51file = undef;
17             foreach my $path ( @INC ) {
18             my $file = File::Spec->catfile( $path, @f );
19             if ( -f $file ) { $m51file = $file; last; }
20             }
21             confess "Unable to find m51.fits within the perl libraries.\n"
22             unless defined $m51file;
23              
24             my @demo = (
25             [comment => q|
26             This demo illustrates the PDL::Transform module.
27              
28             It requires PDL::Graphics::Simple installed and makes use of the image of
29             M51 kindly provided by the Hubble Heritage group at the
30             Space Telescope Science Institute.
31              
32             |],
33              
34             [act => q|
35             # PDL::Transform objects embody coordinate transformations.
36              
37             use PDL::Transform;
38              
39             # set up a simple linear scale-and-shift relation
40              
41             $t = t_linear( Scale=>[2,-1], Post=>[100,0]);
42             print $t;
43             |],
44              
45             [act => q|
46             # The simplest way to use PDL::Transform is to transform a set of
47             # vectors. To do this you use the "apply" method.
48              
49             # Define a few 2-vectors:
50             $xy = pdl([[0,1],[1,2],[10,3]]);
51             print "xy: ", $xy;
52              
53             # Transform the 2-vectors:
54             print "Transformed: ", $xy->apply( $t );
55             |],
56              
57             [act => q|
58             # You can invert and compose transformations with 'x' and '!'.
59             $u = t_linear( Scale=>10 ); # A new transformation (simple x10 scale)
60             $xy = pdl([[0,1],[10,3]]); # Two 2-vectors
61             print "xy: ", $xy;
62             print "xy': ", $xy->apply( !$t ); # Invert $t from earlier.
63             print "xy'': ", $xy->apply( $u x !$t ); # Hit the result with $u.
64             |],
65              
66             [act => q|
67             # PDL::Transform is useful for data resampling, and that's perhaps
68             # the best way to demonstrate it. First, we do a little bit of prep work:
69              
70             # Read in an image ($m51file has been set up by this demo to
71             # contain the location of the file). Transform is designed to
72             # work well with FITS images that contain WCS scientific coordinate
73             # information, but works equally well in pixel space.
74              
75             $m51 = rfits($|.__PACKAGE__.q|::m51file,{hdrcpy=>1});
76              
77             # we use a floating-point version of the image in some of the demos
78             # to highlight the interpolation schemes. (Note that the FITS
79             # header gets deep-copied automatically into the new variable).
80              
81             $m51_fl = $m51->float;
82              
83             # Define a nice, simple scale-by-3 transformation.
84              
85             $ts = t_scale(3);
86             |],
87              
88             [act => q|
89             #### Resampling with ->map and no FITS interpretation works in pixel space.
90              
91             ### Create a plot window, and display the original image
92             $win = pgswin( size=>[8,6], multi=>[2,2] ) ;
93             $win->plot(with=>'image', $m51, { Title=>"M51" });
94              
95             ### Grow m51 by a factor of 3; origin is at lower left
96             # (the "pix" makes the resampling happen in pixel coordinate
97             # space, ignoring the FITS header)
98              
99             $win->plot(with=>'image', $m51->map($ts, {pix=>1}),
100             { Title=>"M51 grown by 3 (pixel coords)" });
101              
102             ### Shrink m51 by a factor of 3; origin still at lower left.
103             # (You can invert the transform with a leading '!'.)
104              
105             $win->plot(with=>'image', $m51->map(!$ts, {pix=>1}),
106             { Title=>"M51 shrunk by 3 (pixel coords)" });
107             |],
108              
109             [act => q|
110             # You can work in scientific space (or any other space) by
111             # wrapping your main transformation with something that translates
112             # between the coordinates you want to act in, and the coordinates
113             # you have. Here, "t_fits" translates between pixels in the data
114             # and arcminutes in the image plane.
115              
116             $win->plot(with=>'points', pdl([1]), {title=>''}); # blank, clears
117             $win->plot(with=>'image', $m51, { Title=>"M51" });
118              
119             ### Scale in scientific coordinates.
120             # Here's a way to scale in scientific coordinates:
121             # wrap our transformation in FITS-header transforms to translate
122             # the transformation into scientific space.
123              
124             $win->plot(with=>'image', $m51->map(!$ts->wrap(t_fits($m51)), {pix=>1}),
125             { Title=>"M51 shrunk by 3 (sci. coords)" });
126             |],
127              
128             [act => q|
129             # If you don't specify "pix=>1" then the resampler works in scientific
130             # FITS coordinates (if the image has a FITS header):
131              
132             ### Scale in scientific coordinates (origin at center of galaxy)
133             $win->plot(with=>'fits', $m51->map($ts, $m51->hdr), { Title=>"M51 3x" });
134              
135             ### Instead of setting up a coordinate transformation you can use the
136             # implicit FITS header matching. Just tweak the template header:
137             $tohdr = $m51->hdr_copy;
138             $tohdr->{CDELT1} /= 3; # Magnify 3x in horiz direction
139             $tohdr->{CDELT2} /= 3; # Magnify 3x in vert direction
140              
141             ### Resample to match the new FITS header
142             # (Note that, although the image is scaled exactly the same as before,
143             # this time the scientific coordinates have scaled too.)
144             $win->plot(with=>'fits', $m51->map(t_identity(), $tohdr),
145             { Title=>"3x (FITS)" });
146             |],
147              
148             [act => q|
149             ### The three main resampling methods are "sample", "linear", and "jacobian".
150             # Sampling is fastest, linear interpolation is better. Jacobian resampling
151             # is slow but prevents aliasing under skew or reducing transformations.
152              
153             $win->plot(with=>'fits', $m51, { Title=>"M51" });
154              
155             $win->plot(with=>'fits', $m51_fl->map( $ts, $m51_fl, { method=>"sample" } ),
156             { Title=>"M51 x3 (sampled)" });
157              
158             $win->plot(with=>'fits', $m51_fl->map($ts, $m51_fl, {method=>"linear"}),
159             { Title=>"M51 x3 (interp.)"});
160              
161             $win->plot(with=>'fits', $m51_fl->map($ts, $m51_fl, { method=>"jacobian" }),
162             { Title=>"M51 x3 (jacob.)"});
163             |],
164              
165             [act => q|
166             ### Linear transformations are only the beginning. Here's an example
167             # using a simple nonlinear transformation: radial coordinate transformation.
168              
169             ### Original image
170             $win->plot(with=>'fits', $m51, { Title=>"M51" });
171              
172             ### Radial structure in M51 (linear radial scale; origin at (0,0) by default)
173             $tu = t_radial( u=>'degree' );
174             $win->plot(with=>'fits', $m51_fl->map($tu),
175             { Title=>"M51 radial (linear)", J=>0 });
176              
177             ### Radial structure in M51 (conformal/logarithmic radial scale)
178             $tu_c = t_radial( r0=>0.1 ); # Y axis 0 is at 0.1 arcmin
179             $win->plot(with=>'fits', $m51_fl->map($tu_c),
180             { Title=>"M51 radial (conformal)", YRange=>[0,4] } );
181             |],
182             # NOTE:
183             # need to 'double protect' the \ in the label_axes()
184             # since it's being evaluated twice (I think)
185             #
186              
187             [act => q|
188              
189             #####################
190             # Wrapping transformations allows you to work in a convenient
191             # space for what you want to do. Here, we can use a simple
192             # skew matrix to find (and remove) logarithmic spiral structures in
193             # the galaxy. The "unspiraled" images shift the spiral arms into
194             # approximate straight lines.
195              
196             $sp = 3.14159; # Skew by 3.14159
197              
198             # Skew matrix
199             $t_skew = t_linear(pre => [$sp * 130, 0] , matrix => pdl([1,0],[-$sp,1]));
200              
201             # When put into conformal radial space, the skew turns into 3.14159
202             # radians per scale height.
203             $t_untwist = t_wrap($t_skew, $tu_c);
204              
205             # Press enter to see the result of these transforms...
206             |],
207              
208             [act => q|
209             ##############################
210             # Note that you can use ->map and ->unmap as either PDL methods
211             # or transform methods; what to do is clear from context.
212              
213             $win->plot(with=>'points', pdl([1]), {title=>''}); # blank, clears
214             # Original image
215             $win->plot(with=>'fits', $m51, { Title=>"M51" });
216              
217             # Skewed
218             $win->plot(with=>'fits', $m51_fl->map( $t_skew ),
219             { Title => "M51 skewed by pi in spatial coords" } );
220              
221             # Untwisted -- show that m51 has a half-twist per scale height
222             $win->plot(with=>'fits', $m51_fl->map( $t_untwist ),
223             { Title => "M51 unspiraled (pi / r_s)"} );
224              
225             # Untwisted -- the jacobian method uses variable spatial filtering
226             # to eliminate spatial artifacts, at significant computational cost
227             # (This may take some time to complete).
228             $win->plot(with=>'fits', $m51_fl->map( $t_untwist, {m=>"jacobian"}),
229             { Title => "M51 unspiraled (pi / r_s; antialiased)" } );
230             |],
231              
232             [act => q|
233             ### Native FITS interpretation makes it easy to view your data in
234             ### your preferred coordinate system. Here we zoom in on a 0.2x0.2
235             ### arcmin region of M51, sampling it to 100x100 pixels resolution.
236              
237             $m51 = float $m51;
238             $data = $m51->match([100,100],{or=>[[-0.05,0.15],[-0.05,0.15]]});
239             $s = "M51 closeup ("; $ss=" coords)";
240             $ps = " (pixels)";
241              
242             $win = pgswin( size=>[8,4], multi=>[2,1] ) ;
243             $win->plot(with=>'image', $data, { title=>"${s}pixel${ss}",
244             xlabel=>"X$ps", ylabel=>"Y$ps", crange=>[600,750] } );
245             $win->plot(with=>'fits', $data, { title=>"${s}sci.${ss}",
246             crange=>[600,750] } );
247             |],
248              
249             [act => q|
250             ### Now rotate the image 360 degrees in 10 degree increments.
251             ### The 'match' method resamples $data to the rotated scientific
252             ### coordinate system in $hdr. The "pixel coordinates" window shows
253             ### the resampled data in their new pixel coordinate system.
254             ### The "sci. coordinates" window shows the data remaining fixed in
255             ### scientific space, even though the pixels that represent them are
256             ### moving and rotating.
257              
258             $hdr = $data->hdr_copy;
259              
260             for ($rot=0; $rot<360; $rot += 10) {
261             $hdr->{CROTA2} = $rot;
262              
263             $d = $m51->match($hdr);
264              
265             $win->plot(with=>'image', $d, { title=>"${s}pixel${ss}",
266             xlabel=>"X$ps", ylabel=>"Y$ps", crange=>[600,750] } );
267             $win->plot(with=>'fits', $d, { title=>"${s}sci.${ss}",
268             xrange=>[-0.05,0.15], yrange=>[-0.05,0.15], crange=>[600,750] } );
269             }
270             |],
271              
272             [act => q|
273             ### You can do the same thing even with nonsquare coordinates.
274             ### Here, we resample the same region in scientific space into a
275             ### 150x50 pixel array.
276              
277             $data = $m51->match([150,50],{or=>[[-0.05,0.15],[-0.05,0.15]]});
278             $hdr = $data->hdr_copy;
279              
280             for ($rot=0; $rot<360; $rot += 5) {
281             $hdr->{CROTA2} = $rot;
282             $d = $m51->match($hdr,{or=>[[-0.05,0.15],[-0.05,0.15]]});
283             $win->plot(with=>'image', $d, { title=>"${s}pixel${ss}",
284             xlabel=>"X$ps", ylabel=>"Y$ps", crange=>[600,750] } );
285             $win->plot(with=>'fits', $d, { title=>"${s}sci.${ss}",
286             xrange=>[-0.05,0.15], yrange=>[-0.05,0.15], crange=>[600,750] } );
287             }
288             |],
289              
290             [comment => q|
291             This concludes the PDL::Transform demo.
292              
293             Be sure to check the documentation for PDL::Transform::Cartography,
294             which contains common perspective and mapping coordinate systems
295             that are useful for work on the terrestrial and celestial spheres,
296             as well as other planets &c.
297             |],
298             );
299              
300             sub demo { @demo }
301             sub done {'
302             undef $win;
303             '}
304              
305             1;