⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch29.htm

📁 《Perl 5 Unreleased》
💻 HTM
📖 第 1 页 / 共 4 页
字号:
179           $$image[$i][$j]

= int($k);<BR>

180&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}

<BR>

181&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>

182 }</FONT></TT>

</BLOCKQUOTE>

<HR>

<H3><A NAME="ReadingtheImage"><B>Reading the Image</B></A></H3>

<P>

The format chosen for this example is the ASCII version of the

portable bitmap (PBM) file type PPM. There are two reasons for

choosing this format. First, it's simple to work with compared

to the more complicated GIF, pcX, and JPEG formats. The idea here

is to show how to use Perl to prototype algorithms, not discuss

graphics file formats. Second, the PBM utilities have some filters

and lots of conversion utilities for converting an image to a

format other than PBM if necessary. The downside of the ASCII

depiction is the slow speed in reading ASCII and the large amount

of disk space required for the image.

<P>

Obviously, after you prototype your algorithm, you'll want to

code the reading and writing of PBM files in a compiled and optimized

language such as C.

<P>

Following is the header for the image shown in Figures 29.1, 29.2,

and 29.3:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">P3<BR>

# CREATOR: XV Version 3.10  Rev: 12/16/94<BR>

99 77<BR>

255<BR>

252 252 252 252 252 252 252 252 252 252 252 252 252 252 252<BR>

252 252 252 252 252 252 252 252 252 252 252 252 252 252 252<BR>

252 252 252 252 252 252 252 252 252 252 252 252 252 252 252<BR>

252 252 252 252 252 252 252 252 252 252 252 252 252 252 252<BR>

252 252 252 252 252 252 252 252 252 252 252 252 252 252 252<BR>

252 252 252 252 252 252 252 252 252 252 252 252 252 252 252</FONT></TT>

</BLOCKQUOTE>

<P>

<TT><FONT FACE="Courier">P3</FONT></TT> is required for this image

file. The comment line concerning <TT><FONT FACE="Courier">CREATOR</FONT></TT>

is optional, but you will have to compensate for its existence.

<TT><FONT FACE="Courier">99</FONT></TT> refers to the number of

columns in the image, <TT><FONT FACE="Courier">77</FONT></TT>

refers to the number of rows of pixels, and <TT><FONT FACE="Courier">255</FONT></TT>

refers to the highest color.

<P>

What follows next is the red/green/blue (RGB) content of each

pixel in the image. All images used in this chapter have 256 gray

levels, so the RGB values are all equal. There must be 99<FONT FACE="Symbol">&#165;</FONT>77<FONT FACE="Symbol">&#165;</FONT>3

distinct RGB values.

<P>

The code for reading these pixel RGB values knows when to start

a new row by reading the number of values per row and then incrementing

the row when it reaches the columns per row. Thus, the program

reads in three values at a time and then assigns each value to

an <TT><FONT FACE="Courier">$$image</FONT></TT> array. Here's

the fragment of code to do this:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">while ($a = &lt;TEXT&gt;) {<BR>

chop $a;<BR>

@words = split(' ',$a);<BR>

$count = $#words;<BR>

<BR>

while (@words) {<BR>

&nbsp;&nbsp;&nbsp;($r,$g,$b) = splice(@words,0,3);<BR>

&nbsp;&nbsp;&nbsp;$$image[$row][$col] = ($r+$g+$b)/3;<BR>

&nbsp;&nbsp;&nbsp;$col++;<BR>

&nbsp;&nbsp;&nbsp;if ($col &gt;= $cols) { $row++; $col = 0 }<BR>

&nbsp;&nbsp;&nbsp;}<BR>

}</FONT></TT>

</BLOCKQUOTE>

<P>

The RGB values in this example are all equal, but this cannot

be guaranteed because you may be working with a color image. You

take the average of the RGB intensities to determine the average

intensity of a pixel by using the following line:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$$image[$row][$col] = ($r+$g+$b)/3;</FONT></TT>

</BLOCKQUOTE>

<P>

instead of assuming grayscale images only and then using only

one value. I do take the liberty of allocating room (by default)

to 97<FONT FACE="Symbol">&#165;</FONT>88 because grayscale images

are used instead of color maps to get the average intensity of

a pixel.

<P>

The processing algorithm requires the dimensions of the file and

the data. These values are returned in the following line:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">return ($cols,$rows,@image);</FONT></TT>

</BLOCKQUOTE>

<H3><A NAME="GettingaHistogram"><B>Getting a Histogram</B></A>

</H3>

<P>

After the image has been read from disk into memory, you can run

some programs on it. The histogram routine to run on the image

is as follows:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">sub getHistogram {<BR>

my ($rows,$cols,$img) = @_;<BR>

my @image = @$img;<BR>

my @refered = ();<BR>

my $hst = \@refered;<BR>

<BR>

my $i,$j,$k;<BR>

<BR>

for($i=0;$i&lt;$rows;$i++) {<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for($j=0;$j&lt;$cols;$j++) {<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$k

= $$image[$i][$j];<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$$hst[$k]

+= 1;<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>

&nbsp;&nbsp;&nbsp;&nbsp;}<BR>

return (@refered);<BR>

}</FONT></TT>

</BLOCKQUOTE>

<P>

The reference to the <TT><FONT FACE="Courier">@hst</FONT></TT>

array in the <TT><FONT FACE="Courier">getHistogram</FONT></TT>

subroutine is called to store the accumulated values per pixel

in the image.

<H2><A NAME="TheFilter"><B><FONT SIZE=5 COLOR=#FF0000>The Filter</FONT></B></A>

</H2>

<P>

A simple 3<FONT FACE="Symbol">&#165;</FONT>3 matrix convolution

filter is used in this section. Two filters are shown in Listing

29.5. The first filter is a uniform gain filter, and the second

is for using a type of Gaussian filter. You can modify this code

to use your own filter.

<P>

The filter is applied with a call to <TT><FONT FACE="Courier">applyFilter3</FONT></TT>.

In line 159, we pick up the <TT><FONT FACE="Courier">$convolve</FONT></TT>

filter and the pointer to the <TT><FONT FACE="Courier">$img</FONT></TT>.

The <TT><FONT FACE="Courier">convolve</FONT></TT> filter is passed

to an array with nine elements: The first three elements are in

the row above the pixel, followed by three more at the center

of row, and then three immediately below the current row. The

filter is shown at line 42 as this:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">@convolve = ( 0.1, 0.1, 0.1,<BR>

&nbsp;&nbsp;&nbsp;&nbsp;0.1, 0.1, 0.1,<BR>

&nbsp;&nbsp;&nbsp;&nbsp;0.1, 0.1, 0.1);<BR>

The second filter is shown at line 49 as this:<BR>

@convolve = ( 0.1, 0.0, 0.1,<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0.0, 0.5, 0.0,<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0.1, 0.0, 0.1);</FONT></TT>

</BLOCKQUOTE>

<P>

The following lines are where the filter is applied and the results

are written to disk:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">print &quot;\n Filter 2 applied&quot;;

<BR>

&amp;applyFilter3($wd,$ht,\@convolve,\@image);<BR>

dumpImage (&quot;filt1.ppm&quot;);</FONT></TT>

</BLOCKQUOTE>

<P>

The output of these filters is shown in Figures 29.2 and 29.3.

The way the convolution matrix is applied to the image is shown

in lines 168 to 179 in Listing 29.5.

<P>

<A HREF="f29-2.gif" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/f29-2.gif" ><B>Figure 29.2 : </B><I>The filtered image using the first filter.</I></A>

<P>

<A HREF="f29-3.gif" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/f29-3.gif" ><B>Figure 29.3 : </B><I>The filtered image using the second filter.</I></A>

<P>

Note that a band is left around the image so as not to overrun

the extents of the image array. When prototyping for eventual

use in a formal language, keep the restrictions of the formal

language in mind.

<P>

Finally, the image is written to disk with the <TT><FONT FACE="Courier">dumpImage</FONT></TT>

subroutine (shown in line 63). The calls to dump the image are

shown in lines 43 and 55.

<H2><A NAME="AnAddedTouch"><B><FONT SIZE=5 COLOR=#FF0000>An Added

Touch</FONT></B></A></H2>

<P>

To see the histograms in three dimensions, you can use the <TT><FONT FACE="Courier">VRML.pm</FONT></TT>

module developed earlier in this book to generate a display. By

applying different filters and then generating 3D histograms of

the resulting image, you can get a pictorial view of how each

filter affects the output. The following lines of code are for

a subroutine, <TT><FONT FACE="Courier">show3Dhistogram</FONT></TT>,

to create VRML cubes from the histogram array. Add this subroutine

to the end of the file shown in Listing 29.5:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">&nbsp;1 use VRML;<BR>

&nbsp;2 use VRML::Cube;<BR>

&nbsp;3 use VRML::Cylinder;<BR>

&nbsp;4<BR>

&nbsp;5 sub show3Dhistogram {<BR>

&nbsp;6 open (VRMLFILE,&quot;&gt;vrml1.wrl&quot;) || die &quot;\n

Cannot open $!\n&quot;;<BR>

&nbsp;7 $oldfile = select VRMLFILE;<BR>

&nbsp;8 my $header = VRML::new();<BR>

&nbsp;9 $header-&gt;VRML::startHeader;<BR>

10 $header-&gt;VRML::startSeparator;<BR>

11 $width = 0.01;<BR>

12 my @cyl;<BR>

13 $hi = $#hist + 1;<BR>

14 for ($i = 0; $i &lt; $hi; $i++) {<BR>

15 $v = $hist[$i] / 100;<BR>

16&nbsp;&nbsp;&nbsp;if ($v &gt; 0) {<BR>

17&nbsp;&nbsp;&nbsp;$x = ($i * $width) % 16 ;<BR>

18&nbsp;&nbsp;&nbsp;$y = ($i * $width) / 16 ;<BR>

19&nbsp;&nbsp;&nbsp;$t = $header-&gt;VRML::putCube(<BR>

20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'width' =&gt;

$width, 'height' =&gt; $v, 'depth' =&gt; $width,<BR>

21&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'translation'

=&gt; [$x,$y,0],<BR>

22&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'ambientColor'

=&gt; [$v,$v,$v]<BR>

23&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);<BR>

24&nbsp;&nbsp;&nbsp;}<BR>

25 }<BR>

26 $header-&gt;VRML::stopSeparator;<BR>

27 close VRMLFILE;<BR>

28&nbsp;&nbsp;select $oldfile;<BR>

29 }</FONT></TT>

</BLOCKQUOTE>

<P>

Note that in line 7, we take care to store away the file handle

of the current output file when we set the default file handle

to <TT><FONT FACE="Courier">VRMLFILE</FONT></TT> with the <TT><FONT FACE="Courier">select</FONT></TT>

call. The <TT><FONT FACE="Courier">for</FONT></TT> loop in line

14 steps through the entire <TT><FONT FACE="Courier">hist</FONT></TT>

array and generates code to print a cube. Lines 19 through 23

are the statements for generating VRML code for a cube. Line 26

terminates the VRML output. The file handle is used to close the

VRML output file in line 27. After the VRML output file is closed,

we reset the default file handle (in line 28) to whatever it was

prior to the <TT><FONT FACE="Courier">select</FONT></TT> call.

<H2><A NAME="APartingNote"><B><FONT SIZE=5 COLOR=#FF0000>A Parting

Note</FONT></B></A></H2>

<P>

The number of routines in this chapter (and other chapters, for

that matter) make it hard for me to look them up by name. You

can use the following script to quickly get listings of all the

subroutine functions you want in a bunch of source code files.

See Listing 29.6.

<HR>

<BLOCKQUOTE>

<B>Listing 29.6. Printing the subroutines in source files.<BR>

</B>

</BLOCKQUOTE>

<BLOCKQUOTE>

<TT><FONT FACE="Courier">&nbsp;1 #!/usr/bin/perl<BR>

&nbsp;2 #<BR>

&nbsp;3 # Display all the subroutines in the files on the command

line<BR>

&nbsp;4 #<BR>

&nbsp;5 while (&lt;&gt;) {<BR>

&nbsp;6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chop;<BR>

&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (/^\s*sub\s+(\w+(?:[:`]+))?(\w+)/)

{<BR>

&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$name = $2;<BR>

&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print $ARGV, &quot;:Line

$.&nbsp;&nbsp;:&quot;, &quot;$name\n&quot;;<BR>

10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;close(ARGV) if eof();&nbsp;&nbsp;&nbsp;&nbsp;#

reset line numbers<BR>

11&nbsp;&nbsp;&nbsp;&nbsp;}<BR>

12&nbsp;}</FONT></TT>

</BLOCKQUOTE>

<HR>

<P>

The key line to look at is the search pattern defined in line

7:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">/^\s*sub\s+(\w+(?:[:`]+))?(\w+)/</FONT></TT>

</BLOCKQUOTE>

<P>

Basically, the first part <TT><FONT FACE="Courier">\s*sub\s*</FONT></TT>

looks for all whitespaces (tabs and spaces) before and after the

string sub. Then it looks for an <TT><FONT FACE="Courier">(</FONT></TT>

open parenthesis, followed by a word as specified by <TT><FONT FACE="Courier">\w</FONT></TT>.

If the word that matches the <TT><FONT FACE="Courier">\w</FONT></TT>

is followed by <TT><FONT FACE="Courier">::</FONT></TT> or a single

quote <TT><FONT FACE="Courier">`</FONT></TT>, then it's considered

a class specification and accepted as such since the second question

mark <TT><FONT FACE="Courier">?</FONT></TT> allows for more than

one occurrence of such words. Note that we did not look for an

open curly brace for the subroutine code on the same line as the

subroutine declaration since the open curly brace may be on the

next line following the subroutine declaration.

<P>

The program shown in Listing 29.6 is not foolproof because it

looks for a very specific pattern in defining subroutines. However,

it will catch most subroutine definitions. The output from this

script gives you a listing of all subroutines declared in a file.

It even attempts to print subroutines in <TT><FONT FACE="Courier">*.pm</FONT></TT>

files. Actually, this script can write out a tags file by replacing

the <TT><FONT FACE="Courier">print</FONT></TT> line with the following

line:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">print &quot;$name\t$ARGV\t\/^$_\/\n&quot;</FONT></TT>

</BLOCKQUOTE>

<P>

Hope this will help you keep your functions in order! ;-)

<H2><A NAME="Summary"><B><FONT SIZE=5 COLOR=#FF0000>Summary</FONT></B></A>

</H2>

<P>

This chapter is designed to show you how to use the techniques

you learned in the previous chapters of this book by developing

prototyping algorithms using Perl. The built-in mathematical and

array functions of Perl can be assets when used for developing

algorithms. In this chapter we worked on a filtering algorithm

for an image, as well as reading and archiving to disk. You even

can use previously developed modules and available tools to see

how your prototypes work.

<P>

<HR WIDTH="100%"></P>



<CENTER><P><A HREF="ch28.htm" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/ch28.htm"><IMG SRC="pc.gif" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/pc.gif" BORDER=0 HEIGHT=88 WIDTH=140></A><A HREF="#CONTENTS"><IMG SRC="cc.gif" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/cc.gif" BORDER=0 HEIGHT=88 WIDTH=140></A><A HREF="index.htm" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/index.htm"><IMG SRC="hb.gif" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/hb.gif" BORDER=0 HEIGHT=88 WIDTH=140></A><A HREF="ch30.htm" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/ch30.htm"><IMG 

SRC="nc.gif" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/nc.gif" BORDER=0 HEIGHT=88 WIDTH=140></A></P></CENTER>



<P>

<HR WIDTH="100%"></P>



</BODY>

</HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -