imagend.pd (PDL-2.074) | : | imagend.pd (PDL-2.075) | ||
---|---|---|---|---|

skipping to change at line 12 | skipping to change at line 12 | |||

use warnings; | use warnings; | |||

pp_addpm({At=>'Top'},<<'EOD'); | pp_addpm({At=>'Top'},<<'EOD'); | |||

=head1 NAME | =head1 NAME | |||

PDL::ImageND - useful image processing in N dimensions | PDL::ImageND - useful image processing in N dimensions | |||

=head1 DESCRIPTION | =head1 DESCRIPTION | |||

These routines act on PDLs as N-dimensional objects, not as threaded | These routines act on PDLs as N-dimensional objects, not as broadcasted | |||

sets of 0-D or 1-D objects. The file is sort of a catch-all for | sets of 0-D or 1-D objects. The file is sort of a catch-all for | |||

broadly functional routines, most of which could legitimately | broadly functional routines, most of which could legitimately | |||

be filed elsewhere (and probably will, one day). | be filed elsewhere (and probably will, one day). | |||

ImageND is not a part of the PDL core (v2.4) and hence must be explicitly | ImageND is not a part of the PDL core (v2.4) and hence must be explicitly | |||

loaded. | loaded. | |||

=head1 SYNOPSIS | =head1 SYNOPSIS | |||

use PDL::ImageND; | use PDL::ImageND; | |||

skipping to change at line 354 | skipping to change at line 354 | |||

return $x -> copy; | return $x -> copy; | |||

} | } | |||

} | } | |||

', | ', | |||

Code => ' | Code => ' | |||

int ms = $SIZE(m); | int ms = $SIZE(m); | |||

int nv = $COMP(ns); | int nv = $COMP(ns); | |||

int i; | int i; | |||

double u, d; | double u, d; | |||

$GENERIC(a) av; | $GENERIC(a) av; | |||

threadloop %{ | broadcastloop %{ | |||

i = 0; | i = 0; | |||

d = -1; | d = -1; | |||

loop (n) %{ $b() = 0; %} | loop (n) %{ $b() = 0; %} | |||

loop (m) %{ | loop (m) %{ | |||

av = $a(); | av = $a(); | |||

u = nv*((m+1.)/ms)-1; | u = nv*((m+1.)/ms)-1; | |||

while (i <= u) { | while (i <= u) { | |||

$b(n => i) += (i-d)*av; | $b(n => i) += (i-d)*av; | |||

d = i; | d = i; | |||

i++; | i++; | |||

skipping to change at line 519 | skipping to change at line 519 | |||

Speed-optimized convolution with selectable boundary conditions | Speed-optimized convolution with selectable boundary conditions | |||

=for usage | =for usage | |||

$new = convolveND($x, $kernel, [ {options} ]); | $new = convolveND($x, $kernel, [ {options} ]); | |||

Conolve an array with a kernel, both of which are N-dimensional. | Conolve an array with a kernel, both of which are N-dimensional. | |||

If the kernel has fewer dimensions than the array, then the extra array | If the kernel has fewer dimensions than the array, then the extra array | |||

dimensions are threaded over. There are options that control the boundary | dimensions are broadcasted over. There are options that control the boundary | |||

conditions and method used. | conditions and method used. | |||

The kernel's origin is taken to be at the kernel's center. If your | The kernel's origin is taken to be at the kernel's center. If your | |||

kernel has a dimension of even order then the origin's coordinates get | kernel has a dimension of even order then the origin's coordinates get | |||

rounded up to the next higher pixel (e.g. (1,2) for a 3x4 kernel). | rounded up to the next higher pixel (e.g. (1,2) for a 3x4 kernel). | |||

This mimics the behavior of the earlier L</convolve> and | This mimics the behavior of the earlier L</convolve> and | |||

L<fftconvolve|PDL::FFT/fftconvolve()> routines, so convolveND is a drop-in | L<fftconvolve|PDL::FFT/fftconvolve()> routines, so convolveND is a drop-in | |||

replacement for them. | replacement for them. | |||

The kernel may be any size compared to the image, in any dimension. | The kernel may be any size compared to the image, in any dimension. | |||

skipping to change at line 578 | skipping to change at line 578 | |||

for tiny kernels. The tradeoff occurs when the array has about 400x | for tiny kernels. The tradeoff occurs when the array has about 400x | |||

more pixels than the kernel. | more pixels than the kernel. | |||

The default method is 'auto', which chooses direct or fft convolution | The default method is 'auto', which chooses direct or fft convolution | |||

based on the size of the input arrays. | based on the size of the input arrays. | |||

=back | =back | |||

NOTES | NOTES | |||

At the moment there's no way to thread over kernels. That could/should | At the moment there's no way to broadcast over kernels. That could/should | |||

be fixed. | be fixed. | |||

The threading over input is cheesy and should probably be fixed: | The broadcasting over input is cheesy and should probably be fixed: | |||

currently the kernel just gets dummy dimensions added to it to match | currently the kernel just gets dummy dimensions added to it to match | |||

the input dims. That does the right thing tersely but probably runs slower | the input dims. That does the right thing tersely but probably runs slower | |||

than a dedicated threadloop. | than a dedicated broadcastloop. | |||

The direct copying code uses PP primarily for the generic typing: it includes | The direct copying code uses PP primarily for the generic typing: it includes | |||

its own threadloops. | its own broadcastloops. | |||

=cut | =cut | |||

EOD | EOD | |||

PMCode => <<'EOD', | PMCode => <<'EOD', | |||

use PDL::Options; | use PDL::Options; | |||

# Perl wrapper conditions the data to make life easier for the PP sub. | # Perl wrapper conditions the data to make life easier for the PP sub. | |||

skipping to change at line 635 | skipping to change at line 635 | |||

Boundary=>'t' | Boundary=>'t' | |||

} | } | |||

); | ); | |||

$def->minmatch(1); | $def->minmatch(1); | |||

$def->casesens(0); | $def->casesens(0); | |||

} | } | |||

my $opt = $def->options(PDL::Options::ifhref($opt0)); | my $opt = $def->options(PDL::Options::ifhref($opt0)); | |||

### | ### | |||

# If the kernel has too few dimensions, we thread over the other | # If the kernel has too few dimensions, we broadcast over the other | |||

# dims -- this is the same as supplying the kernel with dummy dims of | # dims -- this is the same as supplying the kernel with dummy dims of | |||

# order 1, so, er, we do that. | # order 1, so, er, we do that. | |||

$k = $k->dummy($x->dims - 1, 1) | $k = $k->dummy($x->dims - 1, 1) | |||

if($x->ndims > $k->ndims); | if($x->ndims > $k->ndims); | |||

my $kdims = pdl($k->dims); | my $kdims = pdl($k->dims); | |||

### | ### | |||

# Decide whether to FFT or directly convolve: if we're in auto mode, | # Decide whether to FFT or directly convolve: if we're in auto mode, | |||

# choose based on the relative size of the image and kernel arrays. | # choose based on the relative size of the image and kernel arrays. | |||

my $fft = ( ($opt->{Method} =~ m/^a/i) ? | my $fft = ( ($opt->{Method} =~ m/^a/i) ? | |||

skipping to change at line 704 | skipping to change at line 704 | |||

EOD | EOD | |||

Pars=>'k0()', | Pars=>'k0()', | |||

OtherPars=>'SV *k; SV *aa; SV *a;', | OtherPars=>'SV *k; SV *aa; SV *a;', | |||

Code => <<'EOD' | Code => <<'EOD' | |||

/* | /* | |||

* Direct convolution | * Direct convolution | |||

* | * | |||

* Because the kernel is usually the smaller of the two arrays to be convolved, | * Because the kernel is usually the smaller of the two arrays to be convolved, | |||

* we thread kernel-first to keep it in the processor's cache. The strategy: | * we broadcast kernel-first to keep it in the processor's cache. The strategy: | |||

* work on a padded copy of the original image, so that (even with boundary | * work on a padded copy of the original image, so that (even with boundary | |||

* conditions) the geometry of the kernel is linearly related to the input | * conditions) the geometry of the kernel is linearly related to the input | |||

* array. Otherwise, follow the path blazed by Karl in convolve(): keep track | * array. Otherwise, follow the path blazed by Karl in convolve(): keep track | |||

* of the offsets for each kernel element in a flattened original PDL. | * of the offsets for each kernel element in a flattened original PDL. | |||

* | * | |||

* The first (PP) argument is a dummy that's only used to set the GENERIC() | * The first (PP) argument is a dummy that's only used to set the GENERIC() | |||

* macro. The other three arguments should all have the same type as the | * macro. The other three arguments should all have the same type as the | |||

* first arguments, and are all passed in as SVs. They are: the kernel, | * first arguments, and are all passed in as SVs. They are: the kernel, | |||

* the padded copy of the input PDL, and a pre-allocated output PDL. The | * the padded copy of the input PDL, and a pre-allocated output PDL. The | |||

* input PDL should be padded by the dimensionality of the kernel. | * input PDL should be padded by the dimensionality of the kernel. | |||

End of changes. 9 change blocks. | ||||

9 lines changed or deleted | | 9 lines changed or added |