File Coverage

lib/PDL/ImageRGB.pd
Criterion Covered Total %
statement 57 71 80.2
branch 15 34 44.1
condition 3 21 14.2
subroutine 12 13 92.3
pod 0 4 0.0
total 87 143 60.8


line stmt bran cond sub pod time code
1             use strict;
2             use warnings;
3              
4             { no warnings 'once'; # pass info back to Makefile.PL
5             $PDL::Core::Dev::EXTRAS{$::PDLMOD}{OBJECT} .= join '', map " $::PDLBASE/$_\$(OBJ_EXT)", qw(ppm_quant);
6             $PDL::Core::Dev::EXTRAS{$::PDLMOD}{INC} .= qq{ "-I$::PDLBASE"};
7             }
8              
9             pp_add_exported('',"interlrgb rgbtogr bytescl cquant ");
10             pp_addhdr('
11             #include "pdlppm.h" /* Local decs */
12             ');
13              
14             pp_addpm({At=>'Top'},<<'EOD');
15 15     15   126 use strict;
  15         32  
  15         675  
16 15     15   83 use warnings;
  15         24  
  15         968  
17              
18             =head1 NAME
19              
20             PDL::ImageRGB -- some utility functions for RGB image data handling
21              
22             =head1 DESCRIPTION
23              
24             Collection of a few commonly used routines involved in handling of RGB, palette
25             and grayscale images. Not much more than a start. Should be a good place to
26             exercise some of the broadcast/map/clump PP stuff.
27              
28             Other stuff that should/could go here:
29              
30             =over 3
31              
32             =item *
33             color space conversion
34              
35             =item *
36             common image filters
37              
38             =item *
39             image rebinning
40              
41             =back
42              
43             =head1 SYNOPSIS
44              
45             use PDL::ImageRGB;
46              
47             =cut
48              
49 15     15   119  
  15         29  
  15         1110  
50             use vars qw( $typecheck $EPS );
51 15     15   93  
  15         37  
  15         115  
52 15     15   132 use PDL::Core;
  15         32  
  15         115  
53 15     15   132 use PDL::Basic;
  15         28  
  15         108  
54 15     15   120 use PDL::Primitive;
  15         46  
  15         3252  
55             use PDL::Types;
56 15     15   115  
  15         28  
  15         1133  
57 15     15   112 use Carp;
  15         35  
  15         14063  
58             use strict 'vars';
59              
60              
61             $PDL::ImageRGB::EPS = 1e-7; # there is probably a more portable way
62              
63             =head1 FUNCTIONS
64              
65             =head2 cquant
66              
67             =for ref
68              
69             quantize and reduce colours in 8-bit images
70              
71             =for usage
72              
73             ($out, $lut) = cquant($image [,$ncols]);
74              
75             This function does color reduction for <=8bit displays and accepts 8bit RGB
76             and 8bit palette images. It does this through an interface to the ppm_quant
77             routine from the pbmplus package that implements the median cut routine which
78             intelligently selects the 'best' colors to represent your image on a <= 8bit
79             display (based on the median cut algorithm). Optional args: $ncols sets the
80             maximum nunmber of colours used for the output image (defaults to 256).
81             There are images where a different color
82             reduction scheme gives better results (it seems this is true for images
83             containing large areas with very smoothly changing colours).
84              
85             Returns a list containing the new palette image (type PDL_Byte) and the RGB
86             colormap.
87              
88             =cut
89              
90             # full broadcasting support intended
91 0 0 0 0 0 0 *cquant = \&PDL::cquant;
92             sub PDL::cquant {
93 0         0 barf 'Usage: ($out,$olut) = cquant($image[,$ncols])'
94 0         0 if $#_<0 || $#_>1;
95 0 0       0 my $image = shift;
  0         0  
  0         0  
96 0         0 my $ncols;
97 0         0 if ($#_ >= 0 ) { $ncols=shift; } else { $ncols = 256; };
98             my @Dims = $image->dims;
99 0 0 0     0 my ($out, $olut) = (null,null);
      0        
100              
101 0         0 barf "input must be byte (3,x,x)" if (@Dims < 2) || ($Dims[0] != 3)
102 0         0 || ($image->get_datatype != $PDL_B);
103             cquant_c($image,$out,$olut,$ncols);
104             return ($out,$olut);
105             }
106              
107              
108             =head2 interlrgb
109              
110             =for ref
111              
112             Make an RGB image from a palette image and its lookup table.
113              
114             =for usage
115              
116             $rgb = $palette_im->interlrgb($lut)
117              
118             Input should be of an integer type and the lookup table (3,x,...). Will perform
119             the lookup for any N-dimensional input pdl (i.e. 0D, 1D, 2D, ...). Uses the
120             index command but will dataflow only if
121             the $lut ndarray has the dataflow_forward flag set (see L).
122              
123             =cut
124              
125             # interlace a palette image, input as 8bit-image, RGB-lut (3,x,..) to
126             # (R,G,B) format for each pixel in the image
127 1     1 0 7 # should already support broadcasting
128 1         4 *interlrgb=\&PDL::interlrgb;
129             sub PDL::interlrgb {
130             my ($pdl,$lut) = @_;
131 1 50       7 my $lut_fflows = $lut->fflows;
132             # for our purposes $lut should be (3,z) where z is the number
133 1         6 # of colours in the lut
134 1 50       102 barf "expecting (3,x) input" if ($lut->dims)[0] != 3;
135 1         6 # do the conversion as an implicitly broadcasted index lookup
136             my $res = $lut->transpose->index($pdl->dummy(0));
137             $res->sever if !$lut_fflows;
138             return $res;
139             }
140              
141              
142             =head2 rgbtogr
143              
144             =for ref
145              
146             Converts an RGB image to a grey scale using standard transform
147              
148             =for usage
149              
150             $gr = $rgb->rgbtogr
151              
152             Performs a conversion of an RGB input image (3,x,....) to a
153             greyscale image (x,.....) using standard formula:
154              
155             Grey = 0.301 R + 0.586 G + 0.113 B
156              
157             =cut
158              
159             # convert interlaced rgb image to grayscale
160             # will convert any (3,...) dim pdl, i.e. also single lines,
161 1 50   1 0 5 # stacks of RGB images, etc since implicit broadcasting takes care of this
162 1         3 # should already support broadcasting
163 1 50       19 *rgbtogr = \&PDL::rgbtogr;
164             sub PDL::rgbtogr {
165             barf "Usage: \$im->rgbtogr" if $#_ < 0;
166 1         4 my $im = shift;
167 1         4 barf "rgbtogr: expecting RGB (3,...) input"
168 1         9 if (($im->dims)[0] != 3);
169 1         79  
170             my $type = $im->get_datatype;
171 1         5 my $rgb = float([77,150,29])/256; # vector for rgb conversion
172             my $oim = null; # flag PP we want it to allocate
173             inner($im,$rgb,$oim); # do the conversion as a broadcasted inner prod
174              
175             return $oim->convert($type); # convert back to original type
176             }
177              
178             =head2 bytescl
179              
180             =for ref
181              
182             Scales a pdl into a specified data range (default 0-255)
183              
184             =for usage
185              
186             $scale = $im->bytescl([$top])
187              
188             By default $top=255, otherwise you have to give the desired top value as an
189             argument to C. Normally C doesn't rescale data that fits
190             already in the bounds 0..$top (it only does the type conversion if required).
191             If you want to force it to rescale so that the max of the output is at $top and
192             the min at 0 you give a negative $top value to indicate this.
193              
194             =cut
195              
196             # scale any pdl linearly so that its data fits into the range
197             # 0<=x<=$ncols where $ncols<=255
198             # returns scaled data with type converted to byte
199             # doesn't rescale but just typecasts if data already fits into range, i.e.
200 3 50   3 0 10 # data ist not necessarily stretched to 0..$ncols
201 3         7 # needs some changes for full broadcasting support ?? (explicit broadcasting?)
202 3         16 *bytescl = \&PDL::bytescl;
203 3 50       11 sub PDL::bytescl {
204 3 100       12 barf 'Usage: bytescl $im[,$top]' if $#_ < 0;
  2         3  
  2         4  
205 3 50       7 my $pdl = shift;
206             my ($top,$force) = (255,0);
207 3 50       6 $top = shift if $#_ > -1;
208 3         7 if ($top < 0) { $force=1; $top *= -1; }
209 3         17 $top = 255 if $top > 255;
210 3         13  
211 3 100 33     127 print "bytescl: scaling from 0..$top\n" if $PDL::debug;
      66        
212             my ($max, $min);
213             $max = max $pdl;
214 2 50       24 $min = min $pdl;
215 0 0       0 return byte $pdl if ($min >= 0 && $max <= $top && !$force);
216 0 0 0     0  
      0        
217             # check for pathological cases
218 0         0 if (($max-$min) < $EPS) {
219             print "bytescl: pathological case\n" if $PDL::debug;
220             return byte $pdl
221 2 100       26 if (abs($max) < $EPS) || ($max >= 0 && $max <= $top);
222 2         8 return byte ($pdl/$max);
223             }
224              
225             my $type = $pdl->get_datatype > $PDL_F ? $PDL_D : $PDL_F;
226             return byte ($top*($pdl->convert($type)-$min)/($max-$min)+0.5);
227             }
228              
229             ;# Exit with OK status
230              
231             1;
232              
233             =head1 BUGS
234              
235             This package doesn't yet contain enough useful functions!
236              
237             =head1 AUTHOR
238              
239             Copyright 1997 Christian Soeller
240             All rights reserved. There is no warranty. You are allowed
241             to redistribute this software / documentation under certain
242             conditions. For details, see the file COPYING in the PDL
243             distribution. If this file is separated from the PDL distribution,
244             the copyright notice should be included in the file.
245              
246              
247             =cut
248              
249              
250             EOD
251              
252             ################################ XS CODE #################################
253             # a is the input image
254             # b is the output image and c the output lut
255             pp_def(
256             'cquant_c',Doc=>undef,
257             Pars => 'a(m=3,n,o); [o]b(n,o); [o]c(m,p);',
258             GenericTypes => ['B'],
259             OtherPars => 'int psz => p',
260             Code => 'int status;
261             status = ppm_quant($P(a), NULL, NULL, $SIZE(n),
262             $SIZE(o),$P(b), NULL, $P(c), 0,
263             $SIZE(p), 1);
264             if (!status)
265             $CROAK("ppm_quant returned error status");'
266             );
267              
268             pp_done();