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); double+ [t]tmp(pq); 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 crop
155 Return bounding box of given mask in an "indx" ndarray, so it can
156 broadcast. Use other operations (such as "isgood" in PDL::Bad, or
157 "eqvec" in PDL::Primitive with a colour vector) to create a mask
158 suitable for your application.
159
160 $x1x2y1y2 = crop($image);
161
162 cc8compt
163 Connected 8-component labeling of a binary image.
164
165 Connected 8-component labeling of 0,1 image - i.e. find separate
166 segmented objects and fill object pixels with object number.
167 8-component labeling includes all neighboring pixels. This is just a
168 front-end to ccNcompt. See also "cc4compt".
169
170 $segmented = cc8compt( $image > $threshold );
171
172 cc4compt
173 Connected 4-component labeling of a binary image.
174
175 Connected 4-component labeling of 0,1 image - i.e. find separate
176 segmented objects and fill object pixels with object number.
177 4-component labling does not include the diagonal neighbors. This is
178 just a front-end to ccNcompt. See also "cc8compt".
179
180 $segmented = cc4compt( $image > $threshold );
181
182 ccNcompt
183 Signature: (a(m,n); int+ [o]b(m,n); int con)
184
185 Connected component labeling of a binary image.
186
187 Connected component labeling of 0,1 image - i.e. find separate
188 segmented objects and fill object pixels with object number. See also
189 "cc4compt" and "cc8compt".
190
191 The connectivity parameter must be 4 or 8.
192
193 $segmented = ccNcompt( $image > $threshold, 4);
194
195 $segmented2 = ccNcompt( $image > $threshold, 8);
196
197 where the second parameter specifies the connectivity (4 or 8) of the
198 labeling.
199
200 ccNcompt ignores the bad-value flag of the input ndarrays. It will set
201 the bad-value flag of all output ndarrays if the flag is set for any of
202 the input ndarrays.
203
204 polyfill
205 fill the area of the given polygon with the given colour.
206
207 This function works inplace, i.e. modifies "im".
208
209 polyfill($im,$ps,$colour,[\%options]);
210
211 The default method of determining which points lie inside of the
212 polygon used is not as strict as the method used in "pnpoly". Often, it
213 includes vertices and edge points. Set the "Method" option to change
214 this behaviour.
215
216 Method - Set the method used to determine which points lie in the
217 polygon.
218 => Default - internal PDL algorithm
219 => pnpoly - use the "pnpoly" algorithm
220
221 # Make a convex 3x3 square of 1s in an image using the pnpoly algorithm
222 $ps = pdl([3,3],[3,6],[6,6],[6,3]);
223 polyfill($im,$ps,1,{'Method' =>'pnpoly'});
224
225 pnpoly
226 'points in a polygon' selection from a 2-D ndarray
227
228 $mask = $img->pnpoly($ps);
229
230 # Old style, do not use
231 $mask = pnpoly($x, $y, $px, $py);
232
233 For a closed polygon determined by the sequence of points in {$px,$py}
234 the output of pnpoly is a mask corresponding to whether or not each
235 coordinate (x,y) in the set of test points, {$x,$y}, is in the interior
236 of the polygon. This is the 'points in a polygon' algorithm from
237 <http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html>
238 and vectorized for PDL by Karl Glazebrook.
239
240 # define a 3-sided polygon (a triangle)
241 $ps = pdl([3, 3], [20, 20], [34, 3]);
242
243 # $tri is 0 everywhere except for points in polygon interior
244 $tri = $img->pnpoly($ps);
245
246 With the second form, the x and y coordinates must also be specified.
247 B< I<THIS IS MAINTAINED FOR BACKWARD COMPATIBILITY ONLY> >.
248
249 $px = pdl( 3, 20, 34 );
250 $py = pdl( 3, 20, 3 );
251 $x = $img->xvals; # get x pixel coords
252 $y = $img->yvals; # get y pixel coords
253
254 # $tri is 0 everywhere except for points in polygon interior
255 $tri = pnpoly($x,$y,$px,$py);
256
257 polyfillv
258 return the (dataflowed) area of an image described by a polygon
259
260 polyfillv($im,$ps,[\%options]);
261
262 The default method of determining which points lie inside of the
263 polygon used is not as strict as the method used in "pnpoly". Often, it
264 includes vertices and edge points. Set the "Method" option to change
265 this behaviour.
266
267 Method - Set the method used to determine which points lie in the
268 polygon.
269 => Default - internal PDL algorithm
270 => pnpoly - use the "pnpoly" algorithm
271
272 # increment intensity in area bounded by $poly using the pnpoly algorithm
273 $im->polyfillv($poly,{'Method'=>'pnpoly'})++; # legal in perl >= 5.6
274
275 # compute average intensity within area bounded by $poly using the default algorithm
276 $av = $im->polyfillv($poly)->avg;
277
278 rot2d
279 Signature: (im(m,n); float angle(); bg(); int aa(); [o] om(p,q))
280
281 rotate an image by given "angle"
282
283 # rotate by 10.5 degrees with antialiasing, set missing values to 7
284 $rot = $im->rot2d(10.5,7,1);
285
286 This function rotates an image through an "angle" between -90 and + 90
287 degrees. Uses/doesn't use antialiasing depending on the "aa" flag.
288 Pixels outside the rotated image are set to "bg".
289
290 Code modified from pnmrotate (Copyright Jef Poskanzer) with an
291 algorithm based on "A Fast Algorithm for General Raster Rotation" by
292 Alan Paeth, Graphics Interface '86, pp. 77-81.
293
294 Use the "rotnewsz" function to find out about the dimension of the
295 newly created image
296
297 ($newcols,$newrows) = rotnewsz $oldn, $oldm, $angle;
298
299 PDL::Transform offers a more general interface to distortions,
300 including rotation, with various types of sampling; but rot2d is
301 faster.
302
303 rot2d ignores the bad-value flag of the input ndarrays. It will set
304 the bad-value flag of all output ndarrays if the flag is set for any of
305 the input ndarrays.
306
307 bilin2d
308 Signature: (Int(n,m); O(q,p))
309
310 Bilinearly maps the first ndarray in the second. The interpolated
311 values are actually added to the second ndarray which is supposed to be
312 larger than the first one.
313
314 bilin2d ignores the bad-value flag of the input ndarrays. It will set
315 the bad-value flag of all output ndarrays if the flag is set for any of
316 the input ndarrays.
317
318 rescale2d
319 Signature: (Int(m,n); O(p,q))
320
321 The first ndarray is rescaled to the dimensions of the second
322 (expanding or meaning values as needed) and then added to it in place.
323 Nothing useful is returned.
324
325 If you want photometric accuracy or automatic FITS header metadata
326 tracking, consider using PDL::Transform::map instead: it does these
327 things, at some speed penalty compared to rescale2d.
328
329 rescale2d ignores the bad-value flag of the input ndarrays. It will
330 set the bad-value flag of all output ndarrays if the flag is set for
331 any of the input ndarrays.
332
333 fitwarp2d
334 Find the best-fit 2D polynomial to describe a coordinate
335 transformation.
336
337 ( $px, $py ) = fitwarp2d( $x, $y, $u, $v, $nf, { options } )
338
339 Given a set of points in the output plane ("$u,$v"), find the best-fit
340 (using singular-value decomposition) 2D polynomial to describe the
341 mapping back to the image plane ("$x,$y"). The order of the fit is
342 controlled by the $nf parameter (the maximum power of the polynomial is
343 "$nf - 1"), and you can restrict the terms to fit using the "FIT"
344 option.
345
346 $px and $py are "np" by "np" element ndarrays which describe a
347 polynomial mapping (of order "np-1") from the output "(u,v)" image to
348 the input "(x,y)" image:
349
350 x = sum(j=0,np-1) sum(i=0,np-1) px(i,j) * u^i * v^j
351 y = sum(j=0,np-1) sum(i=0,np-1) py(i,j) * u^i * v^j
352
353 The transformation is returned for the reverse direction (ie output to
354 input image) since that is what is required by the warp2d() routine.
355 The applywarp2d() routine can be used to convert a set of "$u,$v"
356 points given $px and $py.
357
358 Options:
359
360 FIT - which terms to fit? default ones(byte,$nf,$nf)
361
362 FIT "FIT" allows you to restrict which terms of the polynomial to fit:
363 only those terms for which the FIT ndarray evaluates to true will
364 be evaluated. If a 2D ndarray is sent in, then it is used for the
365 x and y polynomials; otherwise "$fit->slice(":,:,(0)")" will be
366 used for $px and "$fit->slice(":,:,(1)")" will be used for $py.
367
368 The number of points must be at least equal to the number of terms to
369 fit ("$nf*$nf" points for the default value of "FIT").
370
371 # points in original image
372 $x = pdl( 0, 0, 100, 100 );
373 $y = pdl( 0, 100, 100, 0 );
374 # get warped to these positions
375 $u = pdl( 10, 10, 90, 90 );
376 $v = pdl( 10, 90, 90, 10 );
377 #
378 # shift of origin + scale x/y axis only
379 $fit = byte( [ [1,1], [0,0] ], [ [1,0], [1,0] ] );
380 ( $px, $py ) = fitwarp2d( $x, $y, $u, $v, 2, { FIT => $fit } );
381 print "px = ${px}py = $py";
382 px =
383 [
384 [-12.5 1.25]
385 [ 0 0]
386 ]
387 py =
388 [
389 [-12.5 0]
390 [ 1.25 0]
391 ]
392 #
393 # Compared to allowing all 4 terms
394 ( $px, $py ) = fitwarp2d( $x, $y, $u, $v, 2 );
395 print "px = ${px}py = $py";
396 px =
397 [
398 [ -12.5 1.25]
399 [ 1.110223e-16 -1.1275703e-17]
400 ]
401 py =
402 [
403 [ -12.5 1.6653345e-16]
404 [ 1.25 -5.8546917e-18]
405 ]
406
407 # A higher-degree polynomial should not affect the answer much, but
408 # will require more control points
409
410 $x = $x->glue(0,pdl(50,12.5, 37.5, 12.5, 37.5));
411 $y = $y->glue(0,pdl(50,12.5, 37.5, 37.5, 12.5));
412 $u = $u->glue(0,pdl(73,20,40,20,40));
413 $v = $v->glue(0,pdl(29,20,40,40,20));
414 ( $px3, $py3 ) = fitwarp2d( $x, $y, $u, $v, 3 );
415 print "px3 =${px3}py3 =$py3";
416 px3 =
417 [
418 [-6.4981162e+08 71034917 -726498.95]
419 [ 49902244 -5415096.7 55945.388]
420 [ -807778.46 88457.191 -902.51612]
421 ]
422 py3 =
423 [
424 [-6.2732159e+08 68576392 -701354.77]
425 [ 48175125 -5227679.8 54009.114]
426 [ -779821.18 85395.681 -871.27997]
427 ]
428
429 #This illustrates an important point about singular value
430 #decompositions that are used in fitwarp2d: like all SVDs, the
431 #rotation matrices are not unique, and so the $px and $py returned
432 #by fitwarp2d are not guaranteed to be the "simplest" solution.
433 #They do still work, though:
434
435 ($x3,$y3) = applywarp2d($px3,$py3,$u,$v);
436 print approx $x3,$x,1e-4;
437 [1 1 1 1 1 1 1 1 1]
438 print approx $y3,$y;
439 [1 1 1 1 1 1 1 1 1]
440
441 applywarp2d
442 Transform a set of points using a 2-D polynomial mapping
443
444 ( $x, $y ) = applywarp2d( $px, $py, $u, $v )
445
446 Convert a set of points (stored in 1D ndarrays "$u,$v") to "$x,$y"
447 using the 2-D polynomial with coefficients stored in $px and $py. See
448 fitwarp2d() for more information on the format of $px and $py.
449
450 warp2d
451 Signature: (img(m,n); double px(np,np); double py(np,np); [o] warp(m,n); { options })
452
453 Warp a 2D image given a polynomial describing the reverse mapping.
454
455 $out = warp2d( $img, $px, $py, { options } );
456
457 Apply the polynomial transformation encoded in the $px and $py ndarrays
458 to warp the input image $img into the output image $out.
459
460 The format for the polynomial transformation is described in the
461 documentation for the fitwarp2d() routine.
462
463 At each point "x,y", the closest 16 pixel values are combined with an
464 interpolation kernel to calculate the value at "u,v". The
465 interpolation is therefore done in the image, rather than Fourier,
466 domain. By default, a "tanh" kernel is used, but this can be changed
467 using the "KERNEL" option discussed below (the choice of kernel depends
468 on the frequency content of the input image).
469
470 The routine is based on the "warping" command from the Eclipse data-
471 reduction package - see http://www.eso.org/eclipse/ - and for further
472 details on image resampling see Wolberg, G., "Digital Image Warping",
473 1990, IEEE Computer Society Press ISBN 0-8186-8944-7).
474
475 Currently the output image is the same size as the input one, which
476 means data will be lost if the transformation reduces the pixel scale.
477 This will (hopefully) be changed soon.
478
479 $img = rvals(byte,501,501);
480 imag $img, { JUSTIFY => 1 };
481 #
482 # use a not-particularly-obvious transformation:
483 # x = -10 + 0.5 * $u - 0.1 * $v
484 # y = -20 + $v - 0.002 * $u * $v
485 #
486 $px = pdl( [ -10, 0.5 ], [ -0.1, 0 ] );
487 $py = pdl( [ -20, 0 ], [ 1, 0.002 ] );
488 $wrp = warp2d( $img, $px, $py );
489 #
490 # see the warped image
491 imag $warp, { JUSTIFY => 1 };
492
493 The options are:
494
495 KERNEL - default value is tanh
496 NOVAL - default value is 0
497
498 "KERNEL" is used to specify which interpolation kernel to use (to see
499 what these kernels look like, use the warp2d_kernel() routine). The
500 options are:
501
502 tanh
503 Hyperbolic tangent: the approximation of an ideal box filter by the
504 product of symmetric tanh functions.
505
506 sinc
507 For a correctly sampled signal, the ideal filter in the fourier
508 domain is a rectangle, which produces a "sinc" interpolation kernel
509 in the spatial domain:
510
511 sinc(x) = sin(pi * x) / (pi * x)
512
513 However, it is not ideal for the "4x4" pixel region used here.
514
515 sinc2
516 This is the square of the sinc function.
517
518 lanczos
519 Although defined differently to the "tanh" kernel, the result is
520 very similar in the spatial domain. The Lanczos function is
521 defined as
522
523 L(x) = sinc(x) * sinc(x/2) if abs(x) < 2
524 = 0 otherwise
525
526 hann
527 This kernel is derived from the following function:
528
529 H(x) = a + (1-a) * cos(2*pi*x/(N-1)) if abs(x) < 0.5*(N-1)
530 = 0 otherwise
531
532 with "a = 0.5" and N currently equal to 2001.
533
534 hamming
535 This kernel uses the same H(x) as the Hann filter, but with "a =
536 0.54".
537
538 "NOVAL" gives the value used to indicate that a pixel in the output
539 image does not map onto one in the input image.
540
541 warp2d_kernel
542 Return the specified kernel, as used by "warp2d"
543
544 ( $x, $k ) = warp2d_kernel( $name )
545
546 The valid values for $name are the same as the "KERNEL" option of
547 warp2d().
548
549 line warp2d_kernel( "hamming" );
550
552 Copyright (C) Karl Glazebrook 1997 with additions by Robin Williams
553 (rjrw@ast.leeds.ac.uk), Tim Jeness (timj@jach.hawaii.edu), and Doug
554 Burke (burke@ifa.hawaii.edu).
555
556 All rights reserved. There is no warranty. You are allowed to
557 redistribute this software / documentation under certain conditions.
558 For details, see the file COPYING in the PDL distribution. If this file
559 is separated from the PDL distribution, the copyright notice should be
560 included in the file.
561
562
563
564perl v5.36.0 2023-01-20 Image2D(3)