9512.net
甜梦文库
当前位置:首页 >> >>

MasPar Image Processing Library Reference Manual


MasPar Image Processing Library (MPIPL) Reference Manual
Software Version 1.2

Document Part Number: 9302-0300 Revision: A3 July 1992 MasPar Computer Corporation?

MasPar Image Processing Library Reference Manual Document Part Number 9302-0300, Revision A3, July 1992 This manual describes the MasPar Image Processing Library routines, Version 1.2, released in July 1992.
MasPar Computer Corporation makes no representation or warranties regarding the contents of this document and reserves the right to revise this document or make changes in the specifications of the product described herein at any time without obligation to notify any person of such revision or change. Copyright ? 1991, 1992 MasPar Computer Corporation, Sunnyvale, California All Rights Reserved Printed in the United States of America This manual, its format, and the hardware, software, and microcode described in it are copyrighted by MasPar Computer Corporation and may not be reproduced, transmitted, transcribed, stored in a retrieval system, or translated into any language or computer language in any form or by any means, electronic, mechanical, magnetic, optical, chemical, manual, or otherwise, without the express written permission of MasPar Computer Corporation. Restricted Rights Legend: The software and microcode documented in this manual has been developed at private expense and is not in the public domain. Use, duplication, or disclosure by the U.S. Government is subject to restrictions as set forth in subdivision (c)(1)(i) of the Rights in Technical Data and Computer Software clause at 52.227-7013. MasPar and the MasPar logo are registered trademarks of MasPar Computer Corporation. MasPar Programming Environment, MasPar Fortran, MasPar Programming Language, MasPar Data Display Library, MasPar Image Processing Library, MasPar Mathematics Library, and MasPar Parallel Disk Array are trademarks of MasPar Computer Corporation. DEC, DEC AVS, DECnet, DECwindows, DECstation, ULTRIX, VAX, and VAXstation are trademarks of Digital Equipment Corporation. UNIX is a registered trademark of the American Telephone and Telegraph Company. X Window System is a trademark of the Massachusetts Institute of Technology. Motif is a trademark of the Open Software Foundation, Inc. NFS is a trademark of Sun Microsystems. AVS is a trademark of Advanced Visual Systems, Inc. PostScript is a registered trademark of Adobe Systems Incorporated. Sun, SunOS, Sun-4, SPARC, and SPARCstation are trademarks of Sun Microsystems, Inc.

MasPar Computer Corporation 749 North Mary Avenue Sunnyvale, California 94086 1-800-526-0916 1-408-736-9560 (FAX)

Preface

MPIPL is the MasPar Image Processing Library. It is a library of MPL routines that you can use to perform various operations on images.

How to Use This Manual
Chapter 1 introduces broad categories of routines and discusses some performance issues. Chapter 2 discusses the data mapping technique you must use to store your image in the PE array. Chapter 3 shows how to compile programs that use MPIPL routines, and it discusses the MPIPL example programs. Chapter 4 shows the calling syntax of each MPIPL routine and describes how to use each routine. The examples shown in those man pages are code fragments. See Chapter 3 for complete program examples. Appendix A shows the file $MP_PATH/include/mpl/mpipl.h.

Preface

i

ii

Preface

Prerequisites
Since the MPIPL routines can only be called from MPL code, you should already be familiar with MPL before you use the MPIPL routines. See the MPL Reference Manual and the MPL User Guide. You may also be interested in the MPL parallel I/O routines to capture your image in a file and in the MPDDL (MasPar Data Display Library) routines to display your image on a screen. See the MPL Reference Manual and the MPDDL Reference Manual.

References
1. MasPar system overview. PN 9300-0100. MasPar architecture and products. Gives a birds-eye view of the

2. MasPar commands reference manual. PN 9300-0300. Provides syntax and usage for MasPar commands such as compilers and library management tools. Discusses the MP_PATH environment variable. See the mpld man page for a list of MPL reserved names. 3. MPPE quick reference. PN 9305-0300. Provides a quick reference to the most used features of the MPPE (MasPar Programming Environment). 4. MPPE user guide. PN 9305-0000. Explains how to use the MPPE window interface and how to use the tools in the MPPE. 5. MasPar Fortran reference manual. PN 9303-0000. Provides a complete reference to the syntax and usage of MasPar Fortran. Describes all intrinsics. 6. MasPar Fortran user guide. PN 9303-0100. Explains how to convert an f77 program to MasPar Fortran and call other languages from within MasPar Fortran. 7. MPL reference manual. PN 9302-0000. Describes MPL (MasPar Programming Language), including the parallel I/O and VME access libraries. 8. MPL user guide. PN 9302-0101. Discusses MPL porting and performance issues and common mistakes. 9. MPDDL reference manual. PN 9302-0200. (MasPar Data Display Library). 10. MPIPL reference manual. PN 9302-0300. Image Processing Library). 11. MPML reference manual. PN 9302-0400. Mathematics Library). Describes the MPDDL Describes the MPIPL (MasPar Describes the MPML (MasPar

12. MasPar 3000-series parallel disk array manual. PN 9300-5005.

Preface

iii

13. MasPar 4000-series parallel disk array manual. PN 9300-9040. 14. MasPar VME 6U adapter manual. PN 9300-5007. 15. MasPar VME 9U adapter manual. PN 9300-9019. 16. MasPar parallel VME manual. PN 9300-9018. 17. MasPar architecture specification. PN 9300-5001. Discusses the system architecture, theory of operations, register usage, and MasPar assembler.

Help
To get general information about MasPar, including how to contact MasPar, type ‘‘man maspar’’ at the shell prompt. To get on-line help on MasPar commands, compilers, and library routines, type ‘‘man -k maspar’’ or ‘‘apropos maspar’’ at the shell prompt to see what MasPar man pages are available. To get more general help on how to program the MasPar parallel processing system, study the examples in $MP_PATH/examples. If you have additional questions, or if you want to report defects or make comments on MasPar products and documentation, you can contact MasPar via electronic mail, telephone, or FAX at the following locations: North America and the Pacific Rim: Customer Support MasPar Computer Corporation 749 North Mary Avenue Sunnyvale California 94086 U.S.A. phone: 1-800-526-0916 (8-6 PST) FAX: 1-408-736-9560 email: support@maspar.com Europe and the United Kingdom: Customer Support MasPar Computer Ltd. 8 Commerce Park Brunel Road Theale RG7 4AB Berkshire England phone: +44-734-305444 (9-5 BST) FAX: +44-734-305505 email: support@mpread.co.uk

iv

Preface

Notation Conventions
In running text: typewriter = keywords, examples, input, output italic = variables quotation marks ‘‘ ’’ = literals In command syntax lines: italic = variables
opt

= optional

Chapter 1 Introduction

The MPIPL (MasPar Image Processing Library) is a set of low-level, memory-to-memory routines that help you efficiently manipulate images that are stored in the PE array. These routines give you control over the execution stream, creation and deletion of temporary space, and reuse of previously generated images.

Calling the Routines
The MPIPL is an MPL (MasPar Programming Language) library. This means you call the MPIPL routines from within your MPL code. You can use the MPIPL routines in any program that is written in a language that can call MPL code. This includes MPF (MasPar Fortran), ULTRIX C, and VAX Fortran programs that call MPL code. For more information, see the MasPar Fortran Programming Manuals set and the MPL Programming Manuals set. Note that your program will be much easier to manage if you do all the image processing in MPL. This way, you avoid converting your image between different data mappings. See Chapter 2 for more information on converting data mappings. The calling syntax for each MPIPL routine is shown in Chapter 4. Descriptions of the routines are also given in that chapter. For more information about how to write MPL code (how to fit these calls into your MPL code), see the MPL Programming Manuals set. Chapter 3 shows some example programs that contain MPIPL calls.

Introduction

1-1

1-2

Introduction

Virtualizing Images
If the number of data points in your image is greater than the number of PEs in your MasPar? machine, then you must use some kind of virtualization technique in your MPL code to store your image in the PE array. See Chapter 2 for more information. The MPIPL supports only two-dimensional hierarchical virtualization. Your image data must be mapped to the PE array in this way; otherwise, results returned by the MPIPL routines are undefined.

Displaying Images
MPIPL routines can be used in conjunction with MPDDL (MasPar Data Display Library) routines. This allows you to display your images on most X window graphics devices. See page 3-2 and the MPDDL Reference Manual for more information on the MPDDL routines. The examples in Chapter 3 use MPIPL plotting routines that have been written using MPDDL routines.

Kinds of Image Manipulations
Two broad categories of image manipulations are arithmetic operations and operations to make the image more clear. Within this latter category, two broad subcategories are convolutions and frequency-based filtering. This section discusses these image manipulations in very general terms and offers a few comments on how to achieve better performance. Note that doing all the image processing in MPL saves you the time of converting your image between different data mappings.

Frequency-Based Filtering
This is a three-step process: 1. Forward FFT 2. Filter: high- or low-pass Butterworth or high- or low-pass exponential 3. Inverse FFT The FFTs account for almost all the time in this process; the filtering operations take very little time by comparison.

Introduction

1-3

Convolutions
In addition to frequency-based filtering, a second way to make an image more clear is to convolute it. Convolutions include regional averaging and gradient searches (looking for where the image changes).

Example: Clarifying an Image
For best performance, you want to use the simplest set of operations you can to accentuate what you are looking for. For example, to find the edges of an image, you could use either one of the following two methods: 1. FFT, high-pass filter, inverse FFT, and threshold operation or 2. Sobel convolution (see the mpiorthograd* routines) The Sobel convolution is usually faster than the FFT method, but the FFT method is much more general. The Sobel convolution will only find local, or very sharp, edges. The FFT method will find local edges and will also find global, or more gradual, edges.

Arithmetic Operations
Arithmetic operations on an image include adding, thresholding, multiplying, and scaling. The most efficient way to perform these kinds of operations is to use the mpipntwise utility. See Chapter 5 to learn how to use mpipntwise. If you have a series of arithmetic operations to do on one image or one set of images, using mpipntwise to generate a routine to do all of them requires fewer loads and stores than calling each MPIPL arithmetic routine separately. This can be a significant performance factor since loads and stores of a large image are much more expensive than arithmetic operations on the image. For 8- and 16-bit operations, the loads and stores generally take more time than the arithmetic operation. For example, an 8-bit load or store takes about five times as many clocks as an 8-bit add operation.

Example: Arithmetic Operations
Say that you want to perform the following operations, where A, B, C, and D are images stored in the PE array: E = A + B * (C/D) Calling each MPIPL routine separately requires six image loads and three image stores, as follows: E = C/D load C, load D, store E E *= B load E, load B, store E E += A load E, load A, store E

1-4

Introduction

Using mpipntwise requires four image loads and one image store, as follows: E = A + B * (C/D) load A, B, C, and D; store E

Chapter 2 Data Mapping

If the number of data points in your image is greater than the number of PEs in your MasPar? machine, then you must use some kind of virtualization technique in your MPL code to store your image in the PE array. The MPIPL library supports only two-dimensional hierarchical virtualization. Your image data must be mapped to the PE array in this way; otherwise, results returned by the MPIPL routines are undefined. There are four ways to get an image on the DPU in a two-dimensional hierarchical mapping: 1. If you already have an image on disk with the pixel data in raster scan order, you can use the MPIPL mpiread* and mpiwrite* routines (see Chapter 4). 2. If you already have an image on disk with the pixel data in a one-dimensional cut-and-stack, two-dimensional cut-and-stack, or one-dimensional hierarchical mapping, then you can use the MPIPL data mapping conversion routines (see below). 3. If you already have an image on disk with the pixel data in some other mapping, then you need to write your own code to convert it to two-dimensional hierarchical, one-dimensional hierarchical, one-dimensional cut-and-stack, or two-dimensional cut-and-stack mapping. 4. If you use any of the MPIPL image generation routines, then the resultant image data is in a two-dimensional hierarchical mapping. See the examples in Chapter 3.

Data Mapping

2-1

2-2

Data Mapping

This chapter discusses converting between data mappings and then shows how the MPIPL routines define a two-dimensional hierarchical mapping.

Data Mapping Conversions
The easiest way to manage your program is to do all the image processing in MPL. This way, you avoid writing extra code to convert your image from one data mapping to another and back again. Note that MPF automatically stores all arrays using cut-and-stack mapping, while the MPIPL routines operate only on images stored using two-dimensional hierarchical mapping. MPF stores one-dimensional arrays using one-dimensional cut-and-stack mapping, and it stores all other arrays using two-dimensional cut-and-stack mapping. MPIPL provides routines for converting your image into two-dimensional hierarchical mapping from one-dimensional cut-and-stack, two-dimensional cut-and-stack, or one-dimensional hierarchical mapping. These routines are mpi1dcsto2dh8(), mpi2dcsto2dh8(), and mpi1dhto2dh8(). See Chapter 4 for more information on these routines. MPIPL also provides similar routines for converting your data from two-dimensional hierarchical mapping back to one-dimensional cut-and-stack, two-dimensional cut-and-stack, or one-dimensional hierarchical mapping.

Two-Dimensional Hierarchical Mapping
For hierarchical virtualizations, neighboring pixels (virtual neighbors) in an image are stored on the same PE (are physical neighbors) whenever possible. Storing virtual neighbors on the same PE minimizes PE communication. For example, if an image is four times larger horizontally than the physical number of PEs in a row of the PE array (nxproc), then each PE holds four pixel values, in the following way: ? pixels 0, 1, 2, and 3 are stored on PE0 in memory locations 0, 1, 2, and 3, respectively, ? pixels 4, 5, 6, and 7 are stored on PE1 in memory locations 0, 1, 2, and 3, respectively, and so forth. Similarly, if an image is three times larger vertically than the physical number of PEs in a column of the PE array (nyproc), then each PE holds three pixel values, segregated into groups of three. For two-dimensional hierarchical virtualizations, both the horizontal and vertical image sizes can be larger than the physical number of PEs in their respective directions. Both virtualizations occur simultaneously. The x-direction virtualization is dominant, so that the memory layers in the PE contain first the first x row of pixels, then the second x row of pixels, and so on.

Data Mapping

2-3

In general, the MPIPL routines are more efficient if your image size is a power of two in both directions. Some MPIPL routines perform equally well independent of image size, but others, such as the FFT routines, require the image size to be a power of two in both directions. Figure 2-1 shows how data elements (or pixel values) are mapped onto the PE array in two-dimensional hierarchical virtualization. This figure assumes that you have four times as many data elements as you have PEs: twice as many horizontal data elements as horizontal PEs (2*nxproc horizontal data elements) and twice as many vertical data elements as vertical PEs (2*nyproc vertical data elements). This figure also assumes nxproc = nyproc = 2 and thus nproc = 4.
PE0 D0 L0 PE0 D1 L1 PE1 D2 L0 PE1 D3 L1

PE0 D4 L2

PE0 D5 L3

PE1 D6 L2

PE1 D7 L3

PE2 D8 L0

PE2 D9 L1

PE3 D10 L0

PE3 D11 L1

PE2 D12 L2

PE2 D13 L3

PE3 D14 L2

PE3 D15 L3

D = data element or pixel L = data layer = PE boundaries = boundaries between memory layers on the same PE

Figure 2-1

Two-Dimensional Hierarchical Data Mapping

2-4

Data Mapping

Chapter 3 Examples

This chapter shows examples of complete programs that use MPIPL routines. In contrast, Chapter 4 presents each routine alphabetically and shows only code fragments for examples.

Include File
Remember to include the header file for the MPIPL library whenever you use one of these routines (a copy of this file is shown in Appendix A):
#include <mpipl.h>

Compiling
Remember to link in the MPIPL library when you compile. An example compilation command is as follows:
mpl_cc fileName.m -lmpipl

The MPIPL library contains three routines to help you display your results graphically. These routines are called open_plot(), image_plot(), and close_plot(). These plotting routines use the MPDDL routines (see the MPDDL Reference Manual).
Examples 3-1

3-2

Examples

If you use any of these plotting routines, be sure to link in the MPDDL library in addition to the MPIPL library as follows:
mpl_cc fileName.m -lmpipl -lmpddl

If you do not, you will get a link error. These MPIPL plotting routines use the MPDDL_DEVICE_X_APPROX feature of the MPDDL routines. This feature helps preserve colors in your other windows while your MPIPL image is displayed, since most devices support only one color map at a time. This means that your MPIPL image probably will not have access to 256 distinct colors. If you are not satisfied with the color resolution of your MPIPL image, you can call the MPDDL routines explicitly (instead of using the MPIPL plotting routines) and not use the MPDDL_DEVICE_X_APPROX feature. See the MPDDL Reference Manual for more information. If you do not use MPDDL_DEVICE_X_APPROX, then when you activate the MPIPL ‘‘xmpddl’’ window on a single-color-map display, the rest of your screen may turn black so that you cannot see your other windows or the colors in your other windows may be very different from what you want.

Examples
You can find copies of the examples shown in this chapter in $MP_PATH/examples/mpipl. (See the MasPar Commands manual for a discussion of the MP_PATH environment variable.) Each example is in its own subdirectory. Each of these subdirectories contains two files: a Makefile and a source file (.m). None of these programs require any user input, so you may want to just invoke the executable and watch what happens. You must invoke these demos on the MasPar? front end machine (the DECstation 5000 that is directly connected to the DPU). Otherwise, the program terminates with an error that it could not open the DPU. If you invoke the example and the ‘‘xmpddl’’ window does not display right away, try checking the DPU queue (use mpq) to see whether there is a job ahead of yours. If the display seems to be updated very irregularly, possibly your job is being swapped in and out of the DPU. The descriptions of these examples assume you are displaying the results on a display that is not a monochrome display. The results look quite different if you display them on a monochrome display. See the MPDDL Reference Manual for more information on what you can do if your display looks very different from what is described below.

The Abingdon Cross
This example generates a cross image, adds Gaussian noise to that image, and then removes the noise and enhances the cross. To execute this example, enter either
make PLOT=1

or

Examples

3-3

filterskel rows cols PLOT=1

where rows is the number of pixels in your image in the horizontal direction, and cols is the number of pixels in the vertical direction. The following is what shows in the window where you invoke the example. An ‘‘xmpddl’’ window (see the MPDDL Reference Manual) appears in the upper left corner of your screen. Eight different images are shown in the ‘‘xmpddl’’ window, corresponding to the eight ‘‘Displaying ...’’ lines shown below. Note that the ‘‘xmpddl’’ window remains solid until you select that window (the MPDDL color map is not installed until you select the ‘‘xmpddl’’ window). See below for a discussion of file I/O.
% make PLOT=1 TEST FOR FILTERED SKELETONIZED CROSS Making substitute a.out file you own called /usr/tmp/#msdAAAa18466 transferring 59360 bytes... Displaying cross image ... Type return to continue ... Displaying cross with gaussian ... Type return to continue ... Displaying threshholded cross ... Type return to continue ... Displaying vconvolved cross ... Type return to continue ... Displaying hconvolved cross ... Type return to continue ... Displaying convolution eroded cross ... Type return to continue ... Displaying skeletonized image ... Type return to continue ... Displaying skeleton over original ... Type return to continue ... FILTERED SKELETONIZED CROSS FINISHED

The eight images you should see are described below. You can see how each of these images is produced by searching for the string ‘‘Display’’ in the source file. 1. Cross image. A light gray cross on a darker gray background. 2. Cross with Gaussian noise. Darker overall and peppered with specks. 3. Threshholded cross. More contrast: The background is darker while the cross is lighter. All pixels are now black or white—no shades of gray.

3-4

Examples

4. Vconvolved cross. The background is black and the cross is white. Only a few flecks of noise remain. The vertical lines on the cross are straight, but the horizontal lines are irregular. 5. Hconvolved cross. The cross shifts slightly to the right and the noise is almost all gone. The background is black, the cross is white, and there is only a little irregularity along the edges of the cross. 6. Convolution eroded cross. The cross is a slightly different shape: The arms of the cross are more narrow, and each arm meets its neighbor in two 135-degree angles instead of one 90-degree angle. 7. Skeletonized image. Two crossed thin lines with a fin at each end. 8. Skeleton over original. The skeletonized image is superimposed on the initial cross image. Another way to execute this example is to enter simply ‘‘make’’ at the command prompt. If you do this, you do not get the graphic display described above (the default display argument is ‘‘PLOT=0’’). You can read the initial image from a file instead of having the program generate the initial image, and you can write the results to a file. Use the MPL parallel I/O routines (see the MPL Reference Manual) or the mpiread2d8() and mpiwrite2d8() MPIPL routines to read images from a file and write results to a file. The source code for this example is shown below. Note that five unsigned char type pointers are defined to hold the images at various stages of this example, and these are reused as needed. There is also a larger work array that is required for the skeletonization routine. The amount of memory allocated for each of these image holder variables is a function of the size of the image and the virtualization ratio. The size of the image is specified by the user. The virtualization ratio is found using the macros MPIXVR and MPIYVR that are defined in mpipl.h (see Appendix A). These macros return the number of image points that are assigned to each PE, rounding up to the nearest integer number of points per PE and using all the PEs (unless the image is smaller than the machine size). The MPIPL image generation routines take the image size specified by the user and generate the image in a two-dimensional hierarchical mapping.
/* $Header: jah.ps,v 1.1 92/07/30 08:40:21 alta Exp $ Copyright (c) 1990 MasPar Computer Corporation All Rights Reserved This program has been licensed subject to restrictions on reproduction, use and disclosure and this notice does not imply that the program or the related ideas or algorithms are in the public domain. */ #include #include #include #include <mpl.h> <stdio.h> <string.h> <mpipl.h>

extern plural char *p_malloc();

Examples

3-5

main(argc,argv) int char { int unsigned unsigned unsigned unsigned int char char char rows, cols, display; xvr, yvr, size, i, j; kernel[17]; * imag0, * work; * imag1, * imag2, * imag3, * imag4; argc; *argv[];

plural plural

#ifndef NOARGS if (argc < 4) { printf("Usage: %s <rows> <cols> <display>\n", argv[0]); exit(1); } rows = atoi(argv[1]); cols = atoi(argv[2]); display = atoi(argv[3]); #else rows = 512; cols = 512; display = 0; #endif xvr = MPIXVR(cols); yvr = MPIYVR(rows); size = xvr * yvr; for (i=0; i<17; i++) kernel[i] = 1; imag0 = (plural unsigned char imag1 = (plural unsigned char imag2 = (plural unsigned char imag3 = (plural unsigned char imag4 = (plural unsigned char work = (plural unsigned char if (imag0 == NULL || imag1 == exit(1);

* ) p_malloc(size); * ) p_malloc(size); * ) p_malloc(size); * ) p_malloc(size); * ) p_malloc(size); * ) p_malloc(8*size); NULL || imag2==NULL || imag3==NULL)

/* Generate the cross image. */ mpigencross8(32,0,64,64,imag2,rows,cols); mpigenconst8(128,imag3,rows,cols); mpiadd8(imag2,imag3,rows,cols,imag0); /* Display image. */ if (display) { open_plot(rows,cols); printf("\tDisplaying cross image ...\n"); image_plot(imag0); } /* Generate a gaussian noise image. */ mpigengauss8(0.0,32.0,imag2,rows,cols); mpigengauss8(0.0,32.0,imag3,rows,cols); /* Add gaussian noise to cross */ mpiadd8(imag0,imag2,rows,cols,imag1); mpisub8(imag1,imag3,rows,cols,imag1); /* Display image. */ if (display) { printf("\tDisplaying cross with gaussian ...\n");

3-6

Examples

image_plot(imag1); } /* threshold the image */ mpithresh8(imag1,rows,cols,150,imag0); /* Display image. */ if (display) { printf("\tDisplaying thresholded cross ...\n"); image_plot(imag0); } /* /* /* /* vertical convolution of the image */ first divide by 17 */ then do convolution */ then re-threshold */

mpigenconst8(17,imag3,rows,cols); mpidiv8(imag0,imag3,rows,cols,imag2); mpivconvolve8(imag2,rows,cols,kernel,17,imag0,work); mpithresh8(imag0,rows,cols,128,imag2); /* Display image. */ if (display) { printf("\tDisplaying vconvolved cross ...\n"); image_plot(imag2); } /* /* /* /* horizontal convolution of the image */ first divide by 17 */ then do convolution */ then re-threshold */

mpidiv8(imag2,imag3,rows,cols,imag0); mpihconvolve8(imag0,rows,cols,kernel,17,imag3,work); mpithresh8(imag3,rows,cols,128,imag2); /* Display image. */ if (display) { printf("\tDisplaying hconvolved cross ...\n"); image_plot(imag2); } /* /* /* /* 3x3 median convolution of the image */ first divide by 9 */ then do convolution */ then re-threshold */

mpigenconst8(9,imag3,rows,cols); for (i=0; i<15; i++) { mpidiv8(imag2,imag3,rows,cols,imag0); mpiconvolve8(imag0,rows,cols,kernel,3,3,imag4,work); mpithresh8(imag4,rows,cols,200,imag2); } /* Display image. */ if (display) { printf("\tDisplaying convolution eroded cross ...\n"); image_plot(imag2); } /* skeletonize the image */

Examples

3-7

mpibskel8(imag2,rows,cols,imag0,work); /* Display image. */ if (display) { printf("\tDisplaying skeletonized image ...\n"); image_plot(imag0); } /* Overlap skeletonized with gauss/cross image */ mpiaddclip8(imag0,imag1,rows,cols,imag2); /* Display image. */ if (display) { printf("\tDisplaying skeleton over original ...\n"); image_plot(imag2); close_plot(); } p_free(imag0); p_free(imag1); p_free(imag2); p_free(imag3); p_free(imag4); p_free(work); exit(0); } /* main */

FFT Filterings
This example filters simple generated images using different types of filters based on FFTs. You can run three different test cases, depending on the options you select when you invoke the example. To execute this example, enter either
make PLOT=1

or
filterfft testName rows cols PLOT=1

where rows is the number of pixels in your image in the horizontal direction, and cols is the number of pixels in the vertical direction. If you invoke the executable explicitly, you need to specify one of the following three values for testName: ‘‘2dfft’’, ‘‘hpfexp’’, or ‘‘lpfexp’’. If you use ‘‘make’’, all three tests are performed automatically. The following is what shows in the window where you invoke the example. An ‘‘xmpddl’’ window (see the MPDDL Reference Manual) appears in the upper left corner of your screen. Six different images are shown in the ‘‘xmpddl’’ window, corresponding to the six ‘‘Displaying ...’’ lines shown below: one generated input image and one output image for each of the three tests. Note that the ‘‘xmpddl’’ window remains solid until you select that window (the MPDDL color map is not installed until you select the ‘‘xmpddl’’ window), and a new ‘‘xmpddl’’ window is created for each of the three tests. See below for a discussion of file I/O.

3-8

Examples

% make PLOT=1 TEST FOR FFT FILTERING Making substitute a.out file you own called /usr/tmp/#msdAAAa03137 transferring 59360 bytes... Displaying saw-toothed test image ... Type return to continue ... Displaying output image ... Type return to continue ... Making substitute a.out file you own called /usr/tmp/#msdAAAa03145 transferring 59360 bytes... Displaying saw-toothed test image ... Type return to continue ... Displaying output image ... Type return to continue ... Making substitute a.out file you own called /usr/tmp/#msdAAAa03153 transferring 59360 bytes... Displaying saw-toothed test image ... Type return to continue ... Displaying output image ... Type return to continue ... FFT FILTERING FINISHED

The six images you should see are described below. You can see how each of these images is produced by searching for the string ‘‘Display’’ in the source file. In all three cases, both an FFT and an inverse FFT operation are performed. In the second and third cases, another filtering operation is performed between the FFT and the inverse FFT operations. The first, third, and fifth images are exactly alike because they are generated with the same call. The second image also should look exactly the same as the first image because between the first and second images in this example the program performs only an FFT and then the inverse of that FFT operation. The fourth and sixth images are both a set of vertical lines; in each case, a similar filtering operation is performed between the FFT and the inverse FFT operations, but the filtering is done with respect to a different edge of the original image. If you enter a number larger than ‘‘1’’ for the value of ‘‘PLOT’’, you will get some intermediate results: the real and imaginary parts of the image at intermediate steps in each conversion. Some of these displays are all black because there is no data of that kind at that step (for example, no imaginary part). Another way to execute this example is to enter simply ‘‘make’’ at the command prompt. If you do this, you do not get the graphic display described above (the default display argument is ‘‘PLOT=0’’). You can read the initial image from a file instead of having the program generate the initial image, and you can write the results to a file. Use the

Examples

3-9

MPL parallel I/O routines (see the MPL Reference Manual) or the mpiread2d8() and mpiwrite2d8() MPIPL routines to read images from a file and write results to a file. The source code for this example is shown below. Note that four pointers are defined to hold the images and work areas at various stages of this example, and these are reused as needed. These can be freed at any time during the test sequence or at the end of the test sequence. The amount of memory allocated for each of these image holder variables is a function of the size of the image and the virtualization ratio. The size of the image is specified by the user. The virtualization ratio is found using the macros MPIXVR and MPIYVR that are defined in mpipl.h (see Appendix A). These macros return the number of image points that are assigned to each PE, rounding up to the nearest integer number of points per PE and using all the PEs (unless the image is smaller than the machine size). The MPIPL image generation routines take the image size specified by the user and generate the image in a two-dimensional hierarchical mapping. The generated image data is converted to floating point before it is operated on by an FFT or filtering routine. Then it is converted back to 8-bit data before it is displayed. After the FFT is performed, the data values are out of the range [0,255], and they would have to be scaled before they could be plotted.
/* Copyright (c) 1990 MasPar Computer Corporation All Rights Reserved This program has been licensed subject to restrictions on reproduction, use and disclosure and this notice does not imply that the program or the related ideas or algorithms are in the public domain. */ #include #include #include #define #define <mpl.h> <stdio.h> <mpipl.h> CUTOFF 0.5 ORDER 1

extern plural char *p_malloc(); main(argc,argv) int char { plural plural plural plural plural int unsigned int unsigned char unsigned char float float float rows, cols, op, display; xvr, yvr, size, i, diff; * bsrc, * sptr; * bdest, * dptr; * src; * dest; * work; argc; * argv[];

if (argc < 5) { fprintf(stderr,"Usage: %s <routine> <rows> <cols> <display>\n", argv[0]); exit(1); }

3-10

Examples

/* Parse which routine to test. */ if (strcmp("2dfft",argv[1]) == 0) { op = 1; } else if (strcmp("hpfexp",argv[1]) == 0) { op = 2; } else if (strcmp("lpfexp",argv[1]) == 0) { op = 3; } else { fprintf(stderr,"Usage: %s {2dfft, hpfexp, lpfexp} \ <rows> <cols> <display>\n",argv[0]); exit(1); } /* Read the rows and columns. */ rows = atoi(argv[2]); if (rows <= 0) { fprintf(stderr, "Usage: %s <routine> <rows > 0> <cols> <display>\n", argv[0]); exit(1); } else if (rows & (rows-1)) { fprintf(stderr,"Usage: %s <routine> <2^n> <cols> <display>\n", argv[0]); exit(1); } cols = atoi(argv[3]); if (cols <= 0) { fprintf(stderr, "Usage: %s <routine> <rows> <cols > 0> <display>\n", argv[0]); exit(1); } else if (cols & (cols-1)) { fprintf(stderr,"Usage: %s <routine> <rows> <2^n> <display>\n", argv[0]); exit(1); } /* Read the display option. */ display = atoi(argv[4]); if (display<0 || display>2) { fprintf(stderr,"Usage: %s <routine> <rows> <cols> {0, 1, 2}\n", argv[0]); exit(1); } xvr = mpixvr(cols); yvr = mpiyvr(rows); size = xvr * yvr; bsrc = (plural unsigned char * ) p_malloc(size * sizeof(char )); bdest = (plural unsigned char * ) p_malloc(size * sizeof(char )); src = (plural float * ) p_malloc(size*2*sizeof(float)); dest = (plural float * ) p_malloc(size*2*sizeof(float)); work = (plural float * ) p_malloc(size*3*sizeof(float)); if (bsrc == NULL || src == NULL || dest == NULL || work == NULL) { fprintf(stderr,"Insufficient PMEM"); exit(2); } if (display > 0) open_plot(rows,cols); /* Generate the image and display it. */ mpigensaw8(255.0,cols/8.0,0.0,0.0,0.0,bsrc,rows,cols); if (display > 0) {

Examples

3-11

printf("\tDisplaying saw-toothed test image ...\n"); image_plot(bsrc); } /* Convert to complex float and display the real and imaginary parts */ mpiconv8cf(bsrc,rows,cols,src); if (display > 1) { mpiconvcfr8(src,rows,cols,bdest); printf("\tDisplaying real part of converted input image ...\n"); image_plot(bdest); mpiconvcfi8(src,rows,cols,bdest); printf("\tDisplaying imaginary part of converted input image ...\n"); image_plot(bdest); } switch (op) { case 1: /* Do FFT. */ mpi2dfft(src,rows,cols,dest,work); /* Display FFT. */ if (display > 1) { mpiconvcfr8(dest,rows,cols,bdest); printf("\tDisplaying real part of FFT’d image ...\n"); image_plot(bdest); mpiconvcfi8(dest,rows,cols,bdest); printf("\tDisplaying imaginary part of FFT’d image ...\n"); image_plot(bdest); } /* Do iFFT. */ mpi2difft(dest,rows,cols,src,work); /* Display iFFT. */ if (display > 1) { mpiconvcfr8(src,rows,cols,bdest); printf("\tDisplaying real part of iFFT’d image ...\n"); image_plot(bdest); mpiconvcfi8(src,rows,cols,bdest); printf("\tDisplaying imaginary part of iFFT’d image ...\n"); image_plot(bdest); } break; case 2: /* Do FFT. */ mpi2dfft(src,rows,cols,dest,work); /* Do Exponential HPF. */ mpihpfexp(dest,rows,cols,CUTOFF,ORDER,work); p_bcopy(work,dest,size*2*sizeof(float)); /* Display filtered image. */ if (display > 1) { mpiconvcfr8(dest,rows,cols,bdest); printf("\tDisplaying real part of HPFEXP’d image ...\n"); image_plot(bdest);

3-12

Examples

mpiconvcfi8(dest,rows,cols,bdest); printf("\tDisplaying imaginary part of HPFEXP’d image ...\n"); image_plot(bdest); } /* Do iFFT. */ mpi2difft(dest,rows,cols,src,work); break; case 3: /* Do FFT. */ mpi2dfft(src,rows,cols,dest,work); /* Do Exponential LPF. */ mpilpfexp(dest,rows,cols,CUTOFF,ORDER,work); p_bcopy(work,dest,size*2*sizeof(float)); /* Display filtered image. */ if (display > 1) { mpiconvcfr8(dest,rows,cols,bdest); printf("\tDisplaying real part of LPFEXP’d image ...\n"); image_plot(bdest); mpiconvcfi8(dest,rows,cols,bdest); printf("\tDisplaying imaginary part of LPFEXP’d image ...\n"); image_plot(bdest); } /* Do iFFT. */ mpi2difft(dest,rows,cols,src,work); break; default: break; } /* Put the real part of the result into a byte-type output image. */ mpiconvcfr8(src,rows,cols,bdest); /* Display output image. */ if (display > 0) { printf("\tDisplaying output image ...\n"); image_plot(bdest); close_plot(); } /* Clean up. */ p_free(work); p_free(dest); p_free(src); p_free(bsrc); exit(0); }

Chapter 4 Reference Pages

This chapter contains some general information about the MPIPL routines, a brief description of each MPIPL routine, and then a reference page for each routine. The reference pages are arranged in alphabetical order. For examples of complete programs that use these routines, see Chapter 3. These routines are MPL routines and can only be called from MPL code. You can use the MPIPL routines in any program that is written in a language that can call MPL code. This includes MPF (MasPar Fortran), ULTRIX C, and VAX Fortran programs that call MPL code. Remember to include the header file for the MPIPL library whenever you use any of these routines (a copy of this file is shown in Appendix A):
#include <mpipl.h>

Remember to link in the MPIPL library when you compile. If you use any of the MPIPL plotting routines (open_plot(), image_plot(), or close_plot()), be sure to link in the MPDDL library in addition to the MPIPL library as follows:
mpl_cc fileName.m -lmpipl -lmpddl

See page 3-2 for more information on the MPIPL plotting routines.

Reference Pages

4-1

4-2

Reference Pages

Overview of MPIPL Routines
This section contains a brief description of each MPIPL routine. All of these routines execute in a memory-to-memory fashion and work on entire images, not on segments of images or multiple piece images. All of these routines internally use two-dimensional hierarchical virtualization mapping methods. Routines that only move pixels and do not interpret the pixel values in any way have 8-bit, 16-bit, and 32-bit unsigned versions (indicated by ‘‘8’’, ‘‘16’’, or ‘‘32’’ at the end of the routine name). There are no signed versions of these routines because they are not needed (the unsigned routines work just as well for signed data). The remaining routines have 8-bit unsigned, 16-bit unsigned, and possibly 16-bit signed versions (indicated by ‘‘8’’, ‘‘16’’, or ‘‘16s’’ at the end of the routine name). The routines mpigengrid() and mpigencross() have no signed version because they place no interpretation on the pixel values, and so the unsigned versions work just as well. The routines mpigensine() and mpigensaw() have no signed versions because they produce only non-negative pixel values.

Arithmetic Operations
? Add: mpiadd8(). Adds two images, element-by-element, to form a resultant image of unsigned 8-bit integers. ? Floating point add: mpiaddf(). Adds two images, element-by-element, to form a resultant floating point image. ? Clipped add: mpiaddclip8(). Adds two images, element-by-element, to form a resultant image. Where the result overflows the range of an unsigned 8-bit integer, 255 is returned. ? Subtract: mpisub8(). Subtracts two images, element-by-element, to form a resultant image. ? Floating point subtract: mpisubf(). Subtracts two images, element-by-element, to form a resultant floating point image. ? Clipped subtract: mpisubclip8(). Subtracts two images, element-by-element, to form a resultant image. Where the result underflows the range of an unsigned 8-bit integer, 0 is returned. ? Multiply: mpimul8(). Multiplies two images, element-by-element, to form a resultant image. ? Floating point multiply: mpimulf(). Multiplies two images, element-by-element, to form a resultant floating point image. ? Clipped multiply: mpimulclip8(). Multiplies two images, element-by-element, to form a resultant image. Where the result overflows the range of an unsigned 8-bit integer, 255 is returned. ? Divide: mpidiv8(). Divides two 8-bit images, element-by-element, to form a resultant 8-bit image.

Reference Pages

4-3

? Floating point divide: mpidivf(). Divides two 8-bit images, element-by-element, to form a resultant floating point image.

Logical Operations
? AND: mpiand8(). ANDs two images, element-by-element, to form a resultant image. ? OR: mpior8(). ORs two images, element-by-element, to form a resultant image. ? XOR: mpixor8(). XORs two images, element-by-element, to form a resultant image.

Data Type Conversions
? From complex imaginary to integer: mpiconvcfi8(). Converts the imaginary part of a complex floating point image representation to an unsigned 8-bit integer. ? From complex real to integer: mpiconvcfr8(). Converts the real part of a complex floating point image representation to an unsigned 8-bit integer. ? From floating point to integer: mpiconvf8(). Converts the current image from 32-bit floating point to unsigned 8-bit integers. ? From scaled floating point to integer: mpisconvf8(). Converts the current image from 32-bit floating point to unsigned 8-bit integers, scaling the floating point values. The floating point values are scaled from their entire dynamic range into a subset of the range of unsigned 8-bit integers as specified by input variables. ? From scaled complex imaginary to integer: mpisconvcfi8(). Converts the imaginary part of a complex floating point image representation to an unsigned 8-bit integer, scaling the floating point values. The floating point values are scaled from their entire dynamic range into a subset of the range of unsigned 8-bit integers as specified by input variables. ? From scaled complex real to integer: mpisconvcfr8(). Converts the real part of a complex floating point image representation to an unsigned 8-bit integer, scaling the floating point values. The floating point values are scaled from their entire dynamic range into a subset of the range of unsigned 8-bit integers as specified by input variables. ? From integer to complex: mpiconv8cf(). Converts the current image from unsigned 8-bit integers to complex floating point. ? From integer to complex imaginary: mpiconv8cfi(). Converts the current image from unsigned 8-bit integers to the imaginary part of a complex floating point representation. The real part of the complex is left unchanged.

4-4

Reference Pages

? From integer to complex real: mpiconv8cfr(). Converts the current image from unsigned 8-bit integers to the real part of a complex floating point representation. The imaginary part of the complex is left unchanged. ? From integer to floating point: mpiconv8f(). Converts the current image from unsigned 8-bit integers to floating point.

Convolutions
? Convolve unsigned, result in bottom right: mpiconvolvebr8(). Performs two-dimensional convolutions of arbitrary size on the image with multipliers as input by the user. The computations are performed with unsigned 8-bit integers (only the lower eight bits of the result are returned). The result is stored at the bottom right pixel of the convolution kernel. ? Convolve unsigned, result in center: mpiconvolve8(). Performs two-dimensional convolutions of arbitrary size on the image with multipliers as input by the user. The computations are performed with unsigned 8-bit integers (only the lower eight bits of the result are returned). The result is stored at the center pixel of the convolution kernel. For even kernel sizes, center is defined as being the lower and right pixel from center. ? Convolve scaled, result in center: mpisconvolve*(). Performs two-dimensional convolutions of arbitrary size on the image with multipliers as input by the user. The computations are performed with either signed or unsigned quantities, as specified by one of the calling parameters. Another calling parameter specifies a scale value to divide by to get the result you want. The result is stored at the center pixel of the convolution kernel. For even kernel sizes, center is defined as being the lower and right pixel from center. The library contains two versions of this routine: 8-bit and 16-bit. ? Convolve float, result in bottom right: mpiconvolvebrf(). Performs two-dimensional convolutions of arbitrary size on the image with multipliers as input by the user. The computations are performed in 32-bit floating point. The result is stored at the bottom right pixel of the convolution kernel. ? Convolve float, result in center: mpiconvolvef(). Performs two-dimensional convolutions of arbitrary size on the image with multipliers as input by the user. The computations are performed in 32-bit floating point. The result is stored at the center pixel of the convolution kernel. For even kernel sizes, center is defined as being the lower and right pixel from center. ? Horizontal convolve unsigned, result in right: mpihconvolvebr8(). Performs one-dimensional horizontal convolutions of arbitrary size on the image with multipliers as input by the user. The computations are performed with unsigned 8-bit integers (only the lower eight bits of the result are returned). The result is stored at the right pixel of the convolution kernel. ? Horizontal convolve unsigned, result in center: mpihconvolve8(). Performs one-dimensional horizontal convolutions of arbitrary size on the image with multipliers as input by the user. The computations are performed

Reference Pages

4-5

with unsigned 8-bit integers (only the lower eight bits of the result are returned). The result is stored at the center pixel of the convolution kernel. For even kernel sizes, center is defined as the pixel to right of center. ? Horizontal convolve scaled, result in center: mpishconvolve*(). Performs one-dimensional horizontal convolutions of arbitrary size on the image with multipliers as input by the user. The computations are performed with either signed or unsigned quantities, as specified by one of the calling parameters. Another calling parameter specifies a scale value to divide by to get the result you want. The result is stored at the center pixel of the convolution kernel. For even kernel sizes, center is defined as the pixel to right of center. The library contains two versions of this routine: 8-bit and 16-bit. ? Horizontal convolve float, result in bottom right: mpihconvolvebrf(). Performs one-dimensional horizontal convolutions of arbitrary size on the image with multipliers as input by the user. The computations are performed in 32-bit floating point. The result is stored at the right pixel of the convolution kernel. ? Horizontal convolve float, result in center: mpihconvolvef(). Performs one-dimensional horizontal convolutions of arbitrary size on the image with multipliers as input by the user. The computations are performed in 32-bit floating point. The result is stored at the center pixel of the convolution kernel. For even kernel sizes, center is defined as the pixel to right of center. ? Vertical convolve unsigned, result in bottom: mpivconvolvebr8(). Performs one-dimensional vertical convolutions of arbitrary size on the image with multipliers as input by the user. The computations are performed with unsigned 8-bit integers (only the lower eight bits of the result are returned). The result is stored at the bottom pixel of the convolution kernel. ? Vertical convolve unsigned, result in center: mpivconvolve8(). Performs one-dimensional vertical convolutions of arbitrary size on the image with multipliers as input by the user. The computations are performed with unsigned 8-bit integers (only the lower eight bits of the result are returned). The result is stored at the center pixel of the convolution kernel. For even kernel sizes, the center pixel is defined as below the center of the kernel. ? Vertical convolve scaled, result in center: mpisvconvolve*(). Performs one-dimensional vertical convolutions of arbitrary size on the image with multipliers as input by the user. The computations are performed with either signed or unsigned quantities, as specified by one of the calling parameters. Another calling parameter specifies a scale value to divide by to get the result you want. The result is stored at the center pixel of the convolution kernel. For even kernel sizes, the center pixel is defined as below the center of the kernel. The library contains two versions of this routine: 8-bit and 16-bit. ? Vertical convolve float, result in bottom right: mpivconvolvebrf(). Performs one-dimensional vertical convolutions of arbitrary size on the image with multipliers as input by the user. The computations are performed

4-6

Reference Pages

in 32-bit floating point. The result is stored at the bottom pixel of the convolution kernel. ? Vertical convolve float, result in center: mpivconvolvef(). Performs one-dimensional vertical convolutions of arbitrary size on the image with multipliers as input by the user. The computations are performed in 32-bit floating point. The result is stored at the center pixel of the convolution kernel. For even kernel sizes, the center pixel is defined as below the center of the kernel.

Edge Detection Operations
? Gradient edge detection: mpiorthograd*(). Performs one of several gradient edge detection operations (depending on what parameters you pass) by applying two convolution kernels to the source image to calculate at each point two orthogonal directional gradients of the image. You can use this routine to compute the gradient magnitude, thresholded gradient magnitude, gradient angle, and quantized gradient angle. The filter argument to this routine takes one of three values (which are defined in mpipl.h): PIXDIFF, ROBERTS, or SOBEL. The library contains three versions of this routine: 8-bit, 16-bit unsigned, and 16-bit signed.

Thickening and Thinning Operations
? Dilate binary: mpibdilate8(). Operates on 3x3 neighborhoods to dilate an image (the 3x3 neighborhood is centered on the pixel). Although the image is composed of unsigned 8-bit integers, this operation is done assuming a binary representation (0 and non-zero). ? Dilate non-binary: mpidilate*(). Operates on 3x3 neighborhoods to dilate an image (the 3x3 neighborhood is centered on the pixel). The library contains three versions of this routine: 8-bit, 16-bit unsigned, and 16-bit signed. ? Erode binary: mpiberode8(). Operates on 3x3 neighborhoods to erode an image (the 3x3 neighborhood is centered on the pixel). Although the image is composed of unsigned 8-bit integers, this operation is done assuming a binary representation (0 and non-zero). ? Erode non-binary: mpierode*(). Operates on 3x3 neighborhoods to erode an image (the 3x3 neighborhood is centered on the pixel). The library contains three versions of this routine: 8-bit, 16-bit unsigned, and 16-bit signed. ? Partial skeletonization: mpibparskel8(). Performs partial skeletonization on an image using a 3x3 neighborhood to thin objects in an image. This may be used iteratively to completely skeletonize objects in images. Although the image is of type unsigned 8-bit integers, it is interpreted as binary composed of 0 and non-zero.

Reference Pages

4-7

? Skeletonization: mpibskel8(). Performs skeletonization on an image by iterative use of partial skeletonization. Although the image is composed of unsigned 8-bit integers, it is treated as binary composed of 0 and non-zero values.

Expanding and Shrinking Operations
? Expand, duplicating: mpiexpandrep*(). Increases the size of an image by duplicating pixels when forming a new image. The library contains three versions of this routine: 8-bit, 16-bit, and 32-bit. ? Expand, interpolating: mpiexpandsm*(). Increases the size of an image by interpolating to obtain new pixels (smoothing) when forming a new image. The library contains three versions of this routine: 8-bit, 16-bit unsigned, and 16-bit signed. ? Shrink, skipping: mpishrinksamp*(). Reduces the size of an image by skipping pixels when forming the new image. The library contains three versions of this routine: 8-bit, 16-bit, and 32-bit. ? Shrink, averaging: mpishrinkavg*(). Reduces the size of an image by averaging pixels (smoothing) when forming the new image. The library contains three versions of this routine: 8-bit, 16-bit unsigned, and 16-bit signed.

Extending and Truncating Operations
? Extend: mpiextend*(). Increases the size of an image by extending the image with addition rows and columns whose contents are undefined. The library contains three versions of this routine: 8-bit, 16-bit, and 32-bit. ? Truncate: mpitrunc*(). Truncates an image to a smaller size by removing pixels from the right and lower boundaries. The library contains three versions of this routine: 8-bit, 16-bit, and 32-bit.

Extracting and Inserting Operations
? Extract: mpiextract*(). Removes a portion of an existing image to create a new image. The library contains three versions of this routine: 8-bit, 16-bit, and 32-bit. ? Insert: mpiinsert*(). Inserts one image into a second image, replacing the pixels of the second image. The library contains three versions of this routine: 8-bit, 16-bit, and 32-bit.

4-8

Reference Pages

Transpositions
? Flip east-west: mpiflipew*(). Rotates an image about the central y-axis of the image. The library contains three versions of this routine: 8-bit, 16-bit, and 32-bit. ? Flip north-south: mpiflipns*(). Rotates an image about the central x-axis of the image. The library contains three versions of this routine: 8-bit, 16-bit, and 32-bit. ? Rotate: mpirotate90d*(). Rotates an image in 90 degree increments about the center point of the image. The library contains three versions of this routine: 8-bit, 16-bit, and 32-bit. ? Translate: mpitransl*(). Translates an image in the horizontal and/or vertical image directions. The portion translated onto the image is set to a uniform, user-specified fill value. The portion translated off the image is discarded. The library contains three versions of this routine: 8-bit, 16-bit, and 32-bit. ? Transpose: mpitranspose*(). Transposes an image. The library contains three versions of this routine: 8-bit, 16-bit, and 32-bit.

Image Generation Routines
? Constant intensity: mpigenconst8(). Generates a constant intensity test image. ? Cross: mpigencross*(). Generates a cross test image, where the width of the crossbars, the intensity of the cross and the intensity of the background can be specified. The library contains two versions of this routine: 8-bit and 16-bit. ? Gaussian noise: mpigengauss*(). Generates a Gaussian noise test image with the mean and variance specified. The library contains three versions of this routine: 8-bit, 16-bit unsigned, and 16-bit signed. ? Grid: mpigengrid*(). Generates a grided test image given the number of vertical and horizontal grid lines, the grid intensity and the background intensity, and the grid line widths. The library contains two versions of this routine: 8-bit and 16-bit. ? Random noise: mpigenrand*(). Generates a random noise test image fill with a uniform distribution of the appropriate type. The library contains three versions of this routine: 8-bit, 16-bit unsigned, and 16-bit signed. ? Saw-toothed: mpigensaw*(). Generates a saw-toothed test image given the amplitude and horizontal and vertical periods. The library contains two versions of this routine: 8-bit and 16-bit. ? Sine wave: mpigensine*(). Generates a sine wave test image given the amplitude and horizontal and vertical periods. The library contains two versions of this routine: 8-bit and 16-bit.

Reference Pages

4-9

Color Operations
? Histogram: mpihist8(). Calculates the histogram of unsigned 8-bit integers that compose an image. ? Histogram equalization: mpihisteq8(). Adjusts the unsigned 8-bit integers that compose an image for better balance without changing the dynamic range. ? Histogram stretch: mpihiststr8(). Adjusts the unsigned 8-bit integers that compose an image for better balance and also changes the dynamic range of these integers. ? Tabular adjust: mpitabgsadj8(). Modifies the unsigned 8-bit integer values of an image by means of a 256-entry mapping table. ? Threshhold: mpithresh8(). Adjusts the contrast of an unsigned 8-bit integer image based upon a threshhold quantity. Values less than the threshhold become 0, other values become 255.

Fourier Transforms
? FFT: mpi2dfft(). Performs a two-dimensional FFT. The FFT computation is performed using 32-bit floating point, complex data types. The input to this routine must be 32-bit floating point, complex. The result produced is 32-bit complex floating point. ? Inverse FFT: mpi2difft(). Performs an inverse two-dimensional FFT. The inverse FFT computation is performed using 32-bit floating point, complex data types. The input to this routine must be 32-bit floating point, complex. The result produced is 32-bit complex floating point.

Filtering Operations
? Butterworth HPF: mpihpfbw(). Performs a high-pass filter operation using a Butterworth cutoff filter. This operation is performed in complex space, and it expects 32-bit complex floating point data as input and result. ? Exponential HPF: mpihpfexp(). Performs a high-pass filter operation using an exponential cutoff filter. This operation is perfomed in complex space, and it expects 32-bit complex floating point data as input and result. ? Butterworth LPF: mpilpfbw(). Performs a low-pass filter operation using a Butterworth cutoff filter. This operation is perfomed in complex space, and it expects 32-bit complex floating point data as input and result. ? Exponential LPF: mpilpfexp(). Performs a low-pass filter operation using an exponential cutoff filter. This operation is perfomed in complex space, and it expects 32-bit complex floating point data as input and result.

4-10

Reference Pages

Virtualization Ratio Calculations
Compute the virtualization ratios for hierarchical virtual storage mapping (see the vr.3 man page). ? mpixvr(). Computes number of columns per PE. ? mpiyvr(). Computes number of rows per PE. ? mpi1dvr(). Computes number of elements per PE for a one-dimensional hierarchical array. ? mpi2dvr(). Computes number of elements per PE for a two-dimensional hierarchical array.

Data Mapping Conversions
? One-dimensional cut-and-stack in: mpi1dcsto2dh*(). Converts a one-dimensional cut-and-stack mapping to a two-dimensional hierarchical mapping. The library contains three versions of this routine: 8-bit, 16-bit, and 32-bit. ? One-dimensional cut-and-stack out: mpi2dhto1dcs*(). Converts a two-dimensional hierarchical mapping to a one-dimensional cut-and-stack mapping. The library contains three versions of this routine: 8-bit, 16-bit, and 32-bit. ? Two-dimensional cut-and-stack in: mpi2dcsto2dh*(). Converts a two-dimensional cut-and-stack mapping to a two-dimensional hierarchical mapping. The library contains three versions of this routine: 8-bit, 16-bit, and 32-bit. ? Two-dimensional cut-and-stack out: mpi2dhto2dcs*(). Converts a two-dimensional hierarchical mapping to a two-dimensional cut-and-stack mapping. The library contains three versions of this routine: 8-bit, 16-bit, and 32-bit. ? One-dimensional hierarchical in: mpi1dhto2dh*(). Converts a one-dimensional hierarchical mapping to a two-dimensional hierarchical mapping. The library contains three versions of this routine: 8-bit, 16-bit, and 32-bit. ? One-dimensional hierarchical out: mpi2dhto1dh*(). Converts a two-dimensional hierarchical mapping to a one-dimensional hierarchical mapping. The library contains three versions of this routine: 8-bit, 16-bit, and 32-bit.

I/O Operations
? Input one-dimensional: mpiread1d*(). Reads a one-dimensional hierarchical virtual array of pixels from a file into an image. The library contains three versions of this routine: 8-bit, 16-bit, and 32-bit.

Reference Pages

4-11

? Input two-dimensional: mpiread2d*(). Reads a two-dimensional hierarchical virtual array of pixels from a file into an image. The library contains three versions of this routine: 8-bit, 16-bit, and 32-bit. ? Output one-dimensional: mpiwrite1d*(). Writes a one-dimensional hierarchical virtual array of pixels to a file. The library contains three versions of this routine: 8-bit, 16-bit, and 32-bit. ? Output two-dimensional: mpiwrite2d*(). Writes a two-dimensional hierarchical virtual array of pixels to a file. The library contains three versions of this routine: 8-bit, 16-bit, and 32-bit. ? Plotting utilities: open_plot(), image_plot(), and close_plot(). These plotting routines use preslected interfaces to MPDDL routines for X-window graphics output of image data. See page 3-2 for more information.

Parameter Conventions
This section gives some information about parameters that is true for most, if not all, of the MPIPL routines.

Parameter Names and Values
Almost all of the MPIPL routines have parameters rows and cols, where rows is the number of rows of pixels in the image and cols is the number of columns of pixels in the image. Most of the MPIPL routines have parameters imgSrc and imgDst, which are pointers to areas in PMem. The size of the PMem region pointed to by imgSrc is mpi2dvr(rows,cols)*n], where n is 1 or 4 or 8 depending on the size of the data type being stored. See the vr.3 man page for more information on mpi2dvr(). In general, the MPIPL routines are more efficient if your image size is a power of two in both directions. Some MPIPL routines perform equally well independent of image size, but others, such as the FFT routines, require the image size to be a power of two in both directions. Many of the MPIPL routines also have parameters work1 and work2, which provide workspace PMem for the routine. The workspace areas should not overlap the imgSrc or imgDst areas. None of the MPIPL routines allocate memory. You create a workspace and pass the MPIPL routine a pointer to that space. If you get an error message that your program ran out of memory, check how much PMem your machine has and how much you have allocated with p_malloc().

4-12

Reference Pages

Parameter List Order
This section describes the parameter list order convention that is used throughout the MPIPL library. While the order is indicated here, specifics for each individual routine are given in the man pages. 1. Input images for the routine (if any) are first in the parameter list. 2. Next is the number of rows of pixels in the image. 3. Next is the number of columns of pixels in the image. 4. Other input arguments are after the number of columns (as documented by the man page for any specific routine). 5. Next is the output image. 6. Last is any workspace that may be needed.

Chapter 5 Pointwise Routine Generator

In addition to the routines described in Chapter 4, MPIPL also comes with a utility that you can use to generate your own efficient pointwise image processing routines. This utility is called mpipntwise. A pointwise routine is one for which the computation of each point of the destination image (or images) depends only on the corresponding points of the source images. Examples of pointwise routines include mpiadd8(), mpimul8(), and mpithresh8() (see chapter 4). Input to the mpipntwise utility is a text file that specifies the name of the routine you want generated, its parameters, and the MPL code to compute one point on each PE. Output from the mpipntwise utility is a text file that contains the MPL source for the specified routine. The mpipntwise utility generates the routine by taking your MPL code and wrapping around it the procedure declarations and necessary virtualization code to step through each of the pixels stored on a PE. It uses load/store scheduling to optimize memory performance.1 One use of mpipntwise is to optimize a series of pointwise operations. Instead of making a series of calls to MPIPL pointwise routines, you can use mpipntwise to generate a single routine with the same functionality. By using mpipntwise this way, you increase your performance because you avoid making a series of memory accesses to the same point in the image.

1Examining the output from mpipntwise may also give you ideas for maximizing the memory performance of your MPL code in general, whether or not you are using MPIPL.

Pointwise Routine Generator

5-1

5-2

Pointwise Routine Generator

The MPIPL contains many pointwise routines, such as add and multiply. You can generate these same routines or variations of these routines using mpipntwise. See the examples at the end of this chapter. Below is a list of MPIPL pointwise routines. mpiconv8cf() mpiconv8cfi() mpiconv8cfr() mpiconv8f() mpiconvcfi8() mpiconvcfr8() mpiconvf8() mpigenconst8() mpiadd8() mpiaddclip8() mpiand8() mpidiv8() mpimul8() mpimulclip8() mpior8() mpisconvcfi8() mpisconvcfr8() mpisconvf8() mpisub8() mpisubclip8() mpithresh8() mpixor8()

Generating Your Routine
To create your own MPIPL pointwise arithmetic routine, create a source file (described below) called fileName.pnt. Then at the ULTRIX command prompt enter:
mpipntwise fileName

Do not use the .pnt extension to fileName when you invoke mpipntwise. The mpipntwise command processes the file fileName.pnt to produce a file fileName.m that you can compile and link with the rest of your program. It also creates a temporary file called fileName.tmp; if the file fileName.tmp already exists, it will be overwritten. The fileName.m file produced always contains the following lines at the top:
#include <mpl.h> #include <mpipl.h>

Also at the top of the generated fileName.m file is the following header that allows you to compile the routine with either the mpl* or the ompl* drivers:

Pointwise Routine Generator

5-3

#ifdef __STDMPL__ /* ANSI C extern declaration */ #else /* K&R C extern declaration */ #endif #ifdef __STDMPL__ /* ANSI C function header */ #else /* K&R C function header */ #endif

You can cut out the extern declaration and paste it into routines that call the function that you generated using mpipntwise. If you are using the mpl* or ampl* drivers but you do not want to use the function prototypes, then you need to edit the code generated by mpipntwise to remove the function prototypes yourself.

Writing and Calling Your Routine
This section first describes the mpipntwise source file in general, then the call that goes in your main program, then each section of the source file in more detail, and finally shows examples.

Input Format
The form of the source file for the routine is as follows:
#prelude /* * arbitrary MPL lines such as #include or #define */ #procname procName /* the name of the routine #src sdType identl /* source variables #dst sdType identl /* destination variables #prm prmType identifier /* other parameters #condop bool /* operate outside the image area? #body /* * lines of MPL code that specify operations * to be performed on each point in the image */

*/ */ */ */ */

5-4

Pointwise Routine Generator

The #prelude, #procname, #src, #dst, #prm, #condop and #body sections can be in any order in the file. Only the #procname, #condop, and #body sections are mandatory. Further descriptions of each of the sections in the mpipntwise source file are given below. Some general restrictions on the input file are: ? Lines in the input file cannot be longer than 254 characters. ? The number of lines in the #body section cannot be more than 1,000. ? You can have no more than eight #src lines, eight #dst lines, and eight #prm lines. You can have no more than eight source variables, eight destination variables, and eight #prm variables. ? Variable names referenced in the #src, #dst, #prm, and #body sections cannot end in ‘‘_’’. ? Variables referenced in the #src, #dst, and #prm sections cannot be redeclared in the #body section. ? You cannot have duplicated #src variables, duplicated #dst variables, or duplicated #prm variables. ? Variables referenced in the #src section cannot be duplicated in the #prm section. Variables referenced in the #dst section cannot be duplicated in the #prm section. Variables referenced in the #src section can be duplicated in the #dst section only if the types are identical.

Calling Convention
When you call your routine, list all the sources first, then the number of rows in the image, then the number of columns in the image, then any #prm parameters, and then all the destinations (where ‘‘#prm parameters’’ are any parameters other than sources, destinations, rows, and columns). For example: procName ( src1, src2, rows, cols, prm1, prm2, dst1, dst2 ); See also the examples at the end of this chapter.

Prelude
The #prelude section is optional. It can contain any MPL text that you wish to precede the procedure definition. You may need to use it for #include or #define lines. Note that <mpl.h> and <mpipl.h> are automatically included when you run mpipntwise, so you do not need to specify them.

Pointwise Routine Generator

5-5

Procedure Name
This is the name you use when you call the procedure. Therefore, the #procname line is mandatory.

Sources, Destinations, and Other Parameters
The #src, #dst, and #prm lines are optional—you do not have to have any of them. The #src and #dst variables are always declared as register variables in the generated routine. You can declare a #prm variable to be a register variable in your mpipntwise input file by including the keyword ‘‘register’’ at the start of its type. The declarations of #prm variables precede the declarations of #src and #dst variables in the generated code, so any #prm register declarations you may have take precedence when registers are allocated. You can use the -ZR flag to the MPL compilers when you compile the fileName.m file generated by mpipntwise to check which variables were actually allocated in registers.

Sources and Destinations
The complete syntax of these lines is:
#src sdType identl #dst sdType identl

where: sdType is one of:
uint8 uint16 uint32 uint64 float double int8 int16 int32 int64

See Appendix A for definitions of these types. Since MPIPL routines require all source and destination images to be represented in a two-dimensional hierarchical mapping in the PE array, the keyword ‘‘plural’’ is automatically provided by mpipntwise in the source and destination declarations in the generated routine. Do not specify ‘‘plural’’ on #src and #dst lines in your mpipntwise input. See the examples below. identl is an identifier or an idlist. identifier is the name of a variable to be loaded from memory and operated on in the #body section of this routine definition. It may be any valid C identifier, subject to the restrictions given above (such as it cannot end in ‘‘_’’).

5-6

Pointwise Routine Generator

idlist is a list of identifiers and/or periods separated by spaces and enclosed by parentheses. Use the idlist form if your pixel has multiple components of the same type. Note that mpipntwise does not support pixels that have components of different types. A ‘‘.’’ means skip this field in the pixel structure: There will be no memory operations to read or write this field. An example of a pixel that has multiple components of the same type is a complex pixel with real and imaginary components that are both type float. If a pixel is defined to be an array of two floating point elements, then you can use the dot notation to tell mpipntwise to skip the real element and only operate on the imaginary element or skip the imaginary element and only operate on the real element. See the examples on pages 5-10 and 5-13. You can use the same variable names in both #src and #dst lines. If you do, it does not mean that the source is the same as the destination; it only means that they share a register variable in PReg. Whether the source and destination are the same depends on whether you pass them the same pointer. In the image add example on page 5-8, there is both a source and a destination named ‘‘a1’’. This simply allows the routine to use the more efficient a1+=a2 rather than something like a3=a1+a2. The destination shares PReg with one of the sources, but the input is read from the source pointer and the result is written to the destination pointer. Depending on what source and destination pointers you pass, this one routine can be used to add two different sources and store the result back in one of the sources or add two different sources and store the result into a separate destination.

Other Parameters
You need one #prm line for each parameter other than source images, destination images, number of rows, and number of columns. The complete syntax of this line is:
#prm prmType identifier

where: prmType is any sequence of identifiers, including, for example, long long, plural, or register. (You can use the -ZR flag to the MPL compilers to check for register usage.) Note that, for example, int * is not a valid prmType since * is not an identifier. To use int *, you would need to put a typedef line in the #prelude section, and then use that defined type for prmtype on the #prm line as in the following example:
#prelude typedef int * p_int; #prm p_int parm1

identifier is the name you are using for this parameter in the #body section of this routine definition. It may be any valid C identifier, subject to the restrictions given above (such as it cannot end in ‘‘_’’).

Pointwise Routine Generator

5-7

Conditional Operation Flag
The #condop line is mandatory. There is no default value for this flag. This flag specifies what to do with data that is outside the image. That is, if the image is not a multiple of the machine size (PE array size), should the code in the #body section be performed on array elements that are beyond the image boundaries? For example, if you have a 1K (32-by-32) PE array and your image is 32-by-28 pixels, should the code in the #body section be performed on the plural variable in the last four rows of the PE array? See also the example on page 5-13. The syntax of this line is:
#condop bool

where: bool is either ‘‘0’’ or ‘‘1’’. 0 1 The operations in this routine are not conditional. Execute this routine on all array elements, whether or not they are in the image. The operations in this routine are conditional. Execute this routine only on array elements that are in the image.

In general, the code runs faster if you specify ‘‘0’’. You may want to specify ‘‘1’’ to avoid the possibility of extraneous errors such as divide-by-zero errors outside the image area.

Body
The #body section is the last section in the source file. It consists of lines of MPL code that compute one pixel on each PE. The code is iterated once for each pixel that is stored on a PE; that is, it is iterated vr (virtualization ratio) times, where the virtualization ratio is the number of pixels per PE. Therefore, some kinds of calls may not make sense. See the examples below.

Examples
The first two examples shown here are mpipntwise versions of existing MPIPL routines. The next two are examples of routines you might write yourself. All of these examples show the source .pnt file, the call to the generated routine, and the code generated by mpipntwise. The second and third examples use multiple-component pixels.

5-8

Pointwise Routine Generator

mpiadd8
This example shows how mpiadd8() would be written as an mpipntwise routine. Recall that this routine adds two images to form a resultant image of unsigned 8-bit integers. The following lines are in the file myadd8.pnt. See page 5-6 regarding using the same variable names in both #src and #dst lines.
#procname add8 #src uint8 a1 #src uint8 a2 #dst uint8 a1 #condop 0 #body a1 += a2;

The call in your main program is written as:
add8(src1, src2, rows, cols, dst);

If you enter the following at the ULTRIX command prompt:
mpipntwise myadd8

then the following file myadd8.m is generated (note that the source and destination pointers are stored in registers):
#include <mpl.h> #include <mpipl.h> #ifdef __STDMPL__ extern void add8( register plural uint8 * src0_, register plural uint8 * src1_, unsigned rows_, unsigned cols_ , register plural uint8 * dst0_ ); #else extern void add8(); #endif void add8( #ifdef __STDMPL__

Pointwise Routine Generator

5-9

register plural uint8 * src0_, register plural uint8 * src1_, unsigned rows_, unsigned cols_ , register plural uint8 * dst0_ ) #else src0_, src1_, rows_, cols_ , dst0_ ) register plural uint8 * src0_; register plural uint8 * src1_; register plural uint8 * dst0_; unsigned rows_, cols_; #endif { if (!rows_ | !cols_) return; all { register unsigned cnt_ = MPI2DVR(rows_, cols_); register plural uint8 a1_a_, a1_b_; register plural uint8 a2_a_, a2_b_; a1_a_ = src0_[0]; a2_a_ = src1_[0]; src0_ += 1; src1_ += 1; while (--cnt_) { a1_b_ = src0_[0]; a2_b_ = src1_[0]; src0_ += 1; src1_ += 1;

5-10

Pointwise Routine Generator

a1_a_ += a2_a_; dst0_[0] = a1_a_; dst0_ += 1; if (--cnt_) { a1_a_ = src0_[0]; a2_a_ = src1_[0]; src0_ += 1; src1_ += 1; a1_b_ += a2_b_; dst0_[0] = a1_b_; dst0_ += 1; continue; } a1_b_ += a2_b_; dst0_[0] = a1_b_; return; } a1_a_ += a2_a_; dst0_[0] = a1_a_; return; } }

mpiconv8cfi
The following shows how mpiconv8cfi() would be written as an mpipntwise routine. Recall that this routine converts the current image from unsigned 8-bit integers to the imaginary part of a complex floating point representation. The real part of the complex pixel is left unchanged. The following lines are in the mpipntwise input file. This example uses a source with a multiple-component pixel, and it illustrates the dot notation discussed on page 5-6.

Pointwise Routine Generator

5-11

#procname conv8cfi #src float (. s) #dst uint8 d #condop 0 #body if (s > 255.0) s = 255.0; if (s < 0.0) s = 0.0; d = s + 0.5;

The call in your main program is written as:
conv8cfi(src, rows, cols, dst);

If you enter the following at the ULTRIX command prompt:
mpipntwise myconv8cfi

then the following file myconv8cfi.m is generated:
#include <mpl.h> #include <mpipl.h> #ifdef __STDMPL__ extern void conv8cfi( register plural float * src0_, unsigned rows_, unsigned cols_ , register plural uint8 * dst0_ ); #else extern void conv8cfi(); #endif void conv8cfi( #ifdef __STDMPL__ register plural float * src0_, unsigned rows_, unsigned cols_ , register plural uint8 * dst0_ ) #else

5-12

Pointwise Routine Generator

src0_, rows_, cols_ , dst0_ ) register plural float * src0_; register plural uint8 * dst0_; unsigned rows_, cols_; #endif { if (!rows_ | !cols_) return; all { register unsigned cnt_ = MPI2DVR(rows_, cols_); register plural float s_a_, s_b_; register plural uint8 d_a_, d_b_; s_a_ = src0_[1]; src0_ += 2; while (--cnt_) { s_b_ = src0_[1]; src0_ += 2; if (s_a_ > 255.0) s_a_ = 255.0; if (s_a_ < 0.0) s_a_ = 0.0; d_a_ = s_a_ + 0.5; dst0_[0] = d_a_; dst0_ += 1; if (--cnt_) { s_a_ = src0_[1]; src0_ += 2; if (s_b_ > 255.0) s_b_ = 255.0; if (s_b_ < 0.0) s_b_ = 0.0; d_b_ = s_b_ + 0.5;

Pointwise Routine Generator

5-13

dst0_[0] = d_b_; dst0_ += 1; continue; } if (s_b_ > 255.0) s_b_ = 255.0; if (s_b_ < 0.0) s_b_ = 0.0; d_b_ = s_b_ + 0.5; dst0_[0] = d_b_; return; } if (s_a_ > 255.0) s_a_ = 255.0; if (s_a_ < 0.0) s_a_ = 0.0; d_a_ = s_a_ + 0.5; dst0_[0] = d_a_; return; } }

mpimulcf
This routine shown in this example multiplies complex pixel values. The following lines are in the mpipntwise input file. Similar to the example shown on page 5-10, this example uses the idlist form of source and destination declarations discussed on page 5-6. In contrast to the example shown on page 5-10, this example uses both the real and imaginary components of the complex pixel. This example also illustrates turning conditional operation on.
#procname mulcf #src float (ar ai) #src float (br bi) #dst float (dr di) #condop 1 #body dr = ar * br - ai * bi; di = ai * br + ar * bi;

The call in your main program is written as:
mulcf(src1, src2, rows, cols, dst);

5-14

Pointwise Routine Generator

If you enter the following at the ULTRIX command prompt:
mpipntwise mulcf

then the following file mulcf.m is generated:
#include <mpl.h> #include <mpipl.h> #ifdef __STDMPL__ extern void mulcf( register plural float * src0_, register plural float * src1_, unsigned rows_, unsigned cols_ , register plural float * dst0_ ); #else extern void mulcf(); #endif void mulcf( #ifdef __STDMPL__ register plural float * src0_, register plural float * src1_, unsigned rows_, unsigned cols_ , register plural float * dst0_ ) #else src0_, src1_, rows_, cols_ , dst0_ ) register plural float * src0_; register plural float * src1_;

Pointwise Routine Generator

5-15

register plural float * dst0_; unsigned rows_, cols_; #endif { if (!rows_ | !cols_) return; if (rows_ & (nyproc - 1) | cols_ & (nxproc - 1)) all { unsigned xvr_ = MPIXVR(cols_), yvr_ = MPIYVR(rows_); register unsigned cnt_ = yvr_ * xvr_; plural unsigned xstart_ = ixproc * xvr_, ystart_ = iyproc * yvr_; register plural unsigned short pxvr0_ = (xstart_ >= cols_ ? 0 : xstart_ + xvr_ >= cols_ ? cols_ - xstart_ : xvr_) + 1, pyvr_ = (ystart_ >= rows_ ? 0 : ystart_ + yvr_ >= rows_ ? rows_ - ystart_ : yvr_) + 1; register plural unsigned short pxvr_; register plural float sdat0_, ar; register plural float sdat1_, ai; register plural float sdat2_, br; register plural float sdat3_, bi; register plural float ddat0_, dr; register plural float ddat1_, di; sdat0_ = src0_[0]; sdat1_ = src0_[1]; sdat2_ = src1_[0]; sdat3_ = src1_[1]; src0_ += 2; src1_ += 2; while (--pyvr_) for (pxvr_ = pxvr0_; --pxvr_; ) { ar = sdat0_;

5-16

Pointwise Routine Generator

ai = sdat1_; br = sdat2_; bi = sdat3_; if (--cnt_) all { sdat0_ = src0_[0]; sdat1_ = src0_[1]; sdat2_ = src1_[0]; sdat3_ = src1_[1]; src0_ += 2; src1_ += 2; } dr = ar * br - ai * bi; di = ai * br + ar * bi; ddat0_ = dr; dst0_[0] = ddat0_; ddat1_ = di; dst0_[1] = ddat1_; dst0_ += 2; } } else all { register unsigned cnt_ = MPI2DVR(rows_, cols_); register plural float ar_a_, ar_b_; register plural float ai_a_, ai_b_; register plural float br_a_, br_b_; register plural float bi_a_, bi_b_; register plural float dr_a_, dr_b_; register plural float di_a_, di_b_; ar_a_ = src0_[0]; ai_a_ = src0_[1]; br_a_ = src1_[0];

Pointwise Routine Generator

5-17

bi_a_ = src1_[1]; src0_ += 2; src1_ += 2; while (--cnt_) { ar_b_ = src0_[0]; ai_b_ = src0_[1]; br_b_ = src1_[0]; bi_b_ = src1_[1]; src0_ += 2; src1_ += 2; dr_a_ = ar_a_ * br_a_ - ai_a_ * bi_a_; di_a_ = ai_a_ * br_a_ + ar_a_ * bi_a_; dst0_[0] = dr_a_; dst0_[1] = di_a_; dst0_ += 2; if (--cnt_) { ar_a_ = src0_[0]; ai_a_ = src0_[1]; br_a_ = src1_[0]; bi_a_ = src1_[1]; src0_ += 2; src1_ += 2; dr_b_ = ar_b_ * br_b_ - ai_b_ * bi_b_; di_b_ = ai_b_ * br_b_ + ar_b_ * bi_b_; dst0_[0] = dr_b_; dst0_[1] = di_b_; dst0_ += 2; continue; } dr_b_ = ar_b_ * br_b_ - ai_b_ * bi_b_; di_b_ = ai_b_ * br_b_ + ar_b_ * bi_b_;

5-18

Pointwise Routine Generator

dst0_[0] = dr_b_; dst0_[1] = di_b_; return; } dr_a_ = ar_a_ * br_a_ - ai_a_ * bi_a_; di_a_ = ai_a_ * br_a_ + ar_a_ * bi_a_; dst0_[0] = dr_a_; dst0_[1] = di_a_; return; } }

Cubic Polynomial
This routine performs the following function:
d = a0 + s * (a1 + s * (a2 + s * a3))

In the following mpipntwise input file, a0, a1, a2, and a3 are coefficients of the cubic polynomial.
#procname cubic #src int16 s #dst int16 d #prm register int16 a0 #prm register int16 a1 #prm int16 a2 #prm int16 a3 #condop 0 #body d = s; d *= a3; d += a2; d *= s; d += a1; d *= s; d += a0;

The call in your main program is written as:
cubic(src, rows, cols, A0, A1, A2, A3, dst);

If you enter the following at the ULTRIX command prompt:
mpipntwise cubic

Pointwise Routine Generator

5-19

then the following file cubic.m is generated. Note how variables are allocated to registers.
#include <mpl.h> #include <mpipl.h> #ifdef __STDMPL__ extern void cubic( register plural int16 * src0_, unsigned rows_, unsigned cols_ , register int16 a0 , register int16 a1 , int16 a2 , int16 a3 , register plural int16 * dst0_ ); #else extern void cubic(); #endif void cubic( #ifdef __STDMPL__ register plural int16 * src0_, unsigned rows_, unsigned cols_ , register int16 a0 , register int16 a1 , int16 a2 , int16 a3 , register plural int16 * dst0_ ) #else src0_, rows_, cols_

5-20

Pointwise Routine Generator

, a0, a1, a2, a3 , dst0_ ) register int16 a0; register int16 a1; int16 a2; int16 a3; register plural int16 * src0_; register plural int16 * dst0_; unsigned rows_, cols_; #endif { if (!rows_ | !cols_) return; all { register unsigned cnt_ = MPI2DVR(rows_, cols_); register plural int16 s_a_, s_b_; register plural int16 d_a_, d_b_; s_a_ = src0_[0]; src0_ += 1; while (--cnt_) { s_b_ = src0_[0]; src0_ += 1; d_a_ d_a_ d_a_ d_a_ d_a_ d_a_ d_a_ = s_a_; *= a3; += a2; *= s_a_; += a1; *= s_a_; += a0;

dst0_[0] = d_a_; dst0_ += 1; if (--cnt_) { s_a_ = src0_[0];

Pointwise Routine Generator

5-21

src0_ += 1; d_b_ d_b_ d_b_ d_b_ d_b_ d_b_ d_b_ = s_b_; *= a3; += a2; *= s_b_; += a1; *= s_b_; += a0; dst0_[0] = d_b_; dst0_ += 1; continue; } d_b_ d_b_ d_b_ d_b_ d_b_ d_b_ d_b_ = s_b_; *= a3; += a2; *= s_b_; += a1; *= s_b_; += a0;

dst0_[0] = d_b_; return; } d_a_ d_a_ d_a_ d_a_ d_a_ d_a_ d_a_ = s_a_; *= a3; += a2; *= s_a_; += a1; *= s_a_; += a0;

dst0_[0] = d_a_; return; } }

5-22

Pointwise Routine Generator

Appendix A MPIPL Header File

Below is a copy of the top of the MPIPL header file, $MP_PATH/include/mpl/mpipl.h. The declarations for each routine in the library are not shown, but the predefined variables and type definitions are shown.
#ifndef __MPIPL_HEADER__ #define __MPIPL_HEADER__ #define #define #define #define MPIXVR(n) (((n) + nxproc MPIYVR(n) (((n) + nyproc MPI1DVR(n) (((n) + nproc MPI2DVR(ny,nx) ((((ny) + (((nx) + - 1) >> lnxproc) - 1) >> lnyproc) - 1) >> lnproc) nyproc - 1) >> lnyproc) * \ nxproc - 1) >> lnxproc))

/* codes for sconvolve routines */ #define IS_KS 0 #define IS_KU 1 #define IU_KS 2 #define IU_KU 3 /* filter codes for orthogonal gradient edge detection routines */ #define SOBEL 0 #define PIXDIFF 1 #define ROBERTS 2 /* operation codes for orthogonal gradient edge detection routines */ #define GRAD_MAG 0 #define GRAD_TMAG 1 #define GRAD_ANGLE 2 #define GRAD_QANGLE 3 #define GRAD_MAG_ANGLE 4 #define GRAD_TMAG_ANGLE 5

MPIPL Header File

A-1

A-2

MPIPL Header File

#define GRAD_MAG_QANGLE 6 #define GRAD_TMAG_QANGLE 7 typedef char typedef short typedef int #ifdef _MPL typedef long long #endif typedef unsigned typedef unsigned typedef unsigned #ifdef _MPL typedef unsigned #endif char short int long long int8; int16; int32; int64; uint8; uint16; uint32; uint64;

Index

Abingdon cross 3-2 apropos iii close_plot() 4-11, 3-1 cols 3-3, 3-7, 4-11 Compiler drivers 5-2, 5-3 Compiling 3-1, 4-1 Convolution 3-4 Convolutions 1-3 Cross image 3-2 Data mapping 1-1, 1-2, 2-2, 4-2 Data mapping conversions 2-2 Edge detection 4-6 Examples iii extern 5-3 FFT filterings 3-7 File output 3-4, 3-8 Filtering 3-8 font conventions iv Frequency-based filtering 1-2 Function prototypes 5-3 Gaussian noise 3-2 Gradient edge detection 4-6 Graphic output 1-2, 3-3, 3-7 Help iii Hierarchical virtualization 2-1, 2-3, 4-2

I/O graphic output 1-2 Image size 2-3, 4-11 image_plot() 4-11, 3-1 Imaginary part 3-8 imgDst 4-11 imgSrc 4-11 Include file 3-1 Input file 3-4, 3-8 Job swapping 3-2 Linking MPDDL 3-2, 4-1 MPIPL 3-1, 4-1 make 3-2, 3-4, 3-7, 3-8 Makefiles 3-2 man iii MasPar Architecture Specification iii MasPar Commands manual ii, 3-2 MasPar Data Display Library See MPDDL MasPar Fortran See MPF MasPar Fortran Reference manual ii MasPar Fortran User Guide ii Maspar Programming Language See MPL MasPar System Overview manual ii Memory management 4-11

Index

1

2

Index

MPDDL 1-2, 3-1, 3-2, 4-1 MPDDL Reference manual ii, 1-2, 3-2 MPDDL_DEVICE_X_APPROX 3-2 MPF 1-1, 4-1 mpi1dcsto2dh16() 4-10 mpi1dcsto2dh32() 4-10 mpi1dcsto2dh8() 2-2, 4-10 mpi1dhto2dh16() 4-10 mpi1dhto2dh32() 4-10 mpi1dhto2dh8() 2-2, 4-10 mpi1dvr() 4-10 mpi2dcsto2dh16() 4-10 mpi2dcsto2dh32() 4-10 mpi2dcsto2dh8() 2-2, 4-10 mpi2dfft() 4-9 mpi2dhto1dcs16() 4-10 mpi2dhto1dcs32() 4-10 mpi2dhto1dcs8() 4-10 mpi2dhto1dh16() 4-10 mpi2dhto1dh32() 4-10 mpi2dhto1dh8() 4-10 mpi2dhto2dcs16() 4-10 mpi2dhto2dcs32() 4-10 mpi2dhto2dcs8() 4-10 mpi2difft() 4-9 mpi2dvr() 4-11, 4-10 mpiadd8() 4-2 mpiaddclip8() 4-2 mpiaddf() 4-2 mpiand8() 4-3 mpibdilate8() 4-6 mpiberode8() 4-6 mpibparskel8() 4-6 mpibskel8() 4-7 mpiconv8cf() 4-3 mpiconv8cfi() 4-3 mpiconv8cfr() 4-4 mpiconv8f() 4-4 mpiconvcfi8() 4-3 mpiconvcfr8() 4-3 mpiconvf8() 4-3 mpiconvolve8() 4-4 mpiconvolvebr8() 4-4 mpiconvolvebrf() 4-4 mpiconvolvef() 4-4 mpidilate16() 4-6 mpidilate16s() 4-6 mpidilate8() 4-6 mpidiv8() 4-2 mpidivf() 4-3 mpierode16() 4-6 mpierode16s() 4-6

mpierode8() 4-6 mpiexpandrep16() 4-7 mpiexpandrep32() 4-7 mpiexpandrep8() 4-7 mpiexpandsm16() 4-7 mpiexpandsm16s() 4-7 mpiexpandsm8() 4-7 mpiextend16() 4-7 mpiextend32() 4-7 mpiextend8() 4-7 mpiextract16() 4-7 mpiextract32() 4-7 mpiextract8() 4-7 mpiflipew16() 4-8 mpiflipew32() 4-8 mpiflipew8() 4-8 mpiflipns16() 4-8 mpiflipns32() 4-8 mpiflipns8() 4-8 mpigenconst8() 4-8 mpigencross16() 4-8 mpigencross8() 4-8 mpigengauss16() 4-8 mpigengauss16s() 4-8 mpigengauss8() 4-8 mpigengrid16() 4-8 mpigengrid8() 4-8 mpigenrand16() 4-8 mpigenrand16s() 4-8 mpigenrand8() 4-8 mpigensaw16() 4-8 mpigensaw8() 4-8 mpigensine16() 4-8 mpigensine8() 4-8 mpihconvolve8() 4-4 mpihconvolvebr8() 4-4 mpihconvolvebrf() 4-5 mpihconvolvef() 4-5 mpihist8() 4-9 mpihisteq8() 4-9 mpihiststr8() 4-9 mpihpfbw() 4-9 mpihpfexp() 4-9 mpiinsert16() 4-7 mpiinsert32() 4-7 mpiinsert8() 4-7 mpilpfbw() 4-9 mpilpfexp() 4-9 mpimul8() 4-2 mpimulclip8() 4-2 mpimulf() 4-2 mpior8() 4-3 mpiorthograd16() 1-3, 4-6

Index

3

mpiorthograd16s() 1-3, 4-6 mpiorthograd8() 1-3, 4-6 MPIPL Reference manual ii mpipl.h 3-1, 4-1, A-1 mpipl.h 5-2 mpipntwise 1-3, 1-4, 5-1 mpiread1d16() 4-10 mpiread1d32() 4-10 mpiread1d8() 2-1, 4-10 mpiread2d16() 4-11 mpiread2d32() 4-11 mpiread2d8() 2-1, 3-4, 3-9, 4-11 mpirotate90d16() 4-8 mpirotate90d32() 4-8 mpirotate90d8() 4-8 mpisconvcfi8() 4-3 mpisconvcfr8() 4-3 mpisconvf8() 4-3 mpisconvolve16() 4-4 mpisconvolve8() 4-4 mpishconvolve16() 4-5 mpishconvolve8() 4-5 mpishrinkavg16() 4-7 mpishrinkavg16s() 4-7 mpishrinkavg8() 4-7 mpishrinksamp16() 4-7 mpishrinksamp32() 4-7 mpishrinksamp8() 4-7 mpisub8() 4-2 mpisubclip8() 4-2 mpisubf() 4-2 mpisvconvolve16() 4-5 mpisvconvolve8() 4-5 mpitabgsadj8() 4-9 mpithresh8() 4-9 mpitransl16() 4-8 mpitransl32() 4-8 mpitransl8() 4-8 mpitranspose16() 4-8 mpitranspose32() 4-8 mpitranspose8() 4-8 mpitrunc16() 4-7 mpitrunc32() 4-7 mpitrunc8() 4-7 mpivconvolve8() 4-5 mpivconvolvebr8() 4-5 mpivconvolvebrf() 4-5 mpivconvolvef() 4-6 mpiwrite1d16() 4-11 mpiwrite1d32() 4-11 mpiwrite1d8() 2-1, 4-11 mpiwrite2d16() 4-11 mpiwrite2d32() 4-11

mpiwrite2d8() 2-1, 3-4, 3-9, 4-11 mpixor8() 4-3 MPIXVR 3-4, 3-9 mpixvr() 4-10 MPIYVR 3-4, 3-9 mpiyvr() 4-10 MPL ii, 1-1, 4-1 MPL Reference manual ii, 3-4, 3-9 MPL User Guide ii mpld ii mpl.h 5-2 MPML Reference manual ii MPPE Quick Reference ii MPPE User Guide ii mpq 3-2 MP_PATH ii, 3-2, A-1 notation conventions iv nproc 2-3 nxproc 2-3 nyproc 2-3 open_plot() 4-11, 3-1 Output file 3-4, 3-8 graphic 3-3, 3-7 Parameter order 4-12 Parameters 4-11 PE array 1-1, 1-2, 2-1 PE communication 2-2 Performance 1-2, 1-3 Performance issues image size 2-3, 4-11 Plotting routines 1-2, 3-1, 4-1, 4-11 PMem 4-11 p_malloc() 4-11 Real part 3-8 Reserved names ii Roberts filter 4-6 rows 3-3, 3-7, 4-11 Size of image 2-3, 4-11 Skeletonization 3-4 Sobel filter 1-3, 4-6 Syntax notation conventions iv testName 3-7 ULTRIX C 1-1, 4-1

4

Index

VAX Fortran 1-1, 4-1 Virtualization 1-1, 1-2, 2-1, 4-2 2D hierarchical 2-3 vr.3 4-11 work1 4-11 work2 4-11 Workspace 3-4, 3-9, 4-11 xmpddl window 3-2, 3-3, 3-7

Table of Contents

Preface
How to Use This Manual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . i Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ii References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ii Help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iii

Notation Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iv

Chapter 1.

Introduction

1-1

Calling the Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-1 Virtualizing Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-2 Displaying Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-2 Kinds of Image Manipulations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Frequency-Based Filtering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Convolutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Example: Clarifying an Image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Arithmetic Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Example: Arithmetic Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-2 1-2 1-3 1-3 1-3 1-3

Chapter 2.

Data Mapping

2-1

Data Mapping Conversions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-2 Two-Dimensional Hierarchical Mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-2

Table of Contents

v

vi

Table of Contents

Chapter 3.

Examples

3-1

Include File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-1 Compiling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-1 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-2 The Abingdon Cross . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-2 FFT Filterings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-7

Chapter 4.

Reference Pages

4-1

Overview of MPIPL Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-2 Arithmetic Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-2 Logical Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-3 Data Type Conversions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-3 Convolutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-4 Edge Detection Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-6 Thickening and Thinning Operations . . . . . . . . . . . . . . . . . . . . . . . 4-6 Expanding and Shrinking Operations . . . . . . . . . . . . . . . . . . . . . . 4-7 Extending and Truncating Operations . . . . . . . . . . . . . . . . . . . . . . 4-7 Extracting and Inserting Operations . . . . . . . . . . . . . . . . . . . . . . . 4-7 Transpositions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-8 Image Generation Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-8 Color Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-9 Fourier Transforms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-9 Filtering Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-9 Virtualization Ratio Calculations . . . . . . . . . . . . . . . . . . . . . . . . . 4-10 Data Mapping Conversions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-10 I/O Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-10 Parameter Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-11 Parameter Names and Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-11 Parameter List Order . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-12

Chapter 5.

Pointwise Routine Generator

5-1
5-3 5-3 5-4 5-4 5-5 5-5 5-5 5-6 5-7 5-7

Generating Your Routine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-2 Writing and Calling Your Routine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Input Format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Calling Convention . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Prelude . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Procedure Name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sources, Destinations, and Other Parameters . . . . . . . . . . . . . . . . . . . Sources and Destinations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Other Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Conditional Operation Flag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Body . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-7 mpiadd8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-8 mpiconv8cfi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-10 mpimulcf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-13

Table of Contents

vii

Cubic Polynomial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-18

Appendix A. Index

MPIPL Header File

A-1

viii

Table of Contents

List of Figures

Figure 2-1

Two-Dimensional Hierarchical Data Mapping . . . . . . . . . . . . . . . . . . . . . . . . . . 2-3

List of Figures

ix

x

List of Figures


赞助商链接

更多相关文章:
更多相关标签:

All rights reserved Powered by 甜梦文库 9512.net

copyright ©right 2010-2021。
甜梦文库内容来自网络,如有侵犯请联系客服。zhit325@126.com|网站地图