~ubuntu-branches/ubuntu/lucid/pdl/lucid

« back to all changes in this revision

Viewing changes to Lib/ImageRGB/imagergb.pd

  • Committer: Bazaar Package Importer
  • Author(s): Ben Gertzfield
  • Date: 2002-04-08 18:47:16 UTC
  • Revision ID: james.westby@ubuntu.com-20020408184716-0hf64dc96kin3htp
Tags: upstream-2.3.2
ImportĀ upstreamĀ versionĀ 2.3.2

Show diffs side-by-side

added added

removed removed

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