This repository has been archived by the owner on Jan 19, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
plio.txt
1457 lines (1102 loc) · 66.5 KB
/
plio.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
PLIO (Feb88) Pixel List Package Design PLIO (Feb88)
THE IRAF PIXEL LIST PACKAGE
and
IMIO EXTENSIONS TO SUPPORT IMAGE MASKS
Doug Tody
February, 1988
(Revised June 1988)
1. INTRODUCTION
The pixel list package is a general package for flagging individual
pixels or regions of an image, to mark some subset of the pixels in an
image. This may be done to flag bad pixels, or to identify those
regions of an image to be processed by some applications program. When
the pixel list package is used to flag the bad pixels in an image we
call this a BAD PIXEL MASK, or BPM. When used to identify the regions
of an image to be processed (or ignored), we call the list a REGION
MASK.
A pixel list may be viewed conceptually as either a list or an image;
the list is merely the compressed form of a virtual MASK IMAGE.
Storing a mask image as a list has two major advantages.
[1] Storage efficiency. Simple masks may be stored very compactly,
e.g., as small arrays stored directly in an image header, or in
a separate mask file or database.
[2] Runtime efficiency. Storing a mask in list form has the
advantage that one can determine very quickly whether or not a
given region of the image (e.g., an image line) contains any
pixels in the mask. The alternative, given a fully populated
mask image (or flagging the pixels directly in the data image),
requires that one examine every pixel in the mask image, which
is very inefficient for simple masks.
The pixel list technique for implementing image masks is the most
efficient choice only for simple or moderately complex masks. As a
mask image increases in complexity there eventually comes a point where
it would be simpler and more efficient to use a conventional raster
image to store the mask. For example, if one wishes to associate a
flag value (such as a weight) with every pixel in an image, and the
flag values vary rapidly in value across the image, a separate image
should probably be used (except that other forms of data compression
may be possible; the IRAF NOISE FUNCTION PACKAGE addresses one aspect
of this problem).
The pixel list related software is subdivided into two parts, the pixel
list package itself, and the extensions to IMIO to make use of the
pixel list package. The pixel list package in itself is independent of
IMIO and may be used separately.
-1-
PLIO (Feb88) Pixel List Package Design PLIO (Feb88)
2. IMIO SUPPORT FOR PIXEL LISTS
Most image applications tend to fall into two classes, the simple
pointwise transformation operators, and the more cpu intensive image
analysis operations. The simple operators usually operate upon the
whole image (no mask required) and may ignore the presence of bad
pixels in the image, provided reasonable artificial values have been
provided for the bad pixels so that arithmetic problems do not occur,
and provided we keep track of the locations of the bad pixels (by
propagating the bad pixel lists), so that the bad pixel information is
available to subsequent image analysis programs.
The image analysis operators, on the other hand, must know the
locations of the bad pixels in order to exclude them from the fit. The
analysis is also often performed only upon specified regions of the
image, as indicated by some sort of image mask. Most image analysis
algorithms are fairly cpu intensive, hence as long as we can access the
bad pixel list and region mask reasonably efficiently, we would prefer
a simple interface, e.g., for every buffer of input image data read, an
associated buffer the same size and dimensionality as the input image
data buffer, containing the bad pixel or region mask flag values.
In general, if pixel lists are to be used with images, either IMIO must
provide direct support for pixel lists or the pixel list package must
duplicate much of the functionality of IMIO. This is because the pixel
list must be defined in terms of the physical image, whereas an
applications program accessing an image via IMIO may be operating upon
some user specified section of the image. To support applications
transparent sectioning, boundary extension, multiple input buffers, and
so on, support for pixel lists must be integrated into IMIO.
2.1 MASK IMAGES
These considerations lead us to make it possible for a pixel list
to appear to an application as a special type of image called a MASK
IMAGE, even though the mask may be stored as a pixel list internally,
and accessed or queried directly as a list if desired. If whenever we
read a block of data from the data image, we read an equivalent block
of data from the mask image, it is evident that whatever we come up
with for reading from the mask image is going to have to look an awful
lot like IMIO. Given the complexities of image section
transformations, automatic buffer allocation strategies, and so on, the
simplest solution is to just go ahead and use IMIO to access the virtual
mask image. This leads us to the interface shown in the figure below.
These routines represent an extension to IMIO to support pixel lists.
The conventional IMIO routines, used to access the mask "pixels", are
not shown.
The mask image may be opened by name with IM_PMMAP, or an already opened
pixel mask, perhaps the result of some computation done by the
-2-
PLIO (Feb88) Pixel List Package Design PLIO (Feb88)
applications program, may be opened with IM_PMMAPO. Alternatively, if
the mask is stored (or will be stored in the case of a new mask) in a
pixel list file (".pl" extension), the mask may be opened with a
conventional IMMAP call. This last option is especially powerful,
since it allows all image tasks to access masks as if they were
conventional images, e.g., one can DISPLAY or IMCOPY a stored mask.
im = im_pmmap (maskname, mode, ref_im|NULL)
im = im_pmmapo (pm, ref_im)
imseti (im, IM_RLIO, YES|NO)
imseti (im, IM_PMDES, pm)
pm = imstati (im, IM_PMDES)
bool = im_pmlne[123] (im[, lineno[, bandno]])
bool = im_pmsne[123] (im, x1, x2[, y1, y2[, z1, z2]])
bool = im_pmlnev (im, v)
bool = im_pmsnev (im, vs, ve, ndim)
The MODE argument to IM_PMMAP specifies both the access mode for the
mask, and any standard transformations to be performed upon the mask
before i/o takes place (if an existing mask is to be read). NEW_FILE
mode is used to create a new mask; READ_ONLY to read an existing mask,
and READ_WRITE to modify an existing mask. The mode-transformation
flags currently supported are INVERT_MASK, which performs a PIX_NOT
operation on the input mask, and BOOLEAN_MASK, which converts an
integer input mask to boolean. Any more complex mask transformations
or combinations must be performed explicitly by the calling program via
calls to the PMIO or PLIO routines, mapping the resultant mask onto an
image descriptor with IM_PMMAPO.
If a reference image REF_IM is specified at open time, then the mask
image will inherit any image section, boundary extension, etc. in
effect for the reference image. Inheritance occurs when the first i/o
to the mask image takes place. The reserved names "BPM" and "EMPTY",
respectively (must be upper case), denote the bad pixel mask for the
reference image, or an empty mask the size of the reference image. If
the reference image does not have a bad pixel mask, BPM and EMPTY are
equivalent. Note that separate image descriptors are used for the data
(reference) image and any mask images. Multiple mask images may be
associated with the same reference image.
Normal IMIO calls, e.g., IMGS2I, are used to access the mask "pixels".
Since it is common for a mask to be empty over large regions of an
image, a set of boolean functions are provided for testing whether
regions of the mask are nonempty, allowing a program to avoid the
expense of image mask i/o and subseqent testing of the mask pixel
values if not needed. The boolean functions IM_PMLNE (line not empty)
and IM_PMSNE (section not empty) and their more general variants
IM_PMLNEV and IM_PMSNEV test whether the specified region of the mask
image contains any nonzero mask pixels. The calling sequences of these
routines are patterned after the corresponding IMIO pixel i/o routines,
-3-
PLIO (Feb88) Pixel List Package Design PLIO (Feb88)
e.g., IM_PMLNE2 is intended for use with the IMGL2 routines, and
IM_PMLNEV is intended for use with the IMGNL routines.
By default, mask image i/o operates on data buffers containing arrays of
pixels, as for a conventional data image. When i/o takes place, the
interface automatically converts between pixel format and the
compressed line list format in which the mask is stored internally. An
alternative format for the mask data is RANGE LIST format, enabled by
setting the IM_RLIO parameter to YES in an IMSETI call. Range list i/o
works identically to pixel i/o, except that the "pixel arrays" returned
by IMIO (or input to IMIO) are range list structures, as defined in
<PLSET.H> and discussed in section 3.3.4.
Range list i/o at the IMIO level is fully general, i.e., the section
transformation, if any, is applied transparently to the calling program,
and the full range of IMIO i/o routines may be used. If the data
buffer is a multidimensional subraster, each line of the subraster will
be a separate range list, and the physical length in pixels of each line
of the subraster will be as for a pixel subraster. On a read, if the
length of the encoded range list exceeds the subraster line length in
pixels, and i/o error will occur. Such an i/o error cannot occur when
i/o is restricted to lines or line segments (1D buffers), since IMIO
will automatically allocate a data buffer large enough to hold the
worst case (longest) range list. Range list overflow errors are
unlikely even for subrasters, however, since the range list format is
normally much more compact than the equivalent pixel array (except for
very small subrasters or very complex masks).
2.2 MASKED IMAGE I/O (MIO)
The mask image i/o routines discussed in the previous section
provide a fully generalized means for directly accessing a mask as an
separate entity, independent of the associated reference data image.
Two separate image descriptors are required, and two parallel but
separate sets of calls to the IMIO routines. In many applications,
however, a mask is used only to specify those regions of the data image
to be analyzed or processed. We want to access those regions of the
image visible through the mask, but are not otherwise interested in the
mask itself. The MASKED IMAGE I/O (MIO) interface is designed for such
applications.
The MIO interface is summarized in the figure below. A named mask may
be opened on a previously opened image with the MIO_OPEN procedure. As
for IM_PMOPEN, the reserved names "BPM" and "EMPTY", respectively,
denote the bad pixel mask for the image, or an empty mask the size of
the image. If the image does not have a bad pixel mask, an empty mask
will be opened.
The FLAGS argument, if nonzero, specifies an operation be performed
upon the input mask to generate the mask to be used to access the data
-4-
PLIO (Feb88) Pixel List Package Design PLIO (Feb88)
image. The currently supported flags are INVERT_MASK and
BOOLEAN_MASK. For example, when the mask is a bad pixel mask,
INVERT_MASK would cause MIO to access only that portion of the image
which is NOT covered by the bad pixel mask, i.e., the "good" region of
the image. BOOLEAN_MASK is used to convert an integer mask into a
boolean mask. Note that in the case of inversion of an integer mask,
the PIX_NOT operation merely complements the mask pixel values, hence
will not affect the REGION covered by the mask. To invert an integer
mask in the region sense, use INVERT_MASK+BOOLEAN_MASK.
mp = mio_open (maskname, flags, im)
mp = mio_openo (pm, im)
value = mio_stati (mp, param)
mio_seti (mp, param, value)
mio_setrange (mp, vs, ve, ndim)
n|EOF = mio_[gp]lseg[silrdx] (mp, ptr, mval, v, npix)
mio_close (mp)
More general mask transformations must be carried out by the user using
the PMIO package to directly compute the desired mask, the mapping the
mask onto an image descriptor with MIO_OPENO. For example, given as
input a bad pixel mask and a region mask, one could compute the mask
specifying all pixels in the region mask but not in the bad pixel
mask. Any general mask may be computed in this way.
An MIO application will not normally need to access the mask directly,
but if such access is required the mask descriptor may be obtained with
a call to MIO_STATI to fetch the value of the parameter P_PMDES.
Similarly, the image descriptor may be queried as parameter P_IMDES,
and either parameter may be set with the corresponding call to MIO_SETI.
Successive calls to a get or put line segment procedure, e.g.,
MIO_GLSEGR (get line segment real), return line segments from the data
image until all the data present in the area outlined by the mask has
been accessed, at which time EOF is returned as the function value.
Each line segment is returned along with a vector V specifying the line
of the image from which the segment is taken and the index of the first
pixel of the current line segment within the line, a count NPIX of the
number of pixels in the line segment, and the mask value MVAL for the
current line segment (e.g., 1 for a boolean mask). Each line segment
corresponds to a region of constant nonzero value (MVAL) in the mask.
Line segments are returned sequentially in storage order.
By default, the entire region of the image visible through the mask
will be accessed. To access only a portion of the image, the
IMIO_SETRANGE procedure may be called before performing any i/o to
specify the starting and ending vector coordinates VS and VE of the
region to be accessed. Multiple calls may be made on the same MIO
descriptor to access multiple regions of the data image, or to "rewind"
a given region of the image.
-5-
PLIO (Feb88) Pixel List Package Design PLIO (Feb88)
2.3 MASK IMAGE STORAGE
As we shall see in the discussion of the pixel list package, the
pixel list package is designed to permit a list to be stored anywhere,
e.g., in a binary file, in a database, as an array in an image header,
or merely as a temporary array in memory. When the new image structures
become available storing the masks in the image header or in a global
database will probably be the best approach, but in the meantime the
simplest solution is to store each pixel list or mask in a small binary
file. This approach has the advantage of being independent of the
particular image format used (none of which are currently capable of
storing the pixel list directly in any case).
If desired, the name of the mask file may be stored in the image header
as a simple string valued parameter. Alternatively, the mask name may
be input as a parameter when a task is run. A single mask may be
associated with several images, or several masks may be used with the
same image. The approach to be followed for a particular program is up
to the programmer or package designer.
The bad pixel mask is a special case, since it has a well defined
logical meaning for an image, unlike the region masks which are
application specific. The most straightforward approach is to use a
single boolean mask for the bad pixel list, using the optional header
keyword BPM to store the mask name, which should normally be the image
name plus the pixel list file extension ".PL". An integer BPM could
also be used, but most applications would treat it as a boolean mask,
treating any pixel with a nonzero value as a bad pixel.
Any additional information required to describe the bad pixels is
application specific, and may be stored in any of several ways, e.g.,
as a set of boolean masks, in an integer mask, using flag bits or
reserved values to describe each pixel or region, in a separate fully
populated weight image, or using the noise function package. Most IRAF
applications will probably use the BPM plus a noise function, with the
noise function being stored either as a one-dimensional noise model or
as a separate uncertainty image, transparently to the application. The
combination of a one-dimensional noise model plus a compressed bad
pixel list should provide an efficient and flexible solution to the
pixel variance problem for most applications.
2.4 EXAMPLE
Open a data image and the associated mask image, and sum the pixels
within the area indicated by the mask.
include <pmset.h>
task sum = t_sum
-6-
PLIO (Feb88) Pixel List Package Design PLIO (Feb88)
# SUM -- Sum the image pixels lying within the given mask.
procedure t_sum()
char image[SZ_FNAME] # input data image
char mask[SZ_FNAME] # image mask
int npix, mval, totpix, m_flags
long v[PM_MAXDIM]
pointer im, mp, pp
real sum
bool clgetb()
real asumr()
int mio_glsegr()
pointer immap(), mio_open()
begin
call clgstr ("image", image, SZ_FNAME)
call clgstr ("mask", mask, SZ_FNAME)
m_flags = 0
if (clgetb ("invert"))
m_flags = INVERT_MASK
im = immap (image, READ_ONLY, 0)
mp = mio_open (mask, m_flags, im)
sum = 0; totpix = 0
while (mio_glsegr (mp, pp, mval, v, npix) != EOF) {
sum = sum + asumr (Memr[pp], npix)
totpix = totpix + npix
}
call mio_close (mp)
call imunmap (im)
call printf ("%d pixels, sum=%g, mean=%g\n")
call pargi (totpix)
call pargr (sum)
if (totpix > 0)
call pargr (sum / totpix)
else
call pargr (INDEF)
end
A more complex application might use the spatial information provided by
V and NPIX, or the flag values provided by MVAL (for an integer mask).
For example, a surface fitting routine would accumulate each line
segment into a least squares matrix, using the coordinate information
provided as well as the pixel values.
-7-
PLIO (Feb88) Pixel List Package Design PLIO (Feb88)
2.5 THE PIXEL MASK PACKAGE (PMIO)
We have thus far discussed two quite different interfaces, i.e.,
the use of IMIO to do pixel i/o to a mask mapped as a virtual mask
image, and the MIO interface, used to access the portion of a data
image visible through a mask. The next step is to define the interface
used to access the mask object directly as a MASK, independently of the
use of masks for image i/o.
pm = pm_newmask (ref_im, depth)
pm = pm_open (bufptr|NULL)
pm = pm_create (naxes, axlen, depth)
pm = pm_newcopy (pm)
pm_close (pm)
pm_[sg]size (pm, naxes, alxen, depth)
pm_seti (pm, param, value)
value = pm_stati (pm, param)
pm_debug (pm, outfd, maxcol, flags)
bool = pm_empty (pm)
pm_compress (pm)
pm_clear (pm)
pm_load (pm, bufptr)
nwords = pm_save (pm, bufptr, buflen)
pm_loadf (pm, fname, title, maxch)
pm_savef (pm, fname, title, save_flags)
pm_[load|save]im (pm, imname[, save_flags])
ptr = pm_access (pm, v)
bool = pm_linenotempty (pm, v)
bool = pm_sectnotempty (pm, vs, ve, ndim)
pm[gp]l[lrp][sil] (pm, v, buf, b_depth, npix, rop)
pm_[set|get]plane (pm, v)
pm_point (pm, x, y, rop)
pm_circle (pm, x, y, r, rop)
pm_box (pm, x1,y1, x2,y2, rop)
pm_line (pm, x1,y1, x2,y2, width, rop)
pm_polygon (pm, x, y, npts, rop)
pm_rop (pm_src, vs, pm_dst, vs, vn, rop)
pm_stencil (pm_src, vs, pm_dst, vs, pm_stl, vs, vn, rop)
There are two variants on this lowest level interface, known as PMIO
(pixel mask i/o) and PLIO (pixel list i/o). These two interfaces are
equivalent with one difference: PMIO can accept a reference image and
inherit the section transformation of the reference image, allowing the
mask to be accessed in the coordinate system of the reference image,
while PLIO is a stand alone interface, implemented independently of
IMIO without any ties to IMIO. PMIO is implemented as a thin layer
-8-
PLIO (Feb88) Pixel List Package Design PLIO (Feb88)
upon PLIO, with ties to IMIO to access the section transformation for
the reference image.
The PMIO interface is shown in the figure above. With the exception of
the additional routine PM_NEWMASK, used to create a new, empty mask the
same size as a reference image, the PMIO routines are identical to the
corresponding PLIO routines except for the PM package prefix, and the
implied section transformation. Indeed, if no reference image is
specified or if the section transformation is unitary (the reference
image was opened without an image section), the two interfaces are
identical. Hence the discussion of PLIO in the next section will serve
to document PMIO as well.
To use PMIO, merely include <PMSET.H> rather than <PLSET.H>, and set
the reference image with a call to PM_SETI, e.g.,
call pm_seti (pm, P_REFIM, ref_im)
This step can be skipped if PM_NEWMASK or PM_NEWCOPY is used to create
a new mask, as the reference image will be inherited by the new mask.
Programs which use PMIO to access a mask may also use the low level
line, range, and pixel list routines discussed in section 3.1
(PL_RANGEROP etc.) on lists returned by PMIO, since PMIO will have
already transformed the data into the coordinate system of the
reference image.
In general, the PMIO interface should be used in preference to PLIO
whenever the mask to be accessed is logically associated with some data
image or images. The region description and logical region processing
capabilities of PLIO are very powerful in their own right, however, and
PLIO should be used directly by applications which do not consider the
mask to be merely an overlay for a data image. An example would be any
application which operates upon a 2-dimensional data structure other
than an image (e.g., region filtering in the POE image kernel).
3. THE PIXEL LIST PACKAGE (PLIO)
A pixel list is a way of representing an N-dimensional image matrix
which is well suited for applications where the represented image is
sparse, or consists of a moderate number of arbitrarily shaped
regions. Routines are provided for creating new lists, for writing to
or reading from lists, for storing or retrieving lists, and for
performing various types of operations upon entire lists to make new
lists. The full set of routines in the package are summarized in the
figure below.
A pixel list, like an image, has a fixed dimensionality and size which
is determined at list creation time for the lifetime of the list. New
lists are created with PL_CREATE, which returns a pointer to an empty
-9-
PLIO (Feb88) Pixel List Package Design PLIO (Feb88)
list. The DEPTH parameter specifies the depth of the list in bits,
i.e., the number of bits per pixel, in the range 1-27. A boolean list
has a depth of 1 bit. In the current implementation the boolean mask
is handled as a degenerate case of an integer mask, i.e., an integer
mask which happens to have mask values in the range 0-1.
An existing list is accessed by opening a descriptor with PL_OPEN and
loading the list into the runtime descriptor structure, either by
specifying a non-NULL buffer pointer BUFPTR, or by calling one of the
PL_LOAD functions after opening a null descriptor.
pl = pl_open (bufptr|NULL)
pl = pl_create (naxes, axlen, depth)
pl = pl_newcopy (pl)
pl_close (pl)
pl_[sg]size (pl, naxes, axlen, depth)
pl_seti (pl, param, value)
value = pl_stati (pl, param)
pl_debug (pl, outfd, maxcol, flags)
bool = pl_empty (pl)
pl_compress (pl)
pl_clear (pl)
pl_load (pl, bufptr)
nwords = pl_save (pl, bufptr, buflen)
pl_loadf (pl, fname, title, maxch)
pl_savef (pl, fname, title, save_flags)
pl_[load|save]im (pl, imname[, save_flags])
ptr = pl_access (pl, v)
bool = pl_linenotempty (pl, v)
bool = pl_sectnotempty (pl, vs, ve, ndim)
pl[gp]l[lrp][sil] (pl, v, buf, b_depth, npix, rop)
pl_[set|get]plane (pl, v)
pl_point (pl, x, y, rop)
pl_circle (pl, x, y, r, rop)
pl_box (pl, x1,y1, x2,y2, rop)
pl_line (pl, x1,y1, x2,y2, width, rop)
pl_polygon (pl, x, y, npts, rop)
pl_rop (pl_src, vs, pl_dst, vs, vn, rop)
pl_stencil (pl_src, vs, pl_dst, vs, pl_stl, vs, vn, rop)
Pixel lists are stored externally as opaque binary byte arrays. The
function PL_SAVE will encode a pixel list as a byte array and store it
in the indicated buffer, resizing the buffer if necessary. If BUFPTR
is NULL a new buffer will be allocated, overwriting the NULL. The
PL_LOAD function performs the inverse function. The F suffixed
functions are provided for convenience when storing lists in small
binary files. The IM suffixed functions create masks out of actual
-10-
PLIO (Feb88) Pixel List Package Design PLIO (Feb88)
data images, and vice versa. In the most general case, a list is
encoded into an array in memory and then stored away by the applications
wherever they wish, e.g., as an array parameter in an image header when
the new image structures become available.
Pixel list i/o is provided via the PL[GP]L[LRP][SIL] family of
functions, which read, write, or edit (via the ROP) lines or line
segments of masks. The naming convention is as follows:
pl package prefix
[gp] get or put
l line segment
[lrp] as a line list, range list, or pixel array
[sil] in an array of type short, int, or long
For example, PLGLPS would get a line from a mask image as a fully
populated array of type short. For maximum efficiency, since this is a
low level interface, the data is read from or copied into a user
allocated buffer, rather than having the pixel list package control the
buffer.
The functions PLGLL[SIL] return the packed line list for the indicated
line or line segment. This is the copy-out form of access with the
least overhead, but requires that the application have knowledge of the
internal line list format.
Alternatively, if it is only desired to read from a list, accessing the
list in the internal format, the internal list for an image line may be
directly accessed by pointer with the PL_ACCESS function. This is the
most efficient form of access. The variant PL_LINENOTEMPTY is similar
except that the NULL pointer is returned if the indicated line of the
list is empty, providing an efficient and convenient way to perform the
empty test on mask image lines.
The functions PLGLR[SIL] are similar to the get line list form of
access, but instead of returning the encoded list-list in the internal
format, it returns a simple array of ranges of absolute pixel indices
and associated mask values. This is the recommended way of accessing
the mask as a list structured object, since it does not require
knowledge of the internal packed line list format. For example, to
print line V of the mask on descriptor PL as a series of range lists:
int buf[3,1024], n, i, plglri()
n = plglri (pl, v, buf, 0, axlen[1], 0)
do i = 1, n {
call printf ("range at %d, %d pixels, mask value = %o\n")
call pargi (buf[1,i]); call pargi (buf[2,i])
call pargi (buf[3,i])
}
These routines require that the depth in bits of the output line or
-11-
PLIO (Feb88) Pixel List Package Design PLIO (Feb88)
range list or pixel array be specified. This is necessary to avoid
generating numbers the size of the machine integer when inverting a
mask (PIX_NOT), e.g., if the mask depth is 8 bits, the complement of a
0 pixel should be 377, not 37777777777. The depth argument may also be
used to convert an integer mask to a boolean mask, or vice versa (using
the PIX_VALUE field of the rasterop discussed in the next section). If
B_VALUE is zero, clipping of the output values is disabled. This would
be appropriate, for example, when simply reading from a mask without
modifying the pixel values.
New pixel lists may be created by having the application prepare the
packed line lists externally, inserting them directly into the pixel
list structure with a PUT routine. This is generally inadvisable,
however, because the packed line list format is considered internal to
the PLIO package. A better alternative is to input the mask data as a
populated array or as a range list, letting the PL package manage the
internal line list.
A more convenient approach to creating or modifying masks for most
applications is to define the mask by specifying a series of include
and exclude standard region types (circles, boxes, lines, points, or
polygons), using the block of routines beginning with PL_SETPLANE in
the figure. Note that these are two dimensional operators; they are
provided for convenience even though the pixel list package can support
images of any dimension (if the image has three or more dimensions
PL_SETPLANE may be used to specify the plane to be operated upon). The
most general routine is PL_POLYGON, which may be used to operate upon
the pixels in the interior of any general polygon. All of the region
drawing operators will permit regions to extend beyond the boundary of
the mask, clipping as necessary at the boundary.
3.1 PIXEL, LINE, AND RANGE LIST ROUTINES
Most of the N dimensional region or mask oriented PMIO and PLIO
routines eventually result in calls to the low level pixel, line, and
range rasterop routines and format conversion routines shown in the
figure below. These routines form the functional core of the PLIO
package and will often be responsible for most of the execution time of
routines which use PLIO.
There are two main classes of routines. The PL_PIXROP, PL_LINEROP, and
PL_RANGEROP routines perform the general raster operation on pixel
arrays, line lists, and range lists. The PL_LINESTENCIL routine
performs the stencil rasterop operation upon line lists; currently only
a list list version is available since this is a rarely used routine.
Lastly, a set of six routines are provided for converting between any
two of the three formats, e.g., line list to range list or pixel array
and vice versa, omitting the like-to-like conversions. For example,
PL_P2RI would convert a pixel array to a range list, both of type
integer.
-12-
PLIO (Feb88) Pixel List Package Design PLIO (Feb88)
pl_linerop (ll_src, xs, src_maxval,
ll_dst, ds, dst_maxval, ll_out, npix, rop)
pl_linestencil (ll_src, xs, src_maxval, ll_dst, ds, dst_maxval,
ll_stn, xs, ll_out, npix, rop)
pl_pixrop[sil] (px_src, xs, src_maxval,
px_dst, ds, dst_maxval, npix, rop)
pl_rangerop[sil] (rl_src, xs, src_maxval,
rl_dst, ds, dst_maxval, rl_out, npix, rop)
n = pl_[lrp]2[lrp][sil] (op_src, xs, op_dst, npix)
Note that these low level routines specify the mask depth as a maximum
pixel value, rather than taking the depth in bits as the high level
PMIO and PLIO routines do, and that there are no "PM_" versions of
these routines - the one set of routines may be used with both PLIO and
PMIO.
3.2 RASTEROPS
The argument ROP in the circle, box, and other routines discussed
in the previous sections is called a RASTEROP, and specifies the bitwise
operation to be performed to generate the destination operand. Much of
the generality and conciseness of the pixel list package is due to the
rasterop abstraction, which is patterned after a similar construct used
by the Sun Microsystems SUNVIEW interface to specify operations upon
PIXRECTS, which are logically similar to PLIO masks.
The rasterop defines the operation to be performed to generate the
destination mask, in terms of bitwise boolean operations performed upon
the input source and destination masks. Rasterops are constructed via
a series of bitwise AND and OR operations, using the following macro
defines:
PIX_SRC specifies the source mask
PIX_DST specifies the destination mask
PIX_NOT(op) inverts the operand mask
PIX_VALUE(value) specifies the bitplanes to be set
Examples of some of the possible operations (out of a total of 16
possible operations) are shown below. This table is reproduced from
the SunView Pixrect Reference Manual.
-13-
PLIO (Feb88) Pixel List Package Design PLIO (Feb88)
RASTEROP DESCRIPTION
PIX_SRC copy source to destination
PIX_DST no-op
PIX_SRC | PIX_DST paint (OR source to destination)
PIX_SRC & PIX_DST mask (AND of source and destination)
PIX_NOT(PIX_SRC)&PIX_DST erase (AND destination with negation
of source)
PIX_NOT(PIX_DST) invert area (negate the existing
values)
PIX_SRC ^ PIX_DST inverting paint (XOR of source and
destination)
Here, the |&^ denote the SPP OR, AND, and XOR intrinsic functions,
which must be used to construct actual rasterop expressions in SPP,
e.g.:
PIX_NOT(PIX_SRC) | PIX_DST | PIX_VALUE(v)
would actually be written as
or (PIX_NOT(PIX_SRC), PIX_DST) + PIX_VALUE(v)
The following additional macros are defined to deal with the more common
cases of setting or clearing a region.
PIX_SET (PIX_SRC | PIX_NOT(PIX_SRC))
PIX_CLR (PIX_SRC & PIX_NOT(PIX_SRC))
As a simple example, consider the case of specifying a region mask as a
series of include and exclude circles and boxes. This is trivial for a
boolean mask: an include circle or box is specified by the rasterop
PIX_SET, and an exclude by PIX_CLR. In the equivalent operation upon
an integer mask this would cause any mask values which had already been
set to be replaced, hence it might be desirable to use a
PIX_SRC|PIX_DST rasterop instead, to OR the bits of the new flag values
into those of any flag values already set. Similarly, when using
PL_LTOP to unpack a line list into a pixel array, the PIX_SRC|PIX_DST
rasterop might be specified to OR the mask segment into an existing
pixel array.
General bitwise boolean operations upon masks are provided by the PL_ROP
and PL_STENCIL operators, which operate upon entire masks or rectangular
subregions of masks. The PL_ROP operator combines the source and
destination masks to produce a new mask; PL_STENCIL performs the same
operation, but only in the regions specified by the stencil mask, which
must be a boolean mask. The input mask may be NULL (depending upon the
rasterop specified), or the source and destination masks may be the
same.
The equivalent operators for line lists, range lists, and pixel arrays
are the PL_S2D family of routines, where S=D=[LRP] for a line list,
-14-
PLIO (Feb88) Pixel List Package Design PLIO (Feb88)
range list, or pixel array rop. The routine PL_LINESTENCIL implements
the stencil operation for a line list.
As noted above, when operating upon integer masks (DEPTH > 1), the
PIX_VALUE macro is used to specify the flag value for the indicated
region. For example, the following rasterop would set all the pixels
in a region to the same value:
PIX_VALUE(value)
to OR in the new value instead of replacing any existing flag values:
PIX_VALUE(value) | PIX_DST
If a boolean mask is to be written to an integer mask, PIX_VALUE
specifies the flag value to be used for the regions set to 1 in the
input boolean mask. For example, one might wish to combine a set of 8
boolean masks to form a single 8 bit deep integer mask, with each bit
in the integer mask corresponding to one of the input boolean masks
(001 = mask 1, 002 = mask 2, 040 = mask 3, etc.). This could be done
using the rasterop shown above, incrementing PIX_VALUE in each
operation to specify the bitplane to be set.
3.2.1 RASTEROP EXPRESSION EVALUATION
As mentioned above, there are sixteen possible ways to combine the
source and destination masks subject to the four possible boolean
operations (AND, OR, XOR, and NOT). More precisely, although numerous
bitwise expressions can be constructed, many of these are equivalent,
and there are only sixteen fundamental operations. These are
summarized in the following table.
Operation Opcode
PIX_CLR 00
PIX_SET 17
PIX_SRC 14
PIX_DST 12
PIX_NOT(PIX_SRC) 03
PIX_NOT(PIX_DST) 05
PIX_SRC & PIX_DST 10
PIX_SRC | PIX_DST 16
PIX_SRC ^ PIX_DST 06
PIX_SRC & PIX_NOT(PIX_DST) 04
PIX_SRC | PIX_NOT(PIX_DST) 15
PIX_NOT(PIX_SRC) & PIX_DST 02
-15-
PLIO (Feb88) Pixel List Package Design PLIO (Feb88)
PIX_NOT(PIX_SRC) | PIX_DST 13
PIX_NOT (PIX_SRC & PIX_DST) 07
PIX_NOT (PIX_SRC | PIX_DST) 01
PIX_NOT (PIX_SRC ^ PIX_DST) 11
As an example of the redundancy of arbitrary rasterop expressions,
compare the following with the equivalent expressions (same opcode) in
the table above.
PIX_NOT(PIX_SRC) & PIX_NOT(PIX_DST) 01
PIX_NOT(PIX_SRC) ^ PIX_NOT(PIX_DST) 06
PIX_NOT(PIX_SRC) | PIX_NOT(PIX_DST) 07
PIX_NOT(PIX_SRC) ^ PIX_DST 11
PIX_SRC ^ PIX_NOT(PIX_DST) 11
Any number of additional logically redundant expressions may be
constructed. The programmer should not worry about simplifying logical
expressions, but should choose instead whatever expression is clearest
for their particular application, letting the interface handle
expression optimization internally.
Of the sixteen possible fundamental operations, there are four trivial
operations (CLR, SET, SRC, DST), seven composite operations, and four
primary operations, namely, AND, OR, XOR, and NOT (two cases of the
latter). The composite operations are all implementable as two primary
operations in sequence. PIX_NOT is implemented by actual inversion of
the list rather than as a mode flag, to avoid complications when the
list is read.
3.2.2 RASTEROP ENCODING
The rasterop argument specifies the bitwise boolean operation to be
performed, and optionally the pixel value to be used (in the case of an
integer mask). Both are specified as a single integer value, packed as
shown in the figure below.
+--+-------------+--------+
|32|31 5|4 1|
+--+-------------+--------+
| | pixel value | opcode |
+--+----------------------+
The following is an example of a typical rasterop (note that since the
pixel value field has a reserved range of bits which is zero prior to
expression evaluation, the "+" operator is equivalent to the OR
intrinsic function).
or(PIX_SRC, PIX_NOT(PIX_DST)) + PIX_VALUE(pix_value)
-16-
PLIO (Feb88) Pixel List Package Design PLIO (Feb88)
Note that the width of the pixel value field in the rasterop constrains
the effective mask depth to be 27 bits or less, if full generality is
desired in rasterop operations. Masks of up to 31 bits (the minimum
unsigned precision of a LONG) can be stored and accessed, but rasterops
using PIX_VALUE are limited to 27 bits.
3.3 PIXEL LIST DATA STRUCTURES
A pixel list consists of an array of pointers to the LINE LISTS
forming the mask. There is one pointer for each image line; if the
pointer is NULL, no mask values are set on the associated image line.
N-dimensional images are easily handled by an N-1 dimensional array of
line pointers.
Each line list consists of a series of offsets and mask pixel values
(the pixel values are normally omitted for a boolean mask). The
offsets specify the number of pixels for which the mask has the same
value. This line list format has the following two significant
advantages over the alternative technique of specifying a list of
ranges using absolute pixel coordinates:
[1] A higher degree of data compression is possible. If absolute
pixel coordinates are used in the list, the list must be an
array of 32 bit integer values in order to avoid a builtin
limit on the size of the image which can be represented. By
using offsets, list elements as small as one byte are possible.
[2] A list composed of offsets is invariant with respect to
translation. For example, when extracting a subraster of an
image, one can extract the corresponding segment of each line
list and perhaps edit the first element, and the remainder of
the list may be used without change.
When describing regular regions such as boxes it will often be the case
that successive lines of the mask are equivalent, in which case
multiple line list pointers may point to the same line list. Hence,
the line lists will provide good compression of regular objects in any
two dimensional plane of the mask. This technique can be extended to
higher dimensions if desirable, without affecting the line list data
structures visible to an application.
3.3.1 LINE LIST ENCODING
A good compromise between storage efficiency and efficiency of
runtime access, while keeping things simple, is achieved if we maintain
the compressed line lists as variable length arrays of type short
integer (16 bits per list element), regardless of the mask depth. A
line list consists of a series of simple INSTRUCTIONS which are