1Image2D(3) User Contributed Perl Documentation Image2D(3)
2
3
4
6 PDL::Image2D - Miscellaneous 2D image processing functions
7
9 Miscellaneous 2D image processing functions - for want of anywhere else
10 to put them.
11
13 use PDL::Image2D;
14
16 conv2d
17 Signature: (a(m,n); kern(p,q); [o]b(m,n); int opt)
18
19 2D convolution of an array with a kernel (smoothing)
20
21 For large kernels, using a FFT routine, such as fftconvolve() in
22 "PDL::FFT", will be quicker.
23
24 $new = conv2d $old, $kernel, {OPTIONS}
25
26 $smoothed = conv2d $image, ones(3,3), {Boundary => Reflect}
27
28 Boundary - controls what values are assumed for the image when kernel
29 crosses its edge:
30 => Default - periodic boundary conditions
31 (i.e. wrap around axis)
32 => Reflect - reflect at boundary
33 => Truncate - truncate at boundary
34 => Replicate - repeat boundary pixel values
35
36 Unlike the FFT routines, conv2d is able to process bad values.
37
38 med2d
39 Signature: (a(m,n); kern(p,q); [o]b(m,n); int opt)
40
41 2D median-convolution of an array with a kernel (smoothing)
42
43 Note: only points in the kernel >0 are included in the median, other
44 points are weighted by the kernel value (medianing lots of zeroes is
45 rather pointless)
46
47 $new = med2d $old, $kernel, {OPTIONS}
48
49 $smoothed = med2d $image, ones(3,3), {Boundary => Reflect}
50
51 Boundary - controls what values are assumed for the image when kernel
52 crosses its edge:
53 => Default - periodic boundary conditions (i.e. wrap around axis)
54 => Reflect - reflect at boundary
55 => Truncate - truncate at boundary
56 => Replicate - repeat boundary pixel values
57
58 Bad values are ignored in the calculation. If all elements within the
59 kernel are bad, the output is set bad.
60
61 med2df
62 Signature: (a(m,n); [o]b(m,n); int __p_size; int __q_size; int opt)
63
64 2D median-convolution of an array in a pxq window (smoothing)
65
66 Note: this routine does the median over all points in a rectangular
67 window and is not quite as flexible as "med2d" in this regard
68 but slightly faster instead
69
70 $new = med2df $old, $xwidth, $ywidth, {OPTIONS}
71
72 $smoothed = med2df $image, 3, 3, {Boundary => Reflect}
73
74 Boundary - controls what values are assumed for the image when kernel
75 crosses its edge:
76 => Default - periodic boundary conditions (i.e. wrap around axis)
77 => Reflect - reflect at boundary
78 => Truncate - truncate at boundary
79 => Replicate - repeat boundary pixel values
80
81 med2df does not process bad values. It will set the bad-value flag of
82 all output ndarrays if the flag is set for any of the input ndarrays.
83
84 box2d
85 Signature: (a(n,m); [o] b(n,m); int wx; int wy; int edgezero)
86
87 fast 2D boxcar average
88
89 $smoothim = $im->box2d($wx,$wy,$edgezero=1);
90
91 The edgezero argument controls if edge is set to zero (edgezero=1) or
92 just keeps the original (unfiltered) values.
93
94 "box2d" should be updated to support similar edge options as "conv2d"
95 and "med2d" etc.
96
97 Boxcar averaging is a pretty crude way of filtering. For serious stuff
98 better filters are around (e.g., use "conv2d" with the appropriate
99 kernel). On the other hand it is fast and computational cost grows only
100 approximately linearly with window size.
101
102 box2d does not process bad values. It will set the bad-value flag of
103 all output ndarrays if the flag is set for any of the input ndarrays.
104
105 patch2d
106 Signature: (a(m,n); int bad(m,n); [o]b(m,n))
107
108 patch bad pixels out of 2D images using a mask
109
110 $patched = patch2d $data, $bad;
111
112 $bad is a 2D mask array where 1=bad pixel 0=good pixel. Pixels are
113 replaced by the average of their non-bad neighbours; if all neighbours
114 are bad, the original data value is copied across.
115
116 This routine does not handle bad values - use "patchbad2d" instead
117
118 patchbad2d
119 Signature: (a(m,n); [o]b(m,n))
120
121 patch bad pixels out of 2D images containing bad values
122
123 $patched = patchbad2d $data;
124
125 Pixels are replaced by the average of their non-bad neighbours; if all
126 neighbours are bad, the output is set bad. If the input ndarray
127 contains no bad values, then a straight copy is performed (see
128 "patch2d").
129
130 patchbad2d handles bad values. The output ndarray may contain bad
131 values, depending on the pattern of bad values in the input ndarray.
132
133 max2d_ind
134 Signature: (a(m,n); [o]val(); int [o]x(); int[o]y())
135
136 Return value/position of maximum value in 2D image
137
138 Contributed by Tim Jeness
139
140 Bad values are excluded from the search. If all pixels are bad then the
141 output is set bad.
142
143 centroid2d
144 Signature: (im(m,n); x(); y(); box(); [o]xcen(); [o]ycen())
145
146 Refine a list of object positions in 2D image by centroiding in a box
147
148 $box is the full-width of the box, i.e. the window is "+/- $box/2".
149
150 Bad pixels are excluded from the centroid calculation. If all elements
151 are bad (or the pixel sum is 0 - but why would you be centroiding
152 something with negatives in...) then the output values are set bad.
153
154 cc8compt
155 Connected 8-component labeling of a binary image.
156
157 Connected 8-component labeling of 0,1 image - i.e. find separate
158 segmented objects and fill object pixels with object number.
159 8-component labeling includes all neighboring pixels. This is just a
160 front-end to ccNcompt. See also "cc4compt".
161
162 $segmented = cc8compt( $image > $threshold );
163
164 cc4compt
165 Connected 4-component labeling of a binary image.
166
167 Connected 4-component labeling of 0,1 image - i.e. find separate
168 segmented objects and fill object pixels with object number.
169 4-component labling does not include the diagonal neighbors. This is
170 just a front-end to ccNcompt. See also "cc8compt".
171
172 $segmented = cc4compt( $image > $threshold );
173
174 ccNcompt
175 Signature: (a(m,n); int+ [o]b(m,n); int con)
176
177 Connected component labeling of a binary image.
178
179 Connected component labeling of 0,1 image - i.e. find separate
180 segmented objects and fill object pixels with object number. See also
181 "cc4compt" and "cc8compt".
182
183 The connectivity parameter must be 4 or 8.
184
185 $segmented = ccNcompt( $image > $threshold, 4);
186
187 $segmented2 = ccNcompt( $image > $threshold, 8);
188
189 where the second parameter specifies the connectivity (4 or 8) of the
190 labeling.
191
192 ccNcompt ignores the bad-value flag of the input ndarrays. It will set
193 the bad-value flag of all output ndarrays if the flag is set for any of
194 the input ndarrays.
195
196 polyfill
197 fill the area of the given polygon with the given colour.
198
199 This function works inplace, i.e. modifies "im".
200
201 polyfill($im,$ps,$colour,[\%options]);
202
203 The default method of determining which points lie inside of the
204 polygon used is not as strict as the method used in "pnpoly". Often, it
205 includes vertices and edge points. Set the "Method" option to change
206 this behaviour.
207
208 Method - Set the method used to determine which points lie in the
209 polygon.
210 => Default - internal PDL algorithm
211 => pnpoly - use the "pnpoly" algorithm
212
213 # Make a convex 3x3 square of 1s in an image using the pnpoly algorithm
214 $ps = pdl([3,3],[3,6],[6,6],[6,3]);
215 polyfill($im,$ps,1,{'Method' =>'pnpoly'});
216
217 pnpoly
218 'points in a polygon' selection from a 2-D ndarray
219
220 $mask = $img->pnpoly($ps);
221
222 # Old style, do not use
223 $mask = pnpoly($x, $y, $px, $py);
224
225 For a closed polygon determined by the sequence of points in {$px,$py}
226 the output of pnpoly is a mask corresponding to whether or not each
227 coordinate (x,y) in the set of test points, {$x,$y}, is in the interior
228 of the polygon. This is the 'points in a polygon' algorithm from
229 <http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html>
230 and vectorized for PDL by Karl Glazebrook.
231
232 # define a 3-sided polygon (a triangle)
233 $ps = pdl([3, 3], [20, 20], [34, 3]);
234
235 # $tri is 0 everywhere except for points in polygon interior
236 $tri = $img->pnpoly($ps);
237
238 With the second form, the x and y coordinates must also be specified.
239 B< I<THIS IS MAINTAINED FOR BACKWARD COMPATIBILITY ONLY> >.
240
241 $px = pdl( 3, 20, 34 );
242 $py = pdl( 3, 20, 3 );
243 $x = $img->xvals; # get x pixel coords
244 $y = $img->yvals; # get y pixel coords
245
246 # $tri is 0 everywhere except for points in polygon interior
247 $tri = pnpoly($x,$y,$px,$py);
248
249 polyfillv
250 return the (dataflowed) area of an image described by a polygon
251
252 polyfillv($im,$ps,[\%options]);
253
254 The default method of determining which points lie inside of the
255 polygon used is not as strict as the method used in "pnpoly". Often, it
256 includes vertices and edge points. Set the "Method" option to change
257 this behaviour.
258
259 Method - Set the method used to determine which points lie in the
260 polygon.
261 => Default - internal PDL algorithm
262 => pnpoly - use the "pnpoly" algorithm
263
264 # increment intensity in area bounded by $poly using the pnpoly algorithm
265 $im->polyfillv($poly,{'Method'=>'pnpoly'})++; # legal in perl >= 5.6
266
267 # compute average intensity within area bounded by $poly using the default algorithm
268 $av = $im->polyfillv($poly)->avg;
269
270 rot2d
271 Signature: (im(m,n); float angle(); bg(); int aa(); [o] om(p,q))
272
273 rotate an image by given "angle"
274
275 # rotate by 10.5 degrees with antialiasing, set missing values to 7
276 $rot = $im->rot2d(10.5,7,1);
277
278 This function rotates an image through an "angle" between -90 and + 90
279 degrees. Uses/doesn't use antialiasing depending on the "aa" flag.
280 Pixels outside the rotated image are set to "bg".
281
282 Code modified from pnmrotate (Copyright Jef Poskanzer) with an
283 algorithm based on "A Fast Algorithm for General Raster Rotation" by
284 Alan Paeth, Graphics Interface '86, pp. 77-81.
285
286 Use the "rotnewsz" function to find out about the dimension of the
287 newly created image
288
289 ($newcols,$newrows) = rotnewsz $oldn, $oldm, $angle;
290
291 PDL::Transform offers a more general interface to distortions,
292 including rotation, with various types of sampling; but rot2d is
293 faster.
294
295 rot2d ignores the bad-value flag of the input ndarrays. It will set
296 the bad-value flag of all output ndarrays if the flag is set for any of
297 the input ndarrays.
298
299 bilin2d
300 Signature: (Int(n,m); O(q,p))
301
302 Bilinearly maps the first ndarray in the second. The interpolated
303 values are actually added to the second ndarray which is supposed to be
304 larger than the first one.
305
306 bilin2d ignores the bad-value flag of the input ndarrays. It will set
307 the bad-value flag of all output ndarrays if the flag is set for any of
308 the input ndarrays.
309
310 rescale2d
311 Signature: (Int(m,n); O(p,q))
312
313 The first ndarray is rescaled to the dimensions of the second
314 (expanding or meaning values as needed) and then added to it in place.
315 Nothing useful is returned.
316
317 If you want photometric accuracy or automatic FITS header metadata
318 tracking, consider using PDL::Transform::map instead: it does these
319 things, at some speed penalty compared to rescale2d.
320
321 rescale2d ignores the bad-value flag of the input ndarrays. It will
322 set the bad-value flag of all output ndarrays if the flag is set for
323 any of the input ndarrays.
324
325 fitwarp2d
326 Find the best-fit 2D polynomial to describe a coordinate
327 transformation.
328
329 ( $px, $py ) = fitwarp2d( $x, $y, $u, $v, $nf, { options } )
330
331 Given a set of points in the output plane ("$u,$v"), find the best-fit
332 (using singular-value decomposition) 2D polynomial to describe the
333 mapping back to the image plane ("$x,$y"). The order of the fit is
334 controlled by the $nf parameter (the maximum power of the polynomial is
335 "$nf - 1"), and you can restrict the terms to fit using the "FIT"
336 option.
337
338 $px and $py are "np" by "np" element ndarrays which describe a
339 polynomial mapping (of order "np-1") from the output "(u,v)" image to
340 the input "(x,y)" image:
341
342 x = sum(j=0,np-1) sum(i=0,np-1) px(i,j) * u^i * v^j
343 y = sum(j=0,np-1) sum(i=0,np-1) py(i,j) * u^i * v^j
344
345 The transformation is returned for the reverse direction (ie output to
346 input image) since that is what is required by the warp2d() routine.
347 The applywarp2d() routine can be used to convert a set of "$u,$v"
348 points given $px and $py.
349
350 Options:
351
352 FIT - which terms to fit? default ones(byte,$nf,$nf)
353
354 FIT "FIT" allows you to restrict which terms of the polynomial to fit:
355 only those terms for which the FIT ndarray evaluates to true will
356 be evaluated. If a 2D ndarray is sent in, then it is used for the
357 x and y polynomials; otherwise "$fit->slice(":,:,(0)")" will be
358 used for $px and "$fit->slice(":,:,(1)")" will be used for $py.
359
360 The number of points must be at least equal to the number of terms to
361 fit ("$nf*$nf" points for the default value of "FIT").
362
363 # points in original image
364 $x = pdl( 0, 0, 100, 100 );
365 $y = pdl( 0, 100, 100, 0 );
366 # get warped to these positions
367 $u = pdl( 10, 10, 90, 90 );
368 $v = pdl( 10, 90, 90, 10 );
369 #
370 # shift of origin + scale x/y axis only
371 $fit = byte( [ [1,1], [0,0] ], [ [1,0], [1,0] ] );
372 ( $px, $py ) = fitwarp2d( $x, $y, $u, $v, 2, { FIT => $fit } );
373 print "px = ${px}py = $py";
374 px =
375 [
376 [-12.5 1.25]
377 [ 0 0]
378 ]
379 py =
380 [
381 [-12.5 0]
382 [ 1.25 0]
383 ]
384 #
385 # Compared to allowing all 4 terms
386 ( $px, $py ) = fitwarp2d( $x, $y, $u, $v, 2 );
387 print "px = ${px}py = $py";
388 px =
389 [
390 [ -12.5 1.25]
391 [ 1.110223e-16 -1.1275703e-17]
392 ]
393 py =
394 [
395 [ -12.5 1.6653345e-16]
396 [ 1.25 -5.8546917e-18]
397 ]
398
399 # A higher-degree polynomial should not affect the answer much, but
400 # will require more control points
401
402 $x = $x->glue(0,pdl(50,12.5, 37.5, 12.5, 37.5));
403 $y = $y->glue(0,pdl(50,12.5, 37.5, 37.5, 12.5));
404 $u = $u->glue(0,pdl(73,20,40,20,40));
405 $v = $v->glue(0,pdl(29,20,40,40,20));
406 ( $px3, $py3 ) = fitwarp2d( $x, $y, $u, $v, 3 );
407 print "px3 =${px3}py3 =$py3";
408 px3 =
409 [
410 [-6.4981162e+08 71034917 -726498.95]
411 [ 49902244 -5415096.7 55945.388]
412 [ -807778.46 88457.191 -902.51612]
413 ]
414 py3 =
415 [
416 [-6.2732159e+08 68576392 -701354.77]
417 [ 48175125 -5227679.8 54009.114]
418 [ -779821.18 85395.681 -871.27997]
419 ]
420
421 #This illustrates an important point about singular value
422 #decompositions that are used in fitwarp2d: like all SVDs, the
423 #rotation matrices are not unique, and so the $px and $py returned
424 #by fitwarp2d are not guaranteed to be the "simplest" solution.
425 #They do still work, though:
426
427 ($x3,$y3) = applywarp2d($px3,$py3,$u,$v);
428 print approx $x3,$x,1e-4;
429 [1 1 1 1 1 1 1 1 1]
430 print approx $y3,$y;
431 [1 1 1 1 1 1 1 1 1]
432
433 applywarp2d
434 Transform a set of points using a 2-D polynomial mapping
435
436 ( $x, $y ) = applywarp2d( $px, $py, $u, $v )
437
438 Convert a set of points (stored in 1D ndarrays "$u,$v") to "$x,$y"
439 using the 2-D polynomial with coefficients stored in $px and $py. See
440 fitwarp2d() for more information on the format of $px and $py.
441
442 warp2d
443 Signature: (img(m,n); double px(np,np); double py(np,np); [o] warp(m,n); { options })
444
445 Warp a 2D image given a polynomial describing the reverse mapping.
446
447 $out = warp2d( $img, $px, $py, { options } );
448
449 Apply the polynomial transformation encoded in the $px and $py ndarrays
450 to warp the input image $img into the output image $out.
451
452 The format for the polynomial transformation is described in the
453 documentation for the fitwarp2d() routine.
454
455 At each point "x,y", the closest 16 pixel values are combined with an
456 interpolation kernel to calculate the value at "u,v". The
457 interpolation is therefore done in the image, rather than Fourier,
458 domain. By default, a "tanh" kernel is used, but this can be changed
459 using the "KERNEL" option discussed below (the choice of kernel depends
460 on the frequency content of the input image).
461
462 The routine is based on the "warping" command from the Eclipse data-
463 reduction package - see http://www.eso.org/eclipse/ - and for further
464 details on image resampling see Wolberg, G., "Digital Image Warping",
465 1990, IEEE Computer Society Press ISBN 0-8186-8944-7).
466
467 Currently the output image is the same size as the input one, which
468 means data will be lost if the transformation reduces the pixel scale.
469 This will (hopefully) be changed soon.
470
471 $img = rvals(byte,501,501);
472 imag $img, { JUSTIFY => 1 };
473 #
474 # use a not-particularly-obvious transformation:
475 # x = -10 + 0.5 * $u - 0.1 * $v
476 # y = -20 + $v - 0.002 * $u * $v
477 #
478 $px = pdl( [ -10, 0.5 ], [ -0.1, 0 ] );
479 $py = pdl( [ -20, 0 ], [ 1, 0.002 ] );
480 $wrp = warp2d( $img, $px, $py );
481 #
482 # see the warped image
483 imag $warp, { JUSTIFY => 1 };
484
485 The options are:
486
487 KERNEL - default value is tanh
488 NOVAL - default value is 0
489
490 "KERNEL" is used to specify which interpolation kernel to use (to see
491 what these kernels look like, use the warp2d_kernel() routine). The
492 options are:
493
494 tanh
495 Hyperbolic tangent: the approximation of an ideal box filter by the
496 product of symmetric tanh functions.
497
498 sinc
499 For a correctly sampled signal, the ideal filter in the fourier
500 domain is a rectangle, which produces a "sinc" interpolation kernel
501 in the spatial domain:
502
503 sinc(x) = sin(pi * x) / (pi * x)
504
505 However, it is not ideal for the "4x4" pixel region used here.
506
507 sinc2
508 This is the square of the sinc function.
509
510 lanczos
511 Although defined differently to the "tanh" kernel, the result is
512 very similar in the spatial domain. The Lanczos function is
513 defined as
514
515 L(x) = sinc(x) * sinc(x/2) if abs(x) < 2
516 = 0 otherwise
517
518 hann
519 This kernel is derived from the following function:
520
521 H(x) = a + (1-a) * cos(2*pi*x/(N-1)) if abs(x) < 0.5*(N-1)
522 = 0 otherwise
523
524 with "a = 0.5" and N currently equal to 2001.
525
526 hamming
527 This kernel uses the same H(x) as the Hann filter, but with "a =
528 0.54".
529
530 "NOVAL" gives the value used to indicate that a pixel in the output
531 image does not map onto one in the input image.
532
533 warp2d_kernel
534 Return the specified kernel, as used by "warp2d"
535
536 ( $x, $k ) = warp2d_kernel( $name )
537
538 The valid values for $name are the same as the "KERNEL" option of
539 warp2d().
540
541 line warp2d_kernel( "hamming" );
542
544 Copyright (C) Karl Glazebrook 1997 with additions by Robin Williams
545 (rjrw@ast.leeds.ac.uk), Tim Jeness (timj@jach.hawaii.edu), and Doug
546 Burke (burke@ifa.hawaii.edu).
547
548 All rights reserved. There is no warranty. You are allowed to
549 redistribute this software / documentation under certain conditions.
550 For details, see the file COPYING in the PDL distribution. If this file
551 is separated from the PDL distribution, the copyright notice should be
552 included in the file.
553
554
555
556perl v5.34.0 2022-02-28 Image2D(3)