Image File System Reference Manual Version 8.2.6 April 5, 2014 Wesley Snyder 2 Acknowledgements Based on suggestions by Wesley Snyder of North Carolina State University and Joe Erkes of General Electrics Corporate Research and Development Center, the staff of Communication Unlimited, Inc. designed and coded IFS version 1 during the fall of 1986. Mark Lanzo designed and implemented most of versions 1-4, although other members of the CUI staff contributed heavily, including Katie Boone, Mark Yarboro, Gary McCauley, Bennett Groshong, and Paul Hemler. Katie Boone is responsible for version 5, and Rajeev Ramanath contributed heavily to the creation of Version 6. Version 7 never really got listed as a separate version. Version 8 incorporated 64 bit computers, and compatibility with openCV, and was written mostly by Wesley Snyder and Ben Riggan. IFS is a trademark of Communication Unlimited, Inc. IFS is jointly owned by CUI and North Carolina State University. Contents 1 The IFS system 1.0.1 New with version 8.1 . . . . . . . . . . . 1.0.2 New with Version 8 . . . . . . . . . . . 1.0.3 New with Version 6 . . . . . . . . . . . 1.0.4 New with Version 5 . . . . . . . . . . . 1.1 Using IFS . . . . . . . . . . . . . . . . . . . . . 1.1.1 Program Compilation and Linking . . . 1.2 Referencing IFS images . . . . . . . . . . . . . 1.2.1 Naming conventions in IFS . . . . . . . 1.3 Error handling in IFS . . . . . . . . . . . . . . 1.3.1 Image validation in IFS . . . . . . . . . 1.3.2 Header Files . . . . . . . . . . . . . . . 1.3.3 Coordinate systems and array storage in 1.4 IFS FUNCTION LISTING . . . . . . . . . . . 1.4.1 bilininterp . . . . . . . . . . . . . . . . . 1.4.2 ifsalc . . . . . . . . . . . . . . . . . . . . 1.4.3 ifscigp read from complex or real image 1.4.4 ifscigp3d . . . . . . . . . . . . . . . . . . 1.4.5 ifscipp . . . . . . . . . . . . . . . . . . . 1.4.6 ifscipp3d . . . . . . . . . . . . . . . . . . 1.4.7 ifscfgp . . . . . . . . . . . . . . . . . . . 1.4.8 ifscfgp3d . . . . . . . . . . . . . . . . . . 1.4.9 ifscfpp . . . . . . . . . . . . . . . . . . . 1.4.10 ifscfpp3d . . . . . . . . . . . . . . . . . 1.4.11 Ifsclose . . . . . . . . . . . . . . . . . . 1.4.12 ifscreate . . . . . . . . . . . . . . . . . . 1.4.13 ifs2ipl . . . . . . . . . . . . . . . . . . . 1.4.14 ipl2ifs . . . . . . . . . . . . . . . . . . . 1.4.15 ifsCVpin . . . . . . . . . . . . . . . . . . 1.4.16 ifsCVpot . . . . . . . . . . . . . . . . . 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . IFS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 9 10 10 10 11 11 12 13 13 14 18 19 20 21 21 22 23 24 25 26 27 28 29 30 31 33 33 33 34 4 CONTENTS 1.5 1.6 1.7 1.4.17 ifsCVPopup . . . . . . . . . . . . . . . . . . . 1.4.18 IFSDISPLAY . . . . . . . . . . . . . . . . . . 1.4.19 Building ifsCV and IFSDisplay with openCV 1.4.20 ifsdimen . . . . . . . . . . . . . . . . . . . . . 1.4.21 ifsexwin . . . . . . . . . . . . . . . . . . . . . 1.4.22 ifsexwin3d . . . . . . . . . . . . . . . . . . . . 1.4.23 ifsfgp . . . . . . . . . . . . . . . . . . . . . . 1.4.24 ifsfgp3d . . . . . . . . . . . . . . . . . . . . . 1.4.25 ifsfpp3d . . . . . . . . . . . . . . . . . . . . . 1.4.26 ifsfpp . . . . . . . . . . . . . . . . . . . . . . 1.4.27 ifsfree . . . . . . . . . . . . . . . . . . . . . . 1.4.28 ifsGetFN . . . . . . . . . . . . . . . . . . . . 1.4.29 ifsGetImg . . . . . . . . . . . . . . . . . . . . 1.4.30 ifsigp . . . . . . . . . . . . . . . . . . . . . . . 1.4.31 ifsipp . . . . . . . . . . . . . . . . . . . . . . 1.4.32 ifsmkh . . . . . . . . . . . . . . . . . . . . . . 1.4.33 ifsopen . . . . . . . . . . . . . . . . . . . . . . 1.4.34 ifspin . . . . . . . . . . . . . . . . . . . . . . 1.4.35 ifspot . . . . . . . . . . . . . . . . . . . . . . 1.4.36 ifsPrsFN . . . . . . . . . . . . . . . . . . . . . 1.4.37 ifsPutImg . . . . . . . . . . . . . . . . . . . . 1.4.38 ifsRdHdr . . . . . . . . . . . . . . . . . . . . 1.4.39 ifsRdImg . . . . . . . . . . . . . . . . . . . . 1.4.40 ifssiz . . . . . . . . . . . . . . . . . . . . . . . 1.4.41 ifsslice . . . . . . . . . . . . . . . . . . . . . . 1.4.42 ifsversion . . . . . . . . . . . . . . . . . . . . 1.4.43 ifsWrImg . . . . . . . . . . . . . . . . . . . . IFS Error Codes . . . . . . . . . . . . . . . . . . . . IFS Data Types . . . . . . . . . . . . . . . . . . . . . The structure of an IFS image . . . . . . . . . . . . 1.7.1 The image header fields . . . . . . . . . . . . 1.7.2 The dimension sub-header fields . . . . . . . 2 The FLIP library 2.1 Example Program Using 2.2 Matrix Operations . . . 2.2.1 dmatrix . . . . . 2.2.2 matrix . . . . . . 2.2.3 dvector . . . . . 2.2.4 vector . . . . . . 2.2.5 ivector . . . . . . the FLIP functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 36 37 38 39 40 41 42 43 44 45 47 48 49 51 53 54 55 56 57 58 59 60 61 62 63 64 64 65 66 67 70 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 73 74 74 75 75 75 75 CONTENTS 2.3 2.4 2.5 2.2.6 free ivector . . . . . . . . 2.2.7 free dvector . . . . . . . . 2.2.8 free vector . . . . . . . . . 2.2.9 transpose . . . . . . . . . 2.2.10 ifsmatmult . . . . . . . . 2.2.11 ifsinverse . . . . . . . . . 2.2.12 jacobi . . . . . . . . . . . Arithmetic Operations on Images 2.3.1 flabsolute . . . . . . . . . 2.3.2 fladds . . . . . . . . . . . 2.3.3 fladdv . . . . . . . . . . . 2.3.4 flclip . . . . . . . . . . . . 2.3.5 flcp . . . . . . . . . . . . 2.3.6 fldivs . . . . . . . . . . . . 2.3.7 fldivv . . . . . . . . . . . 2.3.8 flexp . . . . . . . . . . . . 2.3.9 flln . . . . . . . . . . . . . 2.3.10 flmults . . . . . . . . . . . 2.3.11 flmultv . . . . . . . . . . 2.3.12 flneg . . . . . . . . . . . . 2.3.13 flnorm . . . . . . . . . . . 2.3.14 flrec . . . . . . . . . . . . 2.3.15 flsq . . . . . . . . . . . . . 2.3.16 flsqrt . . . . . . . . . . . . 2.3.17 flsubs . . . . . . . . . . . 2.3.18 flsubv . . . . . . . . . . . 2.3.19 flthresh . . . . . . . . . . 2.3.20 flthresh2 . . . . . . . . . . Image Manipulation Functions . 2.4.1 flone border . . . . . . . . 2.4.2 flpad . . . . . . . . . . . . 2.4.3 flplanar . . . . . . . . . . 2.4.4 flrotate . . . . . . . . . . 2.4.5 flshx . . . . . . . . . . . . 2.4.6 flshxy . . . . . . . . . . . 2.4.7 flshy . . . . . . . . . . . . 2.4.8 flzero border . . . . . . . Derivative Operators . . . . . . 2.5.1 flDoG . . . . . . . . . . . 2.5.2 flGabor . . . . . . . . . . 2.5.3 fldx . . . . . . . . . . . . 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 76 76 76 76 77 77 77 77 77 78 78 78 78 78 79 79 79 79 79 79 80 80 80 80 80 80 81 81 81 81 81 81 82 82 82 82 83 83 84 85 6 CONTENTS 2.6 2.7 2.5.4 fldx back . . . . . . . . . . . . . . . . . . . . . . . 2.5.5 fldx forw . . . . . . . . . . . . . . . . . . . . . . . 2.5.6 fldxx . . . . . . . . . . . . . . . . . . . . . . . . . . 2.5.7 fldxy . . . . . . . . . . . . . . . . . . . . . . . . . . 2.5.8 fldxz . . . . . . . . . . . . . . . . . . . . . . . . . . 2.5.9 fldy . . . . . . . . . . . . . . . . . . . . . . . . . . 2.5.10 fldy back . . . . . . . . . . . . . . . . . . . . . . . 2.5.11 fldy forw . . . . . . . . . . . . . . . . . . . . . . . 2.5.12 fldyy . . . . . . . . . . . . . . . . . . . . . . . . . . 2.5.13 fldyz . . . . . . . . . . . . . . . . . . . . . . . . . . 2.5.14 fldz . . . . . . . . . . . . . . . . . . . . . . . . . . 2.5.15 fldzz . . . . . . . . . . . . . . . . . . . . . . . . . . Running the FLIP functions from the command line . . . 2.6.1 flpg1: single input FLIP functions . . . . . . . . . 2.6.2 der1: take a derivative of an image . . . . . . . . . 2.6.3 ifsDoG:Apply a derivative of Gaussian kernel to an Image Manipulation . . . . . . . . . . . . . . . . . . . . . 2.7.1 ifsadd . . . . . . . . . . . . . . . . . . . . . . . . . 2.7.2 ifsany2any . . . . . . . . . . . . . . . . . . . . . . . 3 Image Processing Subroutines 3.1 Geometric functions . . . . . 3.1.1 chainHull 2D . . . . . 3.1.2 compute curvature . . 3.1.3 InsideTriangle . . . . . 3.1.4 InterpolateTriangle . . 3.1.5 cubic splines . . . . . 3.1.6 Resampling Curves . . 3.1.7 Operations on FIFO’s 3.1.8 MinimumRegion . . . 3.1.9 Watersheds . . . . . . 3.1.10 ifs ccl . . . . . . . . . 3.1.11 ifscfft2d . . . . . . . . 3.1.12 ifsc2imag . . . . . . . 3.1.13 ifsc2mag . . . . . . . . 3.1.14 ifsc2phase . . . . . . . 3.1.15 ifsc2real . . . . . . . . 3.1.16 ifsInsert2Dinto3D . . . 3.1.17 ifsmult . . . . . . . . . 3.1.18 ifsrecip . . . . . . . . . 3.1.19 ifssub . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ifs image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 86 86 86 86 86 87 87 87 88 88 88 88 89 89 90 90 90 90 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 93 93 93 94 94 97 98 100 101 101 101 105 106 107 108 109 110 111 112 113 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . CONTENTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 114 114 115 115 116 116 4 Image Synthesis Programs 4.1 Qsyn-synthesize range images . . . . . . . . . . 4.2 3dsyn-synthesize density images . . . . . . . . . 4.3 Matte - synthesize luminance images . . . . . . 4.4 Tomosim - simulate tomographic X-ray source . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 117 123 133 134 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ifs image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 135 135 135 136 137 137 137 137 137 137 137 138 138 139 139 139 139 139 139 139 139 140 140 140 140 141 3.2 3.3 3.1.20 ifsvidscale . . . . . . . . Functions to modify images . . 3.2.1 ifscolormap . . . . . . . 3.2.2 Lower Complete Images 3.2.3 zoomupdown . . . . . . Random number generators . . 3.3.1 gaussrand . . . . . . . . 7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Programs for processing images 5.1 add . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 addhdr . . . . . . . . . . . . . . . . . . . . . . . . . 5.3 atoi . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4 any2any . . . . . . . . . . . . . . . . . . . . . . . . 5.5 c2imag . . . . . . . . . . . . . . . . . . . . . . . . . 5.6 c2mag . . . . . . . . . . . . . . . . . . . . . . . . . 5.7 c2phase . . . . . . . . . . . . . . . . . . . . . . . . 5.8 c2real . . . . . . . . . . . . . . . . . . . . . . . . . 5.9 compmag . . . . . . . . . . . . . . . . . . . . . . . 5.10 ChooseFrame . . . . . . . . . . . . . . . . . . . . . 5.11 gauss add Gaussian-distributed noise to an image . 5.12 ifsDoG Apply a derivative of Gaussian kernel to an 5.13 itoa . . . . . . . . . . . . . . . . . . . . . . . . . . 5.14 mkdoc . . . . . . . . . . . . . . . . . . . . . . . . . 5.15 mult . . . . . . . . . . . . . . . . . . . . . . . . . . 5.16 profile . . . . . . . . . . . . . . . . . . . . . . . . . 5.17 prthdr . . . . . . . . . . . . . . . . . . . . . . . . . 5.18 rmvhdr . . . . . . . . . . . . . . . . . . . . . . . . 5.19 subsample . . . . . . . . . . . . . . . . . . . . . . . 5.20 recip . . . . . . . . . . . . . . . . . . . . . . . . . . 5.21 sub . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.22 triangulate . . . . . . . . . . . . . . . . . . . . . . 5.22.1 Input File Format . . . . . . . . . . . . . . 5.22.2 Output File Format . . . . . . . . . . . . . 5.23 vidscale . . . . . . . . . . . . . . . . . . . . . . . . 5.24 window . . . . . . . . . . . . . . . . . . . . . . . . 8 CONTENTS 5.25 zoomupdown . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141 6 Programs for Analyzing Images 6.1 Harris-Laplace . . . . . . . . . . . . . . . . . . . 6.2 PCON - Piecewise-constant image noise removal 6.3 PLIN - Piecewise-linear image noise removal . . . 6.4 WaterSheds . . . . . . . . . . . . . . . . . . . . . 6.5 ccl Connected-component Labeling . . . . . . . . 6.6 resample curve . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143 143 143 146 148 149 151 7 Programs for Viewing IFS images 7.1 ColorMap . . . . . . . . . . . . . . . . . . 7.2 Eigenimages . . . . . . . . . . . . . . . . . 7.3 ifsview – view ifs images . . . . . . . . . . 7.4 makecolor . . . . . . . . . . . . . . . . . . 7.5 PlayMovie- play a 3D ifs image as a movie 7.6 Plotcontour . . . . . . . . . . . . . . . . . 7.7 C2LaTeX-convert source code to LaTeX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 153 154 154 156 156 157 157 . . . . . . . . . . . . . . . . . . . . . . . . . . . . Chapter 1 The IFS system The IFS Image File System is a set of subroutines, and programs based on those subroutines, used to manipulate images, from within C or C++ programs. An image just refers to any array of data. The term came into use because IFS was originally written to manipulate 2-dimensional pictures, such as ones obtained from a standard camera. However, IFS is not restricted to 2-dimensional images, and is capable of handling arrays of arbitrary dimensionality. In the current release of IFS, most of the image manipulating routines are designed specifically for 2- or 3-dimensional data. Later releases of IFS will have enhanced multidimensional routines. At the simplest level, IFS is a simple system to use, and hides from the user the implementation details of basic data manipulation functions, such as allocating space for data arrays, performing I/O, and manipulating images with different data formats. When used in this way, IFS provides a development tool for program writing, and is not designed to for high execution speed. Use of the standard IFS image access functions such as ifsigp is in fact quite slow in some operations. It is efficient when the aim is to write and test programs quickly and easily. However, for the sophisticated user, IFS does provide access to pointers and data types which allow very speed- efficient software to be written while retaining the IFS image structure. The FLIP (floating point image processing) library was written in this way, to optimize computer speed. 1.0.1 New with version 8.1 There is no longer a libiptools.a All functions except flip are in libifs.a There is now a function which will rotate images about their center, flrotate. In the flip library, however, it will accept inputs which are data types other than float. It does floats and u8bit with pointers, so it’s pretty fast. 9 10 CHAPTER 1. THE IFS SYSTEM 1.0.2 New with Version 8 Several changes to ifs were mandated by the changes in technology which produced a move to 64-bit machines. These include • Complete support for 32-bit and 64 bit machines. This has been tested on Unix (macintosh) and Linux, but not yet on Windows. • New interface with OpenCV. OpenCV provides many attractive features, such as the ability to easily convert bmp, jpg, and other data types, but lacks many of the ifs capabilities, including the ability to manipulate images with any data type and any number of dimensions. Version 8 supports this with a new version of any2any which pretty much will convert any data type to any data type (there are some exceptions of course). The new OpenCV interface also provides a new image viewing capability which smoothly handles two- and three-dimensional images and color images. 1.0.3 New with Version 6 • Support for all processing platforms. Versions of IFS release 6 run on Intel computers under the Microsoft Windows operating system. • IFS Win32 has been tested under windows 2000 and windows XP. It has not been tested (and will probably not work) under Windows 3.1 • Release 6 also runs under RedHat Linux, Enterprise. It has been run under RedHat Fedora, but has not been tested thoroughly. • Release 6 runs on the SUN platforms under Solaris. Release 6 runs on the Macintosh under OS-X. It does not run under Mac OS 9. • Compression By default, all files written by IFS 6 are compressed. They are automatically uncompressed on read. It is possible for the application program to set a flag in the header telling the write subroutine to not compress the file. Uncompressed files can be read by IFS 5, but compressed files can only be read by IFS 6. • New, enhanced display capabilities 1.0.4 New with Version 5 • Support for X-windows. IFS images may now be displayed on any X-windows device. The graphics support automatically determines the dynamic range of the graphics device many X-windows devices are binary, for example ,and either thresholds or dithers, at the users command. 1.1. USING IFS 11 • CPU independent code. Various computers use different conventions for storage of bytes within a word, necessitating byte-swapping when one machine reads a file written on another. Furthermore, depending on the computer, byte swapping may be required on 16 bit or 32 bit boundaries, or both. Finally, there are at least two different conventions for floating point data, DEC and IEEE,which must still be corrected after byte swapping. IFS Version 5 automatically determines what type of machine it is running on and determines what type of machine wrote the input file. Should the input file be incompatible, the IFS file read routine automatically performs all data conversions. 1.1 1.1.1 Using IFS Program Compilation and Linking In order to use IFS, the user needs to link his/her programs to the IFS library at compilation time. To specify these libraries in a Unix environment, one would use the switches -lifs on the cc or ld command. For example, a typical command to compile a program would look like: cc -g test.c -o test -lifs The compiler directive -lifs actually tells the loader to look in /usr/lib or /usr/local/lib for a file named libifs.a. Not all computers have libifs.a installed in the /usr directory, so the user may need to change this command. Instead of using -lifs simply use the entire path the the library file. For example, it might be cc whatever.c /myhomedirectory/ifs/ifslbiraries/libifs.a To actually make use of the IFS functions, the users program also needs to include a header file or two to define various structures used by the IFS routines. All programs which use IFS should include the files stdio.h and ifs.h. Most IFS routines will return error codes through an external global variable called ifserr; if the user plans to examine these error codes he/she should also include the header file ifserr.h. This file defines a set of symbolic constants which one may use rather than using actual values for codes. It is not wise to use actual values in place of these constants when writing programs as the deffnitions for the constants may change from one release of IFS to the next. 12 CHAPTER 1. THE IFS SYSTEM #include<stdio.h> #include<ifs.h> main() { IFSIMG img1,img2; /*Declare pointers to headers */ int len[3]; /*len is an array of dimensions, used by ifscreate*/ int threshold;/*threshold is an int here */ int row,col;/*counters */ int v; img1=ifspin("infile.ifs");/*read in file by this name */ len[0]=2;/*image to be created is two dimensional */ len[1]=128;/*image has 128 columns */ len[2]=128;/*image has 128 rows */ img2=ifscreate("u8bit" ,len, IFS_CR_ALL,0) ;/*image is unsigned 8bit */ threshold=55;/*set some value to threshold */ for(row=0;row< 128;row++) for(col=0;col< 128;col++) { v=ifsigp(img1,row,col);/*read a pixel as an int*/ if(v<threshold) ifsipp(img2,row, col ,255); else ifsipp(img2, row, col, 0); } ifspot(img2,"img2.ifs"); /*write image 2 to disk */ } Figure 1.1: An example ifs program 1.2 Referencing IFS images All IFS images include a header which contains various items of information about the image, such as the number of points in the image, the number of dimensions for the image, and the data format. Also associated with the image is the actual data for the image. The image header includes a pointer to the image data in memory. The user manipulates an image by calling some function in the IFS library; one of the arguments to the function will be the address of the header for the image. The functions will automatically figure out where the data is and how to access it from the information in the header. In addition to handling the work of accessing data in images, the IFS routines automatically take care of allocating of space in memory to store data and headers. Everything is totally dynamic in operation; there are no fixed-dimension arrays needed. This relieves the user of the difficulties involved with accessing data in arrays, when using C, when the arrays are not of some fixed size. The header structure for an image is defined in the file ifs.h, and is known by the name IFSHDR. To manipulate an image, the user merely needs to declare a pointer to an image header structure as IFSHDR *yourimage; or, equivalently, 1.3. ERROR HANDLING IN IFS 13 IFSIMG yourimage; Then, the user simply calls some IFS function to create a new image, and sets the pointer to the value returned from that function. Some typical programs are given in the examples in 1.1 through ??. 1.2.1 Naming conventions in IFS Almost all of the IFS functions have names which begin with the letters ifs, so users should have no problems avoiding conflicts when naming their own functions. Also, all external variables or defined constants also begin with the letters“ifs” or “IFS”. Originally, all IFS routines had names which were limited to 6 characters in an effort to improve compatibility between different compilers. Unfortunately, with three of the letters already being fixed as “ifs”, this doesnt leave much left to create meaningful function names with. Hence, many IFS functions have rather cryptic names. Later versions of IFS have relaxed this restriction, so that newer functions have longer and more descriptive names. Starting with release 3.0 of IFS, all of the IFS functions also have version numbers built into them. These version numbers are actually printable strings which are globally accessible. These strings usually contain the functions name, a version number, and the date of the last modification to the function. Other items of information may occasionally also be contained in the string. If an IFS function has a name ifsXXXX, where XXXX is just some stem naming the function, then the string which gives its version number will have the name ifsvXXXX. For instance, if a user wanted to know what version of the function ifscreate was in his IFSlibrary, he could include the statements extern char *ifsv_create; printf("version is \%d \n",ifsv_create); somewhere within her program. 1.3 Error handling in IFS IFS provides various levels of error checking. When an error occurs, an IFS function usually returns some sort of error flag. IFS also has two external global variables which relate to error handling. The first one is known as ifserr, and is set to error codes which the user may examine to help determine what went wrong. The second one is IFSSLV for IFS Severity Level, which affects the action IFS takes upon detecting an error. Both of these variables are declared as extern int variables in the header file ifs.h, so it is not necessary for the user to declare them. The various error codes which may be returned are defined in the header file ifserr.h, which the user should make sure to include in his/her program if he/she plans on using ifserr. These error codes are described in detail in Section 1.5. Scrutinizing the file ifserr.h may also prove useful. 14 CHAPTER 1. THE IFS SYSTEM The error codes are indicated by individual bits in ifserr, so it is actually possible for several error flags to be set simultaneously. Also,some error codes are actually combinations of other codes. For instance, the codes IFSENOOPEN and IFSENOTIMAGE are two possible errors which may occur when trying to read or write IFS images. If the user checks for the condition IFSEIOERR, she has automatically tested for both of the errors IFSENOOPEN and IFSENOTIMAGE. The way to test for such error codes is with the bitwise logical AND operator, rather than with a comparison. I.e.: if(ifserr&IFSE IO ERR)... is preferable to: if(ifserr == IFSE IO ERR... because in this way, more than one bit may be tested, or just a single bit. The second global variable, IFSSLV, allows the user to specify what action to take when an error occurs. Currently, there are three possible courses of action to take upon an error;these are chosen by setting IFSSLV to some severity level code. The three severity levels are represented by the constants IFSQUIET, IFSWARN, and IFSFATAL, which are defined in ifs.h. These affect the action taken upon the occurrence of an error as follows: • IFSQUIET Do not print out any error messages to the user. The function just returns an error code to the calling routine. The user must make sure to watch out for this code, and act accordingly. If the error is not handled, the program will probably crash. • IFSWARN If an error occurs, print out some message describing the error to stderr. The routine also returns the appropriate error code. This allows the user to know what is going on, but still allows the program to trap errors. IFSWARN is probably the recommended severity level for most applications, and is the default value for IFSSLV. • IFSFATAL If an error occurs, print out an error message, and abort the program. This is not an exceedingly user-friendly option, but is probably better than the perennial Unix favorite “buserror:core dumped”. 1.3.1 Image validation in IFS Most IFS functions will double-check the header of an image before attempting to perform some operation on the image. This is done to verify that the argument the user passed to the function legitimately points to an IFS image, and does not just represent some random value. The most likely source for such an error would be insufficient error checking in a users program, when the severity level variable IFSSLV was set to some value other than IFSFATAL. For instance, a section of code such as img=ifsmkh(nrows,ncols,ubyte"); ifsipp(img,10,20,255); 1.3. ERROR HANDLING IN IFS 15 #include <stdio.h> #include <ifs.h> main() { IFSIMG img1,img2; /*Declare pointers to headers */ int *len; /*len is an array of dimensions, used by ifscreate*/ int frame,row,col; /*counters */ float threshold,v; /*threshold is a float here */ img1 = ifspin("infile.ifs"); /*read in file by this name */ len = ifssiz(img1); /*get dimensions of input image */ /*ifssiz returns a pointer to an array of dimensions*/ img2 = ifscreate(img1->ifsdt, len, IFS_CR_ALL,0); /*output image is to be*/ /*same type as input */ threshold = 55; /*set some value to threshold */ /* check for one, two or three dimensions*/ switch(len[0] { case 1: /*1dsignal*/ { for(col=0;col<len[1];col++) v=ifsfgp(img1,0,col);/* read a pixel as a float*/ if(v<threshold) ifsfpp(img2,0,col,255.0);/* write a float */ /* if img2 not float, will be converted*/ else ifsfpp(img2,0,col,0.0); } break; case 2:/*2dpicture*/ for(row=0;row<len[2];row++) for(col=0;col<len[1];col++) { v=ifsfgp(img1,row,col);/*read a pixel as a float*/ if(v<threshold) ifsfpp(img2,row,col,255.0);/* store a float */ else ifsfpp(img2,row,col,0.0); } break; Figure 1.2: First portion of example, see Figure 1.3 for remainder 16 CHAPTER 1. THE IFS SYSTEM case3:/*3dvolume*/ for(frame=0;frame<len[3];frame++) for(row=0;row<len[2];row++) for(col=0;col<len[1];col++) { v=ifsfgp3d(img1,frame,row,col);/*read a pixel as a float */ if(v<threshold ifsfpp3d(img2, frame, row, col, 255.0); else ifsfpp3d(img2,frame,row,col,0.0); } break; default: printf(" Sorry I cant do 4 or more dimensions\n"); } ifspot(img2,"img2.ifs"); /*write image2 to disk */ } Figure 1.3: Example IFS program to threshold an image using number of dimensions, size of dimen-sions, and data type determined by the input image (Although the example above uses ifsmkh, it is now recommended that ifscreate should be used instead.) which attempts to create an image and set the pixel at location 10,20 to a value of 255 could be a potential source for an error, if ifsmkh had been incapable of creating the image as requested. It would then have returned the value NULL, which would be passed to the function ifsipp. If ifsipp did not check the header, it would blindly attempt to use NULL as a pointer to an image header, which would probably crash the users program. The problem with this error checking is that it takes time to perform. If an image was 100 by 100 pixels in size, and the routine ifsipp was used to set the value of each pixel in the image, then the header would end up being checked 10000 times! For a program which accesses an image heavily, this header checking overhead takes a significant amount of time. Timing analyses on sample programs have shown that it is possible for 30 % of the CPU time used by a program to be spent in the header checking operation. The user may disable the header checking operation in some IFS routines. This, of course, places upon the programmer the responsibility to perform more extensive error checking operations, if robust code is desired. If the user sets the external integer variable IFSCHK to zero, then certain routines will cease to check image headers. Header checking can be reenabled by setting IFSCHK to any non-zero value. Note that not all of the IFS routines are affected by IFSCHK. Generally, only those routines which are called with high frequency, and for which the header checking represents a significant fraction of the execution time for that function, will be affected by this variable. Incidentally, it is not necessary for the users program to declare IFSCHK. As with IFSSLV and ifserr, this is 1.3. ERROR HANDLING IN IFS 17 #include <stdio.h> #include <ifs.h> main() { IFSIMG img1,img2; /*Declare pointers to headers*/ int len[3]; /*len is an array of dimensions, used by ifscreate*/ int size; /*number of bytes in image*/ int threshold; /*threshold is an int here*/ register int count; /*number of pixels in image*/ register unsigned char *ptri,*ptro; img1=ifspin (""); /*read in file; prompt user for name*/ len[0]=2; /*image to be created is two dimensional*/ len[1]=ifsdimen(img1,0); /*get columns of input*/ len[2]=ifsdimen(img1,1); /*get rows of input*/ img2=ifscreate("u8bit",len,IFS_CR_ALL,0); /*image is unsigned 8 bit*/ threshold=55; /*set some value to threshold*/ ptri = (unsigned char *) img1->ifsptr; /*get address of input data*/ ptro=(unsigned char *) img2->ifsptr; /*get address of output data*/ size= len[1] * len[2]; /*compute number of pixels*/ for(count=0;count<size;count++) { if(*ptri++ >= threshold) *ptro = 255; else *ptro=0; ptro++; } ifspot(img2,""); /*write image2 to disk, prompt user for filename */ } Figure 1.4: Example: A more sophisticated version of an IFS program to threshold an image using two dimensions, size of dimensions d and defined data type of unsigned char on both files. Pointers are used for speed. 18 CHAPTER 1. THE IFS SYSTEM #include <stdio.h> #include <ifs.h> #include <ifserr.h> /*optional*/ int main() { IFSHDR *img1,*img2; /*Declare pointers to headers*/ . . . img1=ifsmkh(128,128,"char"); /*make a 128*128 2-d image*/ /* Space for data & header are automatically allocated */ ....manipulateimage1 ..... img2 = ifs_exwin(img1,10,10,100,75); /*e1x2tract a sub-image*/ /*of the original image, img1, and call it img2*/ ifspot(img1,"img1.ifs"); /*writeimage1todisk */ } declared in the header file ifs.h. 1.3.2 Header Files The ifs user will find it convenient to include one or more of several header files, as listed below: ifs.h This is the main header file. Most programs which use ifs will need this file. It defines the ifs header, and the types of many of the ifs functions. ifstypes.h This file is useful if the user wishes to determine the data type of an image. It defines things like IFSA U8BIT, as in the example below: #include <ifsltypes.h> ... if (img->dtype == IFST_32FLT) ... which checks if the data type of image img is 32 bit float. ifserr.h See section ?? ifsmatrix.h Defines the values returned by the matrix operation functions. See section 2.2.2 1.3. ERROR HANDLING IN IFS 1.3.3 19 Coordinate systems and array storage in IFS IFS stores arrays in the same manner that C normally does. As with C, the indices for arrays start with zero rather than one. For example, if you create an image with 30 rows and 20 columns, then valid row indices for that function range from 0 to 29, and column indices may go from 0 to 19. One common source of confusion is the usage of the terms row and column to denote array subscripts when working with 2-dimensional arrays. It is quite typical for a users program to viewthe coordinate system in terms of an x and a y axis. The intent in IFS is that the column axis represents the horizontal axis, and the row axis is the vertical. Hence the width of the image is equivalent to the number of columns in the image, and height is the number of rows. It is common usage that the x axis is the horizontal axis, hence a column coordinate is synonymous with an x coordinate. If this is the coordinate system you normally use, beware of the temptation to write code of the form: int x,y; ... for ( x=0; x<width; x++) for( y=0;y<height; y++){ ifsipp(img, x, y, value); ... } The correct code in this case should be: int x,y; ... for(x=0;x<width;x++) for(y=0;y<height;y++){ ifsipp(img,y,x,value); ...} Unfortunately, people have a tendency to write coordinate pairs as (x, y) or (row,column), but these two are not synonymous if you interpret x, y, row,and column in the manner described above. A second problem occurs when displaying images on graphics output devices. There is no set standard as to where the origin of the coordinate system is among graphics displays. It is probably most common that the origin is in the upper left corner of the display, and moving in the positive direction along the column axis moves you to the right, and moving in the positive direction along the row axis moves you downwards. Some devices place the origin in the lower left corner of the screen, and moving in the positive row direction moves you towards the top of the display. The positive column direction still usually is to the right. This also corresponds to the way most people label axes when hand-drawing a graph. The net affect here is that images displayed in this coordinate system will be upside-down as compared to the first type of system. To further confound the issue, many programs which plot on printers reverse the meaning of the x and y axes, so that images plotted in this manner are rotated by 90 degrees in one direction or another. The point of these warnings about display coordinate systems is that IFS knows nothing about the nature of the users display mechanism. There is no specific “up”, “down”, “left”, or “right”. The user should not be too surprised if an image appears flipped or rotated from what was expected. 20 1.4 CHAPTER 1. THE IFS SYSTEM IFS FUNCTION LISTING This section lists all of the functions in the IFS library, in alphabetical order. The convention used to describe the syntax for the function is: return_value=function_name(arg1,arg2,....); type of return_value; type of arg1; type of arg2;.... where “type of” denotes a C variable type (such as “int”, “float”, “char* ”, or “IFSHDR*”, or other TYPEDEFs or STRUCTs). For instance, the sample description p=ifsalc(numbytes); char *p; int numbytes; indicates that the function ifsalc returns a pointer to a character, and that it takes one argument, which is an integer. 1.4. IFS FUNCTION LISTING 1.4.1 21 bilininterp //====================bilininterp================ Function to perform bilinear interpolation to find the best estimate of a pixel brightness using the four surrounding pixels. arguments: an ifs image, frame, row, column values Returns the estimate. POTENTIAL BUG: does not check if this pixel is next to the end of the image note, this version does not interpolate in the frame direction set frame = 0 to interpolate a 2D image This function is part of the iptools function library, so you need to load libiptools.a in addition to ifs.a float bilininterp(IFSIMG inimage, int frame,float row, float col); 1.4.2 ifsalc ifsalc – allocate storage (memory) cptr=ifsalc(NumBytes); char *cptr; int NumBytes; Ifalc is an IFS function used to allocate storage in main memory such as for storing arrays and image headers. The storage will be initialized to all zeroes. It is essentially just a call to the system function calloc; the only difference being that ifsalc performs a small amount of error checking. If the system cannot allocate the requested amount of storage, then ifsalc will return the value NULL, and the external variable ifserr will be set to the value IFSENOMEM. If the external variable IFSSLV is not set to the value IFSQUIET, then ifsalc will write an error message to stderr if it cant allocate the requested space. If IFSSLV is set to IFSFATAL, then ifsalc will also abort your program upon an error. 22 CHAPTER 1. THE IFS SYSTEM 1.4.3 ifscigp read from complex or real image ifscigp – get pixel value from a 2-d (possibly complex) image Usage: val = int ifscigp(ptri,row,col) IFSHDR *ptri; /*pointer to image header structure */ int row, col, val; /*coordinates - in pixels - of pixel to examine.*/ Ifscigp returns - as an int - the value of the pixel at a specified coordinate in a 2-d image. If image is complex format, returns the imaginary portion of the number. Known Bugs, Special notes: • This routine does not check to see if the specified coordinates actually are in bounds. • If the pixel value wont fit in an int for example, a large number in a float or complex image ,then results are undefined. Maybe you get garbage, maybe your program aborts on an overflow type of error. 1.4. IFS FUNCTION LISTING 1.4.4 23 ifscigp3d ifscigp3d – get pixel value from a 3d-dimage Usage: val = int ifscigp3d(ptri,frame,row,col); IFSHDR *ptri; /*pointer to image header structure*/ int frame, row, col; /*coordinates in pixels of pixel to examine.*/ Ifscigp3d returns as an integer the value of the pixel at a specified coordinate in a 3-d image. If image is complex format, returns the imaginary portion of the number assuming it can be converted to an int. Known Bugs, Special notes: • This routine does not check to see if the specified coordinates actually are in bounds. • If the pixel value wont fit in an int for example, a large number in a float or complex image then results are undefined. Maybe you get garbage, maybe your program aborts on an overflow type of error. 24 CHAPTER 1. THE IFS SYSTEM 1.4.5 ifscipp IFS library: libifs.a ifscipp: set pixel value in a 2-d image usage: status = ifscipp(ptri,x,y,val); IFSHDR *ptri; /*pointer to image headers tructure*/ int x,y; /*coordinates -- in pixels -- of pixel to examine.*/ int val; int status; /*return status*/ Returns: IFSSUCCESS or IFSFAILURE Ifscipp sets the value of the pixel at a specified coordinate in a 2-d image, where the input is an int. If image is complex format, stuffs the imaginary portion of the number, and DOES NOT set the real part to zero. Known Bugs, Special notes: • This routine does not check to see if the specified coordinates actually are in bounds. • If the pixel value wont fit in an int for example, a large number in a float or complex image then results are undefined. Maybe you get garbage, maybe your program aborts on an overflow type of error. 1.4. IFS FUNCTION LISTING 1.4.6 25 ifscipp3d ifscipp3d: set pixel in a 3-d image usage: status = ifscipp3d(ptri, frame, row, col, val); IFSHDR *ptri; int frame, row, col; /*coordinates in pixels of pixel to examine.*/ int status; /*return status*/ Returns: IFSSUCCESS or IFSFAILURE Ifscipp sets the value of the pixel at a specified coordinate in a 2-d image, where the input is a int. If image is complex format, stuffs the imaginary portion of the number, and DOES NOT set the real part to zero. Known bugs, special notes: • This routine does not check to see if the specified coordinates actually are in bounds. • If the value stored wont fit in the output image datatype, then results are undefined. Maybe you get garbage, maybe your program aborts on an overflow type of error. 26 CHAPTER 1. THE IFS SYSTEM 1.4.7 ifscfgp ifscfgp: get value of a pixel in a 2-d image. usage: val - double ifscfgp(ptri,row,col); IFSHDR *ptri; int row,col; /*coordinates (in pixels) of pixel to examine.*/ Ifscfgp returns (as a float) the value of the pixel at a specified coordinate in a 2-d image. If image is complex format, returns the imaginary portion of the number. Known bugs, special notes: • This routine does not check to see if the specified coordinates actually are in bounds. • If the pixel value wont fit in a double results are undefined. Maybe you get garbage, maybe your program aborts on an overflow type of error. There could be possible round off errors. 1.4. IFS FUNCTION LISTING 1.4.8 27 ifscfgp3d ifscfgp3d: get value of a pixel in a 3-d image usage: val = (double) ifscfgp3d(ptri,frame,row,col); IFSHDR *ptri; int frame, row, col; /*coordinates (in pixels) of pixel to examine.*/ ifscfgp3d returns (as a double) the value of the pixel at a specified coordinate in a 3-d image. If image is complex format, returns the imaginary portion of the number. Known bugs, special notes: • This routine does not check to see if the specified coordinates actually are in bounds. • If the pixel value wont fit in a double results are undefined. Maybe you get garbage, maybe your program aborts on an overflow type of error. There could be possible round off errors. 28 CHAPTER 1. THE IFS SYSTEM 1.4.9 ifscfpp ifscfpp: set value of a pixel in a 2-d image. usage: status = ifscfpp(ptri, x, y, val); IFSHDR *ptri; int x,y; /*coordinates (in pixels) of pixel to examine.*/ double val; /*the value to stuff.*/ int status; Returns: IFSSUCCESS or IFSFAILURE Ifscfpp sets the value of the pixel at a specified coordinate in a 2-d image, where the input is a float. If image is complex format, stuffs the imaginary portion of the number. Known Bugs, Special notes: • This routine does not check to see if the specified coordinates actually are in bounds. • If the value stored wont fit in the output image datatype, then results are undefined. Maybe you get garbage, maybe your program aborts on an overflow 1.4. IFS FUNCTION LISTING 1.4.10 29 ifscfpp3d ifscfpp3d: sets the value of a pixel in a 3-d image (This is a completely new version of ifsfpp which handles 3-d images.) usage: status = ifscfpp3d(ptri, frame, row, col, val); IFSHDR *ptri; int frame, row, col; /*coordinates (in pixels) of pixel to examine.*/ double val; /*the value to stuff.*/ int status; Returns: IFSSUCCESS or IFSFAILURE I fscfpp3d sets the value of the pixel at a specified coordinate in a 3-d image, where the input is a float. If image is complex format, stuffs the imaginary portion of the number. Known Bugs, Special notes: • This routine does not check to see if the specified coordinates actually are in bounds. • If the value stuffed wont fit in the output image datatype, then results are undefined. Maybe you get garbage, maybe your program aborts on an overflow type of error. 30 1.4.11 CHAPTER 1. THE IFS SYSTEM Ifsclose ifsclose: close an open file Usage: rc = ifsClose(File); FILE *File; int rc; Ifsclose, an ifs internal function seldom used by typical programmers, is identical to the standard I/O library function fclose, except that it will avoid closing File if File corresponds to stdin, stdout, or stderr. If File is NULL, ifsclose returns -1, else it just returns whatever value fclose would return. Ifsclose is supplied as a complement to ifsOpen since the latter function may return stdin or stdout in some circumstances, and the user typically does not want to close these files. 1.4. IFS FUNCTION LISTING 1.4.12 31 ifscreate ifscreate: create an IFS image Usage: img = ifscreate(type, len, flags, structsize); IFSHDR *img; char *type; int len[]; int flags; int structsize; Ifscreate is used to create a new IFS image or image header. Space for the header is automatically allocated, and a pointer to the header is returned. Various fields in the header structure will be set to default values. Space for the actual data may also be allocated, depending on the value of the flags variable. If space for the data array is allocated, it will be filled with zeros. If the image can not be created, ifscreate returns the value NULL, and the external variable ifserr will be set to some error code, as given in the #include file ifserr.h . The image as created will not have any tail structure associated with it. The arguments to ifscreate are: type The data format for individual pixels, such as byte or double. The valid data types are listed in a later section of this manual. If the data type is not recognized by IFS, then ifscreate will return NULL, and ifserr will be set to the code IFSE BAD DTYPE. len An n+1-length integer array the first element (len[0]) gives the number of dimensions for the image, the remaining elements give the length for each dimension of the image being created. This is in exactly the same format as the arrays returned by the function ifssiz. The lengths are given in terms of ascending rank for the image. Images are stored in standard C storage order: the column or x index changes most rapidly when scanning through memory, hence this dimension has rank 1. The row or y index has rank 2, the frame or z index has rank 3, and so on. I.e., the second element of the array (len[1]) gives the number of columns of the image, len[2] is the number of rows, etc. flags The various bits of this argument determine precisely what is and is not allocated when generating the image. If flags = IFS CR ALL or IFS CR DATA, then storage space for the image is allocated, as well as storage for the image header. In this case the field img->ifsptr points to the data storage. If flags = IFS CR HDR then only space for the image header is allocated. The field img->ifsptr will be set to NULL. The user must supply an array to store the image in, and set img->ifsptr to point to this array. Note: versions 4.0, 5.0, and 6 of ifscreate will ALWAYS allocate space for 32 CHAPTER 1. THE IFS SYSTEM the image header; the flag IFS CR HDR is not really examined, and is only intended for possible future expansion. All that is really checked is the IFS CR DATA bit. The flag IFS CR ALL is the combination of IFS CR DATA and IFS CR HDR and is probably the best flag to use if one wants data space allocated. structsize This argument is only needed if type is struct, in which case it gives the size of a single data element (structure) in bytes. If type is not struct this argument should be set to 0. Example of using ifscreate with a data type of struct: /* Create a 2-d image with 20 rows and 30 columns */ /* and a 1-d array of 10 structures #include <ifs.h> main() { IFSHDR * img, * strimg; int lengths[3]; IFSHDR * ifscreate(); typedef struct { int red; int green; int blue; } RGB; . . . /* create 2D byte array */ lengths[0] = 2; /* Image will be 2D */ lengths[1] = 30; /* Number of columns (width; x-dimension) */ lengths[2] = 20; /* Number of rows (height; y-dimension) */ img = ifscreate("ubyte", lengths, IFS_CR_ALL); if (img == NULL) { /* error processing code */ } . . . /* create 1D structure array */ lengths[0] = 1; lengths[1] = 10; strimg = ifscreate("struct",lengths,IFS_CR_ALL,sizeof(RGB)); . . . 1.4. IFS FUNCTION LISTING 33 Routines which are compatible with openCV In order to make use of the capabilities of openCV, and still retain the usefulness of IFS, several new functions are available to go between the two formats. openCV uses an image format called IPL, which is very similar to ifs in many ways. Most openCV functions do not support all the data formats that ipl supports, and ipl does not support some of the data types that ifs supports. In particular, the data types complex short, and complex are supported by ifs, but not by ipl. 1.4.13 ifs2ipl Converts an ifs image to an ipl-format image of the same data type. It returns a pointer to an ipl image IplImage *ifs2ipl(IFSIMG inputimage); Note that the old image is NOT deleted, but a new image is created using memory allocation. This is a potential memory leak unless the user is careful. If the old ifs image is no longer needed, it can be deleted using ifsfree(oldimage,IFS_FR_ALL); which will delete the image, and the header and the tail (if there is a tail). 1.4.14 ipl2ifs Converts an ipl image to an ifs-format image. It returns a pointer to an ifs image IFSIMG ipl2ifs(IplImage *inputimage); Note that the old image is NOT deleted, but a new image is created using memory allocation. This is a potential memory leak unless the user is careful. If the old image is no longer needed, it can be deleted using cvReleaseImage(&imagepointer); 1.4.15 ifsCVpin Reads an image from the disk. If it is an ifs image already, The ifs format will be retained in memory. If it is • Windows bitmaps - BMP, DIB, 34 CHAPTER 1. THE IFS SYSTEM • JPEG files - JPEG, JPG, JPE, • Portable Network Graphics - PNG, • Portable image format - PBM, PGM, PPM, • Sun rasters - SR, RAS, or • TIFF files - TIFF, TIF it will be converted to ifs and stored in ifs format in memory. IFSIMG ifsCVpin(char *filename); 1.4.16 ifsCVpot Writes an ifs image to disk. If the target file name has the extension “ifs”, it will be written retaining the original ifs format. If the target is any of the other image types, the image MUST be unsigned char, since that is the only format supported by the ipl write software. int ifsCVpot (IFSIMG imagepointer, char *filename); 1.4.17 ifsCVPopup This will pop up a window on the user’s screen with an image in it. ifsCVPopup is also usable as a general-purpose image viewing program. If you don’t want to use it as a subroutine (and have to deal with linking to openCV), you can get the same functionality using the program ifsview. IplImage *ifsCVPopup(IFSIMG imagepointer, int colorflag,int ignoreflag, int scaleflag ); The colorflag, if 1, means that a 3D, 3frame image should be interpreted as color rather than as a 3 frame image. example use, put up an image, wait for a user interaction, and close the screen window. The window is named “img1”. The ignore flag argument only affects contrast enhancement. If it is greater than zero, than any pixel of that brightness will not enter the calculation of contrast stretching. This is useful if you want to look at an image containing artificially added graphics with a special brightness, like 255. The scaleflag only affects 3D images. if scaleflag is one, each frame will be video scaled independenlty, if zero, the entire image will brightness scaled the same. IFSIMG iggle; IplImage *oggle; oggle = ifsCVPopup(iggle,0,-1);// put up the image, don’t ignore anything 1.4. IFS FUNCTION LISTING 35 cvReleaseImage(&oggle);// free the memory used by the temporary creation of an image to display cvWaitKey(0);//wait for the user to hit a key in the display window cvDestroyWindow("img1"); //close the window on the screen Note the ampersand in the call to cvReleaseImage. Yes, it is a pointer to a pointer. The pointer itself will be freed as well as the image. The image will stay on the screen until the user closes it, or the program exits. CAUTION: When the file is converted from ifs to ipl, the temporary ipl image is not deleted, since the use may want it. This is a potential memory leak if the user does not delete the temporary image after she is finished displaying it. As illustrated above, IPL images can be freed using cvReleaseImage( &imagepointer); Using a poped-up Image: Once you have called ifsCVPopup, you have a variety of options: • LOUPE As soon as the image pops up, and you move the mouse over it, another image will pop up which is a zoomed1 version of the original image, zoomed about where the mouse is. We will refer to this second image as the “loupe” image, as in a jewler’s loupe. As you move the mouse, the second image will move around also. • Stopping the tracking A right click on the original image will freeze the loupe image. A second right click will turn tracking back on. On the mac, a right click is accomplished by hitting the trackpad with two fingers simultaneously. • Additional zoom With the pointer on the original image, you can use right and left arrow keys to increase or decrease zooming (respectively). Note that you will not see the result of the zoom until you move the mouse again, which will refresh the loupe image. Note: some versions of Linux are not compatible with each other as far as the code used to represent an arrow key. For that reason, the following alternative keys may be used: – i uparrow – m downarrow – j leftarrow – k rightarrow – return key return to the calling program 1 Well, it is in the scale of the original image. If the original image is 4000 × 4000, the loupe image will seem significantly zoomed. However, it is is 512 × 512, no zoom will be apparent 36 CHAPTER 1. THE IFS SYSTEM • Image values – original image Clicking on the original image will return the brightness at the point of the click, or if color, will return the R,G,B values. • Image values – loupe image To look at points in great detail, first move the mouse to get to where you want to be in the original image. Then right click to turn off tracking. Move the pointer to the loupe image, and click on any point. The brightness or color of that point will be returned. • Exploring 3D images With the mouse on the original image (tracking can be on or off), the up and down arrow will display different frames of the 3D image. Remember that these values don’t show up in the loupe image until you move the mouse. • Enhancing contrast The lower-case c key will toggle contrast enhancement on or off. When on, the loupe image will be displayed with enhanced contrast. • Returning If you hit control C, you will be returned to the top (system) level. If you hit return, you will be returned to whatever program call the ifsCVPopup function. If that program was ifsview, it will, in turn, return you to the system. Should you simply wish to display an image and obtain information about it, use the program ifsview, which is just a wrapper around ifsCVPopup, and that way, you won’t need to mess with linking openCV, which can be a painful hassle. 1.4.18 IFSDISPLAY The module IFSDISPLAY in the directory iptools contains two important subroutines that allow you to display images. int CreateIFSDisplayWindow and WriteToIFSDisplayWindow. The first of these creates a window into which you can put an ifs image and display it. The second allow you to rewrite what is in that display window. Usage: int CreateIFSDisplayWindow(IFSIMG img,float zoom); Zoom is a scale factor, which can be used to make the displayed image larger. The integer returned is an index allowing the user to display more than one image at the same time. A maximum of ten images may be simultaneously displayed. int WriteToIFSDisplayWindow(int whichwindow,IFSIMG img,int frame,float zoom); This function allows the user to overwrite the contents of a particular screen. The dimensions of the new image must match those of the original. 1.4. IFS FUNCTION LISTING 1.4.19 37 Building ifsCV and IFSDisplay with openCV You can compile and load the openCV routines listed above using the same operations that you used to build ifs, except you need to tell the linker to load the CV subroutines. Here is a compile example that will do this in xcode. (add this item to the build instructions) OTHER_LDFLAGS = -lcxcore /Users/wes/src/ifs/MacX/ifslib/libifs.a -lcvaux -lhighgui -lcv If you are using a makefile, the compile command would be something like cc -o myprogram -lxcore Users/wes/src/ifs/MacX/ifslib/libifs.a -lcvaux -lhighgui -lcv This assumes, of course, that the openCV libraries were installed in the standard places (/usr/local/lib), and have the standard names (libhighgui.a rather than libhighgui.2.3.a) If you didn’t install them there, you will need to use the full path name, instead of the shortened path, and if the version number is included with the library file names, you will need to use it. It’s simpler to just use ifsview. 38 1.4.20 CHAPTER 1. THE IFS SYSTEM ifsdimen ifsdimen: get size of dimensionUsage: len = ifsdimen(image, n); int len; IFSHDR*image; int n; Ifsdimen returns the length (number of elements) of the nth dimension of image. It also may be used to get the total number of elements or bytes required by the data section of an image. The argument n is the rank of the dimension being queried, i.e., ifsdimen(img,0) is the number of columns, ifsdimen(img,1) is the number of rows, and so on. If n is specified as -1, ifsdimen returns the total number of elements in the image (the product of all the individual dimension lengths). If n is specified as -2, ifsdimen returns the total number of bytes occupied by the image data, i.e., the total number of elements times the size in bytes for a single element. If there is some error, ifsdimen returns zero and sets the external variable ifserr appropriately. Possible error conditions are IFSE BAD HEADER or IFSE NULL HEADER for invalid images, or IFSE WRONG NDIM if n is invalid (such as asking for the number of frames for a 2D image). 1.4. IFS FUNCTION LISTING 1.4.21 39 ifsexwin ifsexwin: Extract a window from an image Usage: new = ifsexwin(old, r1, c1, r2, c2); IFSHDR *new, *old; int r1, c1, r2, c2; Ifsexwin is used to create a new image which is a subimage of some old image The old image must be a two-dimensional image. The arguments r1,c1 and r2,c2 give the row and column positions of the corners of a box which defines the region to be extracted. These corners must be on opposite ends of a diagonal for the window It does not matter which corners are chosen for each point, as long as as they are on opposite ends of a box diagonal. The region extracted includes the area of the bounding box itself, ie, is inclusive of the rows r1, r2 and columns c1, c2. Ifsexwin returns a pointer to the newly created image, or NULL if some error occurred. In the latter case, the external variable ifserr will be set to indicate the nature of the error. Possibilities are: • IFSE BAD HDR If the pointer old does not point to a valid IFS image. • IFSE NO MEM If space couldnt be allocated for the new image. • IFSE WRONG NDIM If the original image is not two-dimensional. • IFSE BAD POS If either of the box coordinates is outside the image dimensions. The dimensionality of windowed image is consistent. That is, a 1-d/2-d slice ( a 3-d image one voxel thick in one or more dimensions) returns with a header consistent with the actual dimensionality.) 40 1.4.22 CHAPTER 1. THE IFS SYSTEM ifsexwin3d ifsexwin3d: Extract a window from an image usage: newimg = ifsexwin3d(oldimg,f1,r1,c1,f2,r2,c2) where f1,r1,c1 and f2,r2,c2 are the coordinates (frame,row,col) of one corner of the box and the opposite (diagonal) corner. It doesnt matter which corners are chosen.The box which is extracted includes the bordering surface (i.e, coordinates are f1,r1,c1 to f2,r2,c2 INCLUSIVE). Returns: This function returns NULL if an error occurs, and returns an error code thru the external variable ifserr. External variables: ifserr, IFSSLV Ifsexwin3d extracts a piece (window) out of a 3-d IFS image, to make a new IFS image. The data type of the new image is identical to that of the old one. The dimensionality of windowed image is consistent. That is, a 1-d/2-d slice ( a 3-d image one voxel thick in one or more dimensions) returns with a header consistent with the actual dimensionality. 1.4. IFS FUNCTION LISTING 1.4.23 41 ifsfgp ifsfgp: get pixel from a 2-D image Usage: value = ifsfgp(img, row, col); double value; int row,col; IFSHDR *img; Ifsfgp is used to get the value of some pixel in a 2-dimensional image. The value returned is of type double, regardless of what the data format of the image is. Otherwise, ifsfgp is identical to the function ifsigp, in all respects. See the documentation for ifsigp for more details. 42 CHAPTER 1. THE IFS SYSTEM 1.4.24 ifsfgp3d ifsfgp3d: gets the value of a pixel in a 3-d image (A generic multidimensional fgp can be attempted thru variable parameter passing, but that would make the code unportable.) usage: val = ifsfgp3d(ptri, frame, row, col); IFSHDR *ptri; /*pointer to image header structure*/ int frame, row, col; /*coordinates (in pixels) of pixel to examine.*/ double val; Ifsfgp3d returns (as a double) the value of the pixel at a specified coordinate in a 3-d image. If image is complex format, returns the real portion of the number. Known Bugs, Special notes: • This routine does not check to see if the specified coordinates actually are in bounds. • If the pixel value wont fit in a double then results are undefined. Maybe you get garbage, maybe your program aborts on an overflow type of error. Round off error can occur in conversions. e.g. int to double typecasting. 1.4. IFS FUNCTION LISTING 1.4.25 43 ifsfpp3d ifsfpp3d: set the value of a pixel in a 3-d image usage: status = ifsfpp3d(ptri, frame, row, col, val); \index{ifsfpp3d}\index{put pixel} IFSHDR *ptri; /*pointer to image header structure*/ int frame, row, col; /*coordinates (in pixels) of pixel to examine.*/ double val; /*the value to stuff*/ int status; Returns: IFSSUCCESS or IFSFAILURE Ifsfpp3d sets the value of the pixel at a specified coordinate in a 3-d image, where the input is a float. If image is “complex” format, stuffs the real portion of the number. Known Bugs, Special notes: • This routine does not check to see if the specified coordinates actually are in bounds. • If the value stuffed wont fit in the output image data type, then results are undefined. Maybe you get garbage, maybe your program aborts on an overflow type of error. 44 CHAPTER 1. THE IFS SYSTEM 1.4.26 ifsfpp ifsfpp: put pixel value into a 2-D image status = ifsfpp(img, row, col, value); int status; double value; int row, col; IFSHDR *img; Ifsfpp3d sets the value of the pixel at a specified coordinate in a 3-d image, where the input is a float. If image is complex format, stuffs the real portion of the number. Known Bugs, Special notes: • This routine does not check to see if the specified coordinates actually are in bounds. • If the value stuffed wont fit in the output image datatype, then results are undefined. Maybe you get garbage, maybe your program aborts on an overflow type of error. 1.4. IFS FUNCTION LISTING 1.4.27 45 ifsfree ifsfree: delete and deallocate an IFS image img = ifsfree(img,flags); IFSHDR *img; int flags; Ifsfree is used to get rid of an IFS image which is no longer in use. The space for the header and/or data is deallocated, and returned to the operating system for other use. Basically, ifsfree just consists of several calls to the system function cfree. The arguments to ifsfree are: • img A pointer to the image header structure. • flags A set of flags which indicates exactly what is to be deallocated. Possibilities for the flags are: – IFS FR DATA If this flag is set, then ifsfree will deallocate the space allocated for the storage of the actual image data (if there is any), and the header field img->ifsptr will be set to NULL to show that the header no longer has any data associated with it. If there is no data associated with the header, then this flag has no effect. This will not cause any errors. – IFS FR HDR If this flag is set, then ifsfree will deallocate the space allotted for the image header. The data space is left intact. This is usually only going to be used if the user supplied his own data area for the image (perhaps a static array or somesuch). – IFS FR ALL If this flag is specified, then ifsfree will free up everything image header and data. IFS FR ALL is just the combination of IFS FR DATA and IFS FR HDR. This is probably the normal flag to set when calling ifsfree . Ifsfree returns a pointer to the image header as it should be AFTER the desired things have been deallocated. If only the IFS – FR DATA flag was specified, then ifsfree returns the original pointer value img, with the field img->ifsptr now set to NULL to show that the data array has been deleted. If the header structure was freed, then ifsfree returns NULL to indicate that the pointer is no longer valid. Hence it is good practice to assign the return value from ifsfree back to the original pointer value img. It is not an error to simply say ifsfree(img,IFS FR ALL) rather than img = ifsfree(img,IFS FR ALL) to get rid of an image, but the latter usage is preferable in that it will make it more obvious to any subsequent routines called (erroneously) with the argument img. Ifsfree will also return the value NULL if an error occurred. In this case, the external variable ifserr will be set to the appropriate error code. Possible error conditions are: • IFSE NULL HDR This indicates that you passed the pointer NULL for the argument img. 46 CHAPTER 1. THE IFS SYSTEM • IFSE BAD HDR This indicates that the pointer img does not reference a valid IFS image structure. Note that the error IFSE NULL HDR is actually a subclass of the error IFSE BAD HDR, so if you test the value (ifserr & IFSE BAD HDR), you will automatically also pick up errors of the type • IFSE NULL HDR. BUGS (features): Trying to deallocate something which was not originally obtained using some standard system memory-allocation function (e.g, calloc, or the IFS routines ifsalc or ifscreate) will cause grave errors usually a program crash. This is a problem of the system allocate/deallocate routines and not ifsfree. 1.4. IFS FUNCTION LISTING 1.4.28 47 ifsGetFN ifsGetFN: read in a filename and expand it Usage: FileName = ifsGetFN(Prompt,Input); char *FileName; char *Prompt; FILE *Input; IfsGetFN will read in a string from the file Input (typically stdin), and expand it using the function ifsPrsFN. It returns a pointer to the name it read, or NULL if it failed. Space for the filename is dynamically allocated and may be freed (using cfree) when the user is through with it. If Input is a terminal, and Prompt is not NULL, then Prompt will be printed before the filename is read in. IfsGetFN normally delimits filenames with any control character or whitespace character and strips off any leading whitespace characters supplied in the name. Any character (including whitespace characters) may be put in a filename by prefixing it with a backslash n. This applies to leading whitespace characters as well as whitespace characters in the middle or end of the name. 48 1.4.29 CHAPTER 1. THE IFS SYSTEM ifsGetImg ifsGetImg: open a file and read an IFS image from it Usage: img = ifsGetImg(FileName, Prompt, ReadTail); IFSHDR *img; char *FileName; char *Prompt; int ReadTail; IfsGetImg reads an IFS image from some file FileName. If ReadTail is false (zero), then any tail information associated with the image will not be read in. It returns a pointer to the new image header, or NULL if it failed, in which case the external integer variables ifserr and column can be examined to determine the nature of the error. Space for the header, data, and tail is allocated dynamically, each may be freed (using cfree or ifsfree) when the user is through with it. If FileName is NULL, then the input image is read from stdin. If FileName is a null string (that is, FileName = ), then a filename will be read in from stdin using the routine ifsGetFN. In this case, if Prompt isnt NULL and stdin corresponds to a terminal, then the string Prompt will be printed on the terminal (actually, to stderr) before reading a name. If stdin is not attached to a terminal, such as when input is being piped in from another program, then the printing of the prompt string is suppressed. If a filename is read in from stdin, and it is (a single dash), then the image itself will be read from stdin. Filenames are expanded using ifsPrsFN, so they may contain such things as environment variable names and login id constructs. IfsGetImg works by opening the specified file and then calling ifsRdImg to do the actual work of getting the image. It then closes the file when its done (unless it read from stdin). Note that calling ifsGetImg with Filename = NULL is essentially the same as calling ifsRdImg directly. The complimentary routine to ifsGetImg is ifsPutImg. 1.4. IFS FUNCTION LISTING 1.4.30 49 ifsigp ifsigp: get pixel from a 2-D image Usage: value = ifsigp(img,row,col); int value; int row,col; IFSHDR *img; Ifsigp is used to get the value of some pixel in a 2-dimensional image. The value returned is of type int, regardless of what the data format of the image is. Ifsigp performs all necessary type conversions. If the value of the pixel in the image will not fit into an int data type, then the value that is returned will be meaningless. If the image data format is one of the complex forms, then ifsigp returns the real part of the specified data point. If some sort of error occurs, then ifsigp will return zero, and the external variable ifserr will be set to indicate the nature of the error. The arguments to ifsigp are: • img A pointer to the image header structure. This should refer to a 2-dimensional image. If the image has 3 or more dimensions, then ifsigp will access the first frame of the data (ie, all indices besides the first two will simply be treated as zero). • row,col The coordinates of the point to be examined. Note that row, col may also be regarded as a y, x pair. Beware that row corresponds to the y index, not the x index . The following error codes (defined in the #include file <ifserr.h >) may be returned by ifsigp : • IFSE BAD HEADER: The pointer img does not point to an actual IFS image. • IFSE BAD DTYPE: The image is of some data type that ifsigp does not recognize. Usually this indicates that your header has been damaged, and the field img ! ifsdt is mangled, or the image data type is struct. It could also occur if someone added a new data type to that understood by IFS, and forgot to modify ifsigp accordingly. BUGS (features): Ifsigp does not verify that the image passed to it corresponds to a 2-dimensional image. The indices row, col may (depends on severity level setting) not checked to verify that they lie inside the image dimensions. Ifsigp does not check to make sure that the data pointer img-/textgreaterifsptr is not NULL. Previous versions of IFS did not allow this data pointer to be NULL, so it was not previously necessary to check for this. Results when numeric overflow occur (as is possible when converting a floating point number into an integer) are undefined. 50 CHAPTER 1. THE IFS SYSTEM Any of the above issues could cause an abrupt and unpleasant termination of your program, generally with the infamous “bus error: core dumped” message under UNIX systems. Of course, such a crash would be indicative of some prior error in the users program not having been caught. 1.4. IFS FUNCTION LISTING 1.4.31 51 ifsipp ifsipp: put pixel value into a 2-D image status = ifsipp(img,row,col,value); int status; int value; int row,col; IFSHDR *img; Ifsipp is used to set the value of some pixel in a 2-dimensional image. The argument value is automatically converted from an integer into whatever data format the image is in. If the image is of type complex, then ifsipp sets the real part of the datum to value, and the imaginary portion to zero. Ifsipp returns the value IFS SUCCESS if it succeeded, otherwise it returns the value IFS FAILURE and sets the external variable ifserr to the appropriate error code. The arguments to ifsipp are: • img A pointer to the image header structure. This should refer to a 2-dimensional image. If the image has 3 or more dimensions, then ifsipp will access the first frame of the data (ie, all indices besides the first two will simply be treated as zero). row,col The coordinates of the point to be examined. Note that row, col may also be regarded as a y, x pair. Beware that row corresponds to the y index, not the x index. • value The actual data value to be put into the image. Note that if the datum represents some value that can not be represented in the data format of the image itself (such as trying to place the value 500 into a ubyte image), a meaningless value will end up being put into the image. The following error codes (defined in the #include file ifserr.h ) may be set by ifsipp (in the variable ifserr): • IFSE BAD HEADER: The pointer img does not point to an actual IFS image. • IFSE BAD DTYPE: The image is of some data type that ifsipp does not recognize. Usually this indicates that your header has been damaged, and the field img->ifsdt is mangled, or that the image data type is “struct”. It could also occur if someone added a new data type to that understood by IFS, and forgot to modify ifsipp accordingly. BUGS (features): • Ifsipp does not verify that the image passed to it corresponds to a 2-dimensional image. • The indices row, col are not checked to verify that they lie inside the image dimensions. 52 CHAPTER 1. THE IFS SYSTEM • Ifsipp does not check to make sure that the data pointer img-/textgreaterifsptr is not NULL. Previous versions of IFS did not allow this data pointer to be NULL, so it was not previously necessary to check for this. Any of the above issues could cause an abrupt and unpleasant termination of your program, generally with the infamous “bus error: core dumped” message under UNIX systems. These problems will not occur however, unless the users program contains some other sort of error. 1.4. IFS FUNCTION LISTING 1.4.32 53 ifsmkh ifsmkh: Create a two-dimensional IFS image THIS FUNCTION IS OBSOLETE STARTING WITH RELEASE 3.0 OF IFS THE FUNCTION ifscreate SHOULD BE USED INSTEAD 54 1.4.33 CHAPTER 1. THE IFS SYSTEM ifsopen ifsopen: open a file for reading or writing. Usage: File = ifsOpen(FileName,Mode,Prompt,NumRetries); FILE *File; char *FileName; char *Mode; char *Prompt; int NumRetries; Ifsopen opens up a file FileName for reading or writing, and returns a pointer to the open file descriptor (stream in Unix terminology). Ifsopen is used by ifspin, and the usual user does not (normally) need it. If the file can not be opened or some other error occurs, then ifsopen will return NULL. The argument Mode is the same as the mode argument to the standard i/o library function fopen, i.e. r or w for read or write access, (on Windows - based compilers, one sometimes must use “rb” and “wb”. If FileName is NULL, then ifsopen just returns stdin or stdout as is appropriate for the specified Mode. If FileName is a null string (FileName = “”), then ifsopen will read the name of the file to be opened from stdin. If stdin is attached to a terminal, then the string Prompt will be printed before getting the filename (unless Prompt is NULL). FileName is read using the function ifsGetFN, and expanded using ifsPrsFN, so it may contain the names of environment variables or constructs of the form login id to represent some users home directory name. If the name read in is a single dash, then ifsopen will return stdin or stdout, according to the argument Mode. If a filename is being read interactively (when FileName = “”, stdin is connected to a terminal, and Prompt is not NULL), then the user is allowed NumRetries mistakes before ifsopen will give up and return NULL. For instance, if ifsopen tries to open a non-existent file for reading, it will print a message to the user and ask for a new name. After several failures it will give up. This is to prevent such things as runaway shell scripts from sitting in a perpetual error loop. 1.4. IFS FUNCTION LISTING 1.4.34 55 ifspin ifspin: read in an image from disk img = ifspin(filename); IFSHDR *img; char *filename; Ifspin is used to read an IFS image from the specified file filename. All necessary storage space for the image and its data is automatically allocated. The “tail” information for the file is not read in. If the user wants the tail information read in, he should use the newer function ifsGetImg. If filename points to a null string, then ifspin will prompt the user to specify some filename. Any filename (whether or not read interactively) will be translated using the function ifsPrsFN, which will substitute for environment variables and names of users home directories specified in the C- shell shorthand form of user/filename. If filename is NULL, then input will be read from stdin. Also, if a user is prompted for a filename, if she specifies a single dash, the input will be read from stdin. The printing of a prompt string will be suppressed if stdin is not attached to a terminal. Ifspin returns a pointer to the new image, or NULL if some sort of error occurs. In the latter case, the external variable ifserr will be set to indicate the nature of the error. Possibilities are: • IFSE NO OPEN if the specified file cant be opened (usually meaning that it doesnt exist. • IFSE IO ERR if some sort of I/O error occurred (usually meaning the file does not contain a valid IFS image). The standard system I/O library variable errno may contain additional information about the nature of the error. Note that IFSE NO OPEN is a subclass of the IFSE IO ERR error, so one can check for both automatically by using a construct of the form “if (ifserr & IFSE IO ERR) action to take();” • FSE NO MEM if it isnt possible to allocate storage to put the image into. IFSE BAD NAME if some error occurred when translating the file name. BUGS/NOTES: Ifspin is an obsolete function. Under version 4 of IFS, this just remaps its arguments and calls ifsGetImg. Even though it is obsolete, it is easier to use than ifsGetImg, many programs use it all the time. 56 CHAPTER 1. THE IFS SYSTEM 1.4.35 ifspot ifspot: write an image to disk Usage: status = ifspot(img,filename); int status; IFSHDR *img; char *filename; Ifspot is used to write an IFS image to the specified file filename. If filename points to a null string, then ifspot will prompt the user to specify some filename, and read a filename from stdin. If filename is NULL, then ifspot will write the image to stdout. Also, if ifspot reads a filename from stdin, and the filename is -, then ifspot will write to stdout. If stdin is not connected to a terminal (e.g, input is being piped in from another program), then the printing of a prompt will be suppressed. The filename is translated using ifsPrsFN, so it may contain environment variables (beginning with a leading “$”) and the names of users home directories specified in the C-shell shorthand form of “user/ filename”. Ifspot returns the value IFS SUCCESS if it succeeded, or IFS FAILURE if some sort of error occurred. In the latter case, the external variable ifserr will be set to indicate the nature of the error. Possibilities are: • IFSE BAD HEADER if img doesnt point to a valid image. • IFSE NOT IMAGE if there is no data associated with the header, i.e., the field img->ifsptr is set to NULL. • IFSE NO OPEN if the specified file cant be opened (usually meaning that the name is invalid or that the user doesnt have write permission in the directory in which she is trying to put the image. • IFSE IO ERR if some sort of I/O error occurred. The standard system I/O library variable errno may contain additional information about the nature of the error. Note that IFSE NO OPEN is a subclass of the IFSE IO ERR error, so one can check for both automatically by using a construct of the form if (ifserr & IFSE IO ERR) action to take(); • IFSE BAD NAME if some error occurred while translating the name. BUGS/NOTES: • The function of ifspot has been superceded by the newer function ifsPutImg. Starting with version 4 of IFS, ifspot is just a dummy routine which remaps its arguments and calls if- sPutImg. Ifspot, however is convenient and supported • Ifspot does not write out any tail information associated with the image. 1.4. IFS FUNCTION LISTING 1.4.36 57 ifsPrsFN ifsPrsFN: expand a filename NewName = ifsPrsFN(Name,rc); char *NewName; char *Name; int *rc; This function is very useful for programmers writing systems like ifs. The ifs user is also welcome to use it. IfsPrsFN scans a string Name looking for references to environment variables or abbreviations for a users home directory of the form user such as is provided by the Unix C-shell. It returns a pointer to the expanded name, or NULL if it failed. The space for the expanded name is allocated using calloc, so it may be cfreeed when the user is through with it. A status code is returned through the pointer rc. This code will be 0 if it was successful, 1 if the expansion failed (such as by reference to an unset environment variable), or 2 if the routine had an internal error (such as a failure in a call to calloc). Environment variables are specified by prefixing the name with a dollar sign $. The name of the environment variable may contain any alphanumeric character, and is terminated by the first non-alphanumeric character found. The name may be enclosed in braces to isolate it from other characters, such as when the user desires the first character after the environment variable name to be an alphanumeric. Also, if the name is enclosed in braces, almost any printable character can be part of the variable name rather than just alphanumerics. Environment variable substitution is done on a strict left to right basis. A reference to some users home directory may be specified in the same manner as that allowed by the Unix C-shell. If the first character in a filename begins with a tilde character, then the word immediately following the tilde (where word is terminated by the first character which is not alphanumeric or underscore) is taken to be the name of some users login id; the name of the users home directory is substituted for the login id construct. Examples Assume the following environment variables and login ids: $i ifs $file output $J john /usr/users/myhome john /usr/users/alpha Then the following names expand as: NAME myfile$i myfile.$i /myfile john/$file.$i $J/$file.$i $ibase $ibase EXPANSION myfileifs myfile.ifs /usr/users/myhome/myfile /usr/users/alpha/output.ifs /usr/users/alpha/output.ifs no expansion unless environment variable ibase set ifsbase (braces isolate i from base) 58 1.4.37 CHAPTER 1. THE IFS SYSTEM ifsPutImg ifsPutImg: open a file and write an IFS image to it Usage: rc = ifsPutImg(Image, FileName, Prompt, WriteTail); int rc; IFSHDR *Image; char *FileName; char *Prompt; int WriteTail; IfsPutImg writes an IFS image to some file FileName. If WriteTail is false (zero), then any tail information associated with the image will not be written to the new file. IfsPutImg returns IFS SUCCESS if all went well, or IFS FAILURE if something went wrong, in which case the external integer variables ifserr and column can be examined to determine the nature of the error. If FileName is NULL, then the image is written to stdout. If FileName is a null string (that is, FileName = “”), then a filename will be read in from stdin using the routine ifsGetFN. In this case, if Prompt isnt NULL and stdin corresponds to a terminal, then the string Prompt will be printed on the terminal (actually, to stderr) before reading a name. If stdin is not attached to a terminal, such as when input is being piped in from another program, then the printing of the prompt string is suppressed. If a filename is read in from stdin, and it is a single dash, then the image itself will be written to stdout. Filenames are expanded using ifsPrsFN, so they may contain such things as environment variable names and login id constructs. IfsPutImg works by opening the specified file and then calling ifsWrImg to do the actual work of storing the image. It then closes the file when its done (unless it wrote to stdout). Note that calling ifsPutImg with Filename = NULL is essentially the same as calling ifsWrImg directly. The complimentary routine to ifsPutImg is ifsGetImg. 1.4. IFS FUNCTION LISTING 1.4.38 59 ifsRdHdr ifsRdHdr: read an IFS image header from an open file Usage: hdr = ifsRdHdr(file); IFSHDR *hdr; FILE *file; IfsRdHdr reads an image header from a previously opened file. It does not read in any data or tail information for the file. It returns a pointer to the new image header, or NULL if it failed, in which case the external integer variables ifserr and column can be examined to determine the nature of the error. Space for the header is allocated dynamically, and may be freed (using cfree) when the user through with it. After the header is read, the file pointer is positioned so that the next character read from the file will the first byte of the data stored in the file. Hence, ifsRdHdr does scan past any padding at the end of the header. There is no complimentary routine for writing headers to open files in this version of IFS. Writing a header to a file without writing any data would not make sense Accordingly, there is a function ifsWrImg, but not an ifsWrHdr. 60 1.4.39 CHAPTER 1. THE IFS SYSTEM ifsRdImg ifsRdImg: read an IFS image from an open file img = ifsRdImg(File,ReadTail); I FSHDR *img; FILE *File; int ReadTail; IfsRdImg reads an image from a previously opened file. If ReadTail is false (zero), then any tail information associated with the image will not be read in. It returns a pointer to the new image header, or NULL if it failed, in which case the external integer variables ifserr and column can be examined to determine the nature of the error. Space for the header, data, and tail is allocated dynamically, each may be freed (using cfree or ifsfree) when the user is through with it. IfsRdImg will always read the entirety of an image file (including tail informa- tion and any padding after it), discarding the tail if it is not wanted, and the file read position will be set so that the next read request will start with the first byte after the end of the image. If File corresponds to a disk file, this just means the read pointer will point to the end-of- file (unless some garbage has been concate- nated to to the of the image file). If File does not correspond to a disk file, such as when piping is being used and File is stdin, this means the file read pointer is positioned so that subsequent read requests (including read, scanf, getchar, another call to ifsRdImg, etc.) will properly read new data rather than reading padding characters left over from the end of the first image file. The complementary routine to ifsRdImg is ifsWrImg. 1.4. IFS FUNCTION LISTING 1.4.40 61 ifssiz ifssiz: Get size (lengths of all dimensions) of an IFS image Usage: dlength = ifssiz(image); int *dlength; IFSHDR *image; Ifssiz is used to determine the lengths of each dimension of an IFS image. It returns a pointer to an integer array, the various elements of which indicate the lengths of each dimension of the image, and also how many dimensions the array defined as. The array will have N+1 elements, where N is the number of dimensions of the image. The first element of the array (element number zero) gives the number of dimensions for the image. Subsequent elements of the array give the length each dimension, where the dimensions are in order of ascending rank; i.e., element one gives the number of pixels per line (number of columns) for the image, element two gives the number of lines (rows), element three is the number of frames, and so forth. The space for the array returned by ifssiz is automatically allocated using standard system calls (e.g., calloc), and as such may be released back to the system with the appropriate calls (free, cfree) when the user is through with the array. CAUTION – Potential Memory Leak: a popular programming error is to use ifssiz inside a loop without a free, and then wonder why the program is growing. For this reason, most programmers prefer ifsdimen to perform the same function. If there is some error in ifssiz, then the external variable ifserr will be set to some error code as defined in the file ifserr.h ( most likely IFSE BAD HEADER or IFSE NO MEM.) Example usage: int nrows, ncols, ndims, * dimlength; IFSHDR * image2d; ... make or read in image pointed to by image2d ... dimlength = ifssiz(image2d); ndims = dimlength[0]; if (ndims != 2) { /* Exit with nasty error messages ... */ } ncols = dimlength[1]; nrows = dimlength[2]; cfree( (char *) dimlength ); 62 1.4.41 CHAPTER 1. THE IFS SYSTEM ifsslice ifsslice: take a complete slice of a two-d or three-d image Usage: newimg = ifsslice(oldimg, string, value); where string is a char pointer pointing to a string. The following are legitimate strings “frame”, “f”, “row”, “r”, “column”, “col”, “c”. Passing any one of these strings will inform the function that the slice should be taken with that particular dimension (row,col or frame) held constant at the integer parameter value. i.e, if the string is frame and the value = 10, then a 2-d slice of the 3-d image at frame=10 is returned. Similarly for row and col slices. This is a generic slice program for 2-d and 3-d images. Using ifsslice on 1-d images will return with a copy of the image pointer and a warning. Similarly, a text string of frame on a 2-d image returns a copy of the image pointer and a warning. Returns: This function returns NULL if an error occurs, and returns an error code through the external variable ifserr. External variables: ifserr, IFSSLV Special routines used: ifscfree, ifsdie, ifswarn, ifsexwin, ifsexwin3d, ifssiz Ifsslice extracts a complete slice of a two-d or three-d image from the constituent image. The datatype of the sliced new image is exactly that of the old image. Note that the slice is complete in all dimensions except in one dimension. 1.4. IFS FUNCTION LISTING 1.4.42 63 ifsversion ifsversion: display version numbers Usage ifsversion(file); FILE *file; Ifsversion will write the version numbers of all the IFSfunctions it knows about to the specified file. Typically, file will be stdout or stderr. For each function ifsversion knows about, it will print the name of the function, its version number, and the date it was last modified. In rare cases there may be some additional information printed. 64 1.4.43 CHAPTER 1. THE IFS SYSTEM ifsWrImg ifsWrImg: write an IFS image to an open file rc = ifsWrImg(Image,File,WriteTail); int rc; IFSHDR *Image; FILE *File; int WriteTail; IfsWrImg writes an IFS image to some opened file File. If WriteTail is false (zero), then any tail information associated with the image will not be written to the new file. IfsWrImg returns IFS SUCCESS if all went well, or IFS FAILURE if something went wrong, in which case the external integer variables ifserr and column can be examined to determine the nature of the error. The complimentary routine to ifsWrImg is ifsRdImg. 1.5 IFS Error Codes This section describes the various error flags which may be set (in the global variable ifserr) when an error occurs in an IFS routine. These are defined in the #include file ifserr.h Each error is represented by a bit or set of bits in ifserr; hence it is best to test for specific bits rather than using a standard comparison (==). Note that all of the IFS error codes have names which are of the form IFSE xxxxxx, where xxxxxx is the actual name for the error. IFSE ERROR This is a combination of all possible errors. It is to be -1, i.e., all bits of the variable ifserr are set. Hence, all other error codes are subclasses of this code. IFS routines do not generally return this code. It generally indicates that either (a) an error was too complex for IFS to figure out, or (b) it was such a rare error that it was not considered important enough to define a separate code for the error. IFSE BAD HEADER or IFSE BAD HDR The pointer you passed to a function does not correspond to a valid header for an IFS image. Most IFS routines double-check image headers before doing anything, and will exit with IFSE BAD HEADER set if the header is not valid. IFSE NULL HEADER or IFSE NULL HDR The value NULL was passed to some IFS routine where you should have passed a pointer to an image header. The most likely cause of this is calling a routine to get or put a pixel in an image, when you havent yet created (or read in) the image. This error is a subclass of the error IFSE BAD HEADER. IFSE NO OPEN A file could not be opened for I/O activities. Usually this indicates that the file does not exist (on reads), or that the user does not have access permission for the specified file or directory. IFSE NO OPEN is a subclass of the error IFSE IO ERR. IFSE NOT IMAGE An error occurred when attempting to read an image header from a file. This usually means the file is too small to possibly be an IFS image. An image header alone occupies at least 1 block, where a block is normally to be 512 bytes. IFSE NOT IMAGE is 55 a subclass of the error IFSE IO ERR. IFSE BAD NAME A filename 1.6. IFS DATA TYPES 65 is considered invalid. This is normally set within routines such as ifsPrsFN when a name expansion fails (such as by reference to a file fred/ file.ifs when user fred doesnt exit). IFSE BAD NAME is a subclass of the error IFSE IO ERR. IFSE IO ERR Some sort of error occurred while performing I/O. The system global variable errno may contain additional information about the error. Common causes are (a) encountering an unexpected EOF, (b) inability to write output due to a full disk or users disk quotas exceeded, (c) inability to open a file. IFSE BAD DTYPE The datatype (short, int, float, etc.) is invalid or unrecognized by a particular routine. Usually this will only occur if you pass an invalid argument to an image creation routine (e.g., ifsmkh or ifscreate). It might also occur on routines which read or write data in images if the image header has been corrupted, or if the function is not capable of working on an image of a particular data type (for instance, it would make little sense to pass a complex format image to a histogram routine). IFSE BAD POS Some coordinate (array index) is illegal for the specified operation, such as trying to access a pixel in column 30 of an image which is only 20 columns wide. Note that the routines which read or write single pixels currently do NOT check to see if coordinates are within bounds. This is a flaw with IFS which will probably be fixed at a later time. IFSE WRONG NDIM The routine called does not work with images of the dimensionality of the image being used. An example would be trying to extract a window (2D subimage) from a 1-dimensional array. IFSE NOT SUPPORTED The specified function is not currently allowed. Usually this indicates a function which is not yet implemented, but which is intended to be implemented. In rare cases it may indicate that a function is obsolete (a separate error code may later be for this). 1.6 IFS Data Types This section describes the various data types that IFS version 5 understands. IFS has a certain basic set of names it recognizes for data types, and which it actually puts into image headers; in addition, it recognizes a number of synonyms for data types which it automatically remaps into the real data type. Some of these synonyms are machine dependent, for instance, a type of int may map to 16bit on one machine and 32bit on another machine. The final authority on data types and synonyms is the header file ifstypes.h which contains a table relating synonyms to the proper data type. Note that the data types ARE case sensitive. The possible data types are: • 8bit Signed byte. Synonyms are byte, char, i1, and I1. • u8bit Unsigned byte. Synonyms are ubyte, uchar, u1, and U1. • 16bit Signed 16 bit integer. Synonyms are short, i2, and I2. 66 CHAPTER 1. THE IFS SYSTEM • u16bit Unsigned 16 bit integer. Synonyms are ushort, u2, and U2. • 32bit Signed 32 bit integer. Synonyms are int, long, i4, and I4. • u32bit Unsigned 32 bit integer. Synonyms are uint, ulong, u4, and U4 (this data type is not supported by many compilers) • 32flt 32 bit floating point number. Synonyms are float, real, real*4, r4, and R4. • 64flt 64 bit floating point number. Synonyms are double, real*8, r8, and R8. • 32cmp Complex number consisting of two 32flt numbers (real and imaginary parts). Synonyms are complex, complex*4, c4, and C4. • 64cmp Complex number consisting of two 64flt numbers (real and imaginary parts). Synonyms are complex*8, c8, and C8. • struct Arbitrary user defined structure. Although IFS will read and write such images, it supplies no intrinsic routines to manipulate such images. 1.7 The structure of an IFS image An IFS image, whether it is in a disk file or in program memory, is stored as a set of three distinct pieces. When written to disk, each piece will begin on a block boundary, where the size of a block is given by the constant BLOCKSIZE, which is de ned the #include file ifs.h. Hence, there may be garbage bytes between one section and the next. The first piece is a header for the image. This header contains all sorts of information relevant to the processing of the image, along with information intended solely for the users benefit. Sample items in the header include the number of dimensions the image has, how long each dimension is, who the creator of the image is, and so on. The second entity in an image is the actual image data. The data is just stored in one long linear array, in exactly the same way that any C program stores arrays. The user can directly access this data if he/she so desires, although the usual way to get at the data is to use various IFS routines such as ifsigp and ifsipp. The third part of the image is the tail. The tail is just a block of data at the end of the file which IFS places no particular interpretation upon. It is up to the users programs to manipulate and understand the contents of the tail. An sample usage for the tail might be to store the text of a spoken message for which the data block was the digitized message. In most cases, it is not necessary for the user to directly alter any of the information in the image header as the IFS routines themselves will fill in the header with all the information needed to process the image, and all of the user information fields will be set to default values which are fine for most applications. However, at times it is desirable to alter fields in the header, which requires that the user know what the fields in the header are, and how 1.7. THE STRUCTURE OF AN IFS IMAGE 67 they are used. The header actually consists of several C structures. These structures are defined in the #include file ifs.h. The header actually consists of two types of structures. The first structure is the main image header structure, and contains most of the relevant information about the image, such as the number of dimensions, the format of the data, etc. This structure is the so called IFSHDR structure which one refers to when one declares an image pointer variable in a program (e.g: IFSHDR * img1, * img2;). Along with the IFSHDR structure exists a variable number of dimension sub- headers. There is one of these sub-headers for each dimension of the image, e.g., a 2-d image would have two sub- headers. The main piece of information in these subheaders is how long each dimension is. This structure goes by the name IFSDIM. The IFSDIM structures come directly after the the main header structure, both in the in-core images and the disk images. Hence, given a pointer to the main header structure, and the sizes of the headers, one can easily generate pointers to any of the dimension headers. The macro ifsgetdim (defined in ifs.h) may be used for this: IFSDIM * dim; IFSHDR * img; dim = ifsgetdim(img,2); will return a pointer to the third dimension sub-header (the first sub-header has number of zero). 1.7.1 The image header fields • char ifsmgc[4] This is the magic number field in the header. This field is used by the various routines as a way of verifying the validity of the header passed to them. If this field does not contain a special magic number (really, a character string rather than a number), then the IFS routines will assume that an invalid pointer was sent to them. The user should never alter this field. • int ifsbb This is the number of bytes in a physical block, when images are stored on disk. This value is set to the constant BLOCKSIZE, which is defined in ifs.h. For all systems to date, the blocksize is 512. When images are written to disk files, the header always starts at block 0, and the data always begins at the start of the next block after the header, i.e, there may be a small amount of wasted space between the end of the header and the start of the data, if the header does not completely ll the last block it occupies. • int ifssoh This is the block number of the first block of the header. This is always set to zero, at least for the time being. int ifssod This is the number of the block at which the data starts. The user can position directly to the start of the data array by using fseek to position an I/O pointer to the ifssod*ifsbb byte of the le. Of course, this only works for disk files. 68 CHAPTER 1. THE IFS SYSTEM • int ifssot This is the block number of the start of the tail for the le. If this field is negative, it indicates that there is no tail present; taking the absolute value of it would give the block number at which the tail would be if it existed. char * ifstail This is a pointer to the image tail, for an in-core image. If there is no tail, this is set to NULL. • int ifstsz This gives the size of the tail in bytes. If there is no tail, this is just zero. char ifsfc[8] This is the file class field. This is not used by UNIX installations of IFS, and is intended for systems running operating systems other than UNIX. • char ifsct[8] This is the file class type field. This also is not used and is for non-UNIX systems. • char ifsunm[32] This field is used to store the name of the owner of the file, as a null terminated character string. Note that since one byte must be reserved for the terminating null, that the effective username length is 31 characters. The user can put anything here she wants. When a user creates a new image, this field is filled in with his/her login id. • char ifscdt[32] This is a character string giving the time and date at which the image was created. This is automatically filled in when a user creates a new image, but the user can change it if she so desires. As with the name field, there can be up to 31 characters, plus the terminating null character. • char ifscpg[32] This is a character string giving the name of the program which created the image. When a user first creates an image, this field is normally lled with the name of the subroutine which actually created the image (e.g.: ifscreate). • char ifsver[8] This is a character string giving the version of the program which created the image. E.g., V 1.00 or Ver 1A or something in that vein. Certain routines such as ifscreate will stuff their version number in here. • char ifsrs1[40] This is just space reserved for future expansion. • char ifsdts[16] This is a character string giving the units of data for the pixels in the image, e.g., for an intensity image, this field might contain lumens. One must make sure not to use names for units which exceed 15 characters. The default for this field is just pixels. • float ifsdsc This field gives a scaling factor for the data in the image. This can be used along with the data offset (defined below) to convert values in the image array to some other scale. This might be used for example, if an image is taken and digitized using some measuring instrument, and later it is found that the instrument was off center (a data offset) or suffered from some sort of compression (scaling) problem. 1.7. THE STRUCTURE OF AN IFS IMAGE 69 The default for this field is 1.0. float ifsdo This field gives an offset which should be applied to the data in an image. I.e., the real value for a point in the image array should be calculated as realvalue = storedvalueif sdsc + if sdof Note that the routines which get values from the image array (such as ifsfgp) do NOT apply the scaling factors. The default for this field is 0.0. • char ifsdt[16] This is a character string which tells what number format the pixels in the image are stored in, such as u8bit or 32flt. • char comp This byte denotes the type of compression that is used. Right now, the only values are the integers one and zero, where one means use compression and zero means no compression. A program can use this by executing img-¿comp = 0: /* suppress compression */ before the execution of the ifs write file command. • int dtype This is a numeric encoding of the ifsdt field which has been added to the header structure with version four of IFS. This has been added to increase the speed at which certain routines work. • int ifsbpd This is the number of bytes which are needed to store a single pixel value, i.e., its the sizeof whatever data type is used for the image. Of course, this field can be deduced from the ifsdt field. • int ifsdims This gives the number of dimensions for the image. This refers to the number of indices needed to get at values in the image array, i.e, the pixels themselves dont count as a dimension. For instance, an image which has 10 rows and 20 columns is a 2-d image. Some other nomenclatures might refer to this as a 3-d image, where the third axis is the pixel measurement axis (range, brightness, or whatever). • char * ifsptr This is a pointer which gives the address of the of the first data element in the data array, for in-memory images. When fies are written to disk, the value NULL is written for this field. This is normally automatically set to the correct value when an image is read in, although the user can alter it to point to some other array. • int * ifsdln This is a pointer to an array which is used when calculating the address of any arbitrary point of the image. This array has ifsdims elements. The first element is just set to 1, the next element is the number of columns in the image, the next element is the number of rows times the number of columns, the fourth element is numcols * numrows * numframes, and so on. If the user has an N dimensional image, and the N-length vector V gives the coordinate of some point in the image (i.e., V = [ col, row, frame, cube... ]), then the dot-product of V and ifsdln will give you an offset which may be added to the starting address of the image to find the desired element, assuming the starting address is an appropriately declared pointer. If the starting address is declared as a char * (such as with the header field ifsptr) then the 70 CHAPTER 1. THE IFS SYSTEM offset must be scaled by the data size (ifsbpd). This may sound confusing, but really just represents the usual way that a set of indices are converted to absolute memory addresses for an array, whether by IFS or the C language itself. Note: the array itself is not written to disk when an image is stored. It is created when an image is read in (such as by ifsRdImg, ifspin, etc.) using information in the dimension sub-headers. • char * userptr This field is not used at present. • char ifsrs3[4] More reserved space. 1.7.2 The dimension sub-header fields For each dimension of the image, there will be a structure of the following form tacked on after the end of the main header structure. The user can obtain a pointer to one of these structures using the ifsgetdim macro, or can calculate their positions manually using the size of the main header and subheaders. The dimension sub-header fields are: • int ifslen The length (number of elements) of this dimension. • int ifsrnk The rank of this dimension. The rank of the dimension defines the order in which the dimensions are actually stored in memory. The dimension with the lowest rank is the dimension which changes most rapidly. Hence, the dimension with rank 1 is equivalent to columns, the rank 2 dimension is rows, the rank 3 dimension is frames, and so on. Note that images are stored in row-major order (as with all C arrays), which is contrary to the way some languages store arrays Fortran for instance stores in column- major form. Also note that the first dimension subheader after the main header is not necessarily the header for the lowest rank (columns) although the IFS routines do by convention store the dimension subheaders in order of ascending rank, this is not a requirement. • char ifsdir[8] The direction of this dimension. This is for images for which lines are not always stored in a top to bottom, left to right form. For instance, some camera systems scan from left to right on one line, then go from right to left on the next line, and store the data in the same form. This would be known as forward-backward alter storage. Other possibilities include forward (normal),backward, and backwardforward alter. Currently, IFS does NOT recognize this field, and treats all images as being stored in forward format. This is only for possible future expansion. The string fwd is placed in this field. • char ifsxun[8] This is a character string which gives the units for this dimension e.g., inches or mils. Make sure not to use names exceeding 7 characters. The default for this field is pixels. 1.7. THE STRUCTURE OF AN IFS IMAGE 71 • float ifsdsc The scaling factor to apply to this dimension, analogous to the scaling factor which exists in the main header. • float ifsdof The scaling offset for this dimension. • char rs4[32] Reserved space. 72 CHAPTER 1. THE IFS SYSTEM Chapter 2 The FLIP library FLIP Floating Point Image Processing Library This library assumes input in the form of a floating point ifs image. Outputs will be floating point images as well. The library is designed to optimize computation speed, while providing the programmer with easy-to-use tools. If all the inputs are not float, the function returns -1. If the input dimensions are not compatible, the function returns -2. Note that no error messages are printed, so the user must check the value returned. NOTE: to build programs which use many of the flip functions, you will need the math library. Thus, build using the -lm switch which invokes the math library. You can call many of the FLIP functions from the command line. See section 2.6. 2.1 Example Program Using the FLIP functions In this section, we suppose that the user must write a program which computes an expression using derivatives and transcendantal functions. That is, at every pixel, compute r = exp(− (fx )2 + (fy )2 ) 2τ 2 (2.1) where fx denotes the partial derivative with respect to x and τ is a constant. #include <ifs.h> #include <flip.h> int main(int argc, char *argv[]) { IFSIMG inimg,outimg,temp1,temp2; int len[3]; inimg=ifspin(argv[1]); // read the file specified by the first argument len = ifssiz(inimg) ; // get the sizes of the dimensions outimg=ifscreate("float",len,IFS_CR_ALL,0); 73 74 CHAPTER 2. THE FLIP LIBRARY temp1=ifscreate("float",len,IFS_CR_ALL,0); temp2=ifscreate("float",len,IFS_CR_ALL,0); temp3=ifscreate("float",len,IFS_CR_ALL,0); fldx(inimg,temp1); flmultv(temp1,temp1,temp1); // square the value fldy(inimg,temp2); flmultv(temp2,temp2,temp2); // square the value fladdv(temp1,temp2,temp3); // add them fldivs(temp3,temp3,-(2.0 * tau)); // divide flexp(temp3,outimg); ifspot(outimg,argv[2]); free(ifssiz); ifsfree(outimg,iFS_FR_ALL); // doesn’t need to be done since the program is exiting here // but this is good practice ifsfree(inimg,iFS_FR_ALL); ifsfree(temp1,iFS_FR_ALL); ifsfree(temp2,iFS_FR_ALL); ifsfree(temp3,iFS_FR_ALL); } // end of this program In the example above, note the use of in-place operations. with multv, divs, and exp. Calls with the same input and output and NOT allowed in derivative or other neighborhood-based operations. 2.2 Matrix Operations This section contains just a few commonly used matrix operations. These are developed using the Numerical Recipies in C (Cambridge University Press) conventions and utility functions. These functions are defined in flip.h. It is recommended that users set up their vectors to start at 1, not zero, to be consistent with math. For example, use v=vector(1,n); 2.2.1 dmatrix Create a matrix of doubles usage: double **r; r = dmatrix(1,6,1,8); Will create a matrix of doubles, rows indexed from 1 to 6, columns indexed from 1 to 8. 2.2. MATRIX OPERATIONS 2.2.2 matrix Create a matrix of floats usage: float **r; r = matrix(1,6,1,8); Will create a matrix of floats, rows indexed from 1 to 6, columns indexed from 1 to 8. 2.2.3 dvector Create a vector of n doubles usage: double *r; r = dvector(1,6); Will create a vector of 6 doubles, lower index is 1, higher index is 6. 2.2.4 vector Create a vector of n floats usage: float *r; r = vector(1,6); Will create a vector of 6 floats, lower index is 1, higher index is 6. 2.2.5 ivector Create a vector of n integers usage: int *r; r = ivector(1,6); Will create a vector of 6 integers, lower index is 1, higher index is 6. 75 76 2.2.6 CHAPTER 2. THE FLIP LIBRARY free ivector Free a previously created vector of integers. Usage: free_ivector(v,1,6) 2.2.7 free dvector Free a previously created vector of doubles. Usage: free_dvector(v,1,6) 2.2.8 free vector Free a previously created vector of floats. Usage: free_vector(v,1,6) 2.2.9 transpose Usage: void transpose(double **v,int rows,int cols,double **vtrans); The matrix v, which has rows rows and cols columns, will be transposed and stored in matrix vtrans. The user must ensure that the size of vtrans is correct. This program assumes the indexing starts with 1, as is the common convention. 2.2.10 ifsmatmult Multiply two matrices Usage: int ifsmatmult(double **, double **, double **, int,int,int,int); ifsmatmult(x, y, z, xrows,xcols,yrows,ycols); For the two matrices to be compatible, xcols must equal yrows. The program will return an error if this is not true. The resultant matrix, z, must be of size xrows x ycols. The matrices are assumed to have been created with the matrix function defined above, with a lower index of 1. 2.3. ARITHMETIC OPERATIONS ON IMAGES 2.2.11 77 ifsinverse double ifsinverse(double **,double **, int); Computes the inverse of a matrix, using numerical recipies conventions Usage: det = ifsinverse(double **x, double **xinv, int n); x is an nxn matrix. After the call, xinv will contain the inverse of x. The function will return the determinant. 2.2.12 jacobi Computes eigenvalues and eigenvectors. call: float **a,**v; float *d; int n; a = matrix(1,n,1,n); // input float matrix a must be symmetric v = matrix(1,n,1,n); // output matrix v will contain eigenvectors as columns d = vector(1,d); // output vector d will contain eigenvalues ... jacobi(a,n,d,v,&nrot); // computes everything // nrot will contain the number of rotations required 2.3 2.3.1 Arithmetic Operations on Images flabsolute Take absolute value of an image int flabsolute(inimage,outimage} 2.3.2 fladds Add a scalar to an image int fladds(IFSIMG img1, IFSIMG img2, float scalar) 78 2.3.3 CHAPTER 2. THE FLIP LIBRARY fladdv Add two images int fladdv(IFSIMG img1, IFSIMG img2, IFSIMG img3) The first input image is img1, the second input image is img2, the output is img3. Corresponding pixels of img1 and img2 are added and the result stored in img3. 2.3.4 flclip Limit permitted brightness in images int flclip(IFSIMG img1, IFSIMG img2,float scalar) The first image, img1 is clipped so that its maximum value is scalar. 2.3.5 flcp Copy an image flcp(IFSIMG inimg, IFSIMG outimg) The image inimg will be copied to the image outimg 2.3.6 fldivs Divide an image by a scalar. fldivs(IFSIMG img1 IFSIMG,img2,float scalar) Each pixel of img1 will be divided by the scalar, and the result stored in the corresponding pixel if img. 2.3.7 fldivv Divide two images int fldivv(IFSIMG img1, IFSIMG img2, IFSIMG img3); Each pixel of img1 is divided by the corresponding pixel of img2, and the result stored in img3. Note, no check for divide by zero is performed, so the special floating point value INFINITY can occur. 2.3. ARITHMETIC OPERATIONS ON IMAGES 2.3.8 79 flexp Exponentiate int flexp(IFSIMG img1, IFSIMG img2) Each pixel of img2 is independently exponentiated. Result stored in img2. 2.3.9 flln Compute logs of pixels independently int flln(IFSIMG img1, IFSIMG img2) Computes out[i] = log(in[i]); 2.3.10 flmults Scalar multiply int flmults(IFSIMG img1, IFSIMG img2,float scalar) Multiply each pixel of img1 by scalar and store the result in the corresponding pixel of img2. 2.3.11 flmultv Vector multiply int flmultv(IFSIMG img1, IFSIMG img2, IFSIMG img3) Each pixel of img1 is multiplied by the corresponding pixel of img2, the result stored in img3. This is equivalent to the MATLAB .* operation. 2.3.12 flneg Negate image pixels int flneg(IFSIMG img1, IFSIMG img2) Each pixel of img1 is multiplied by -1 and the result stored in img2. 2.3.13 flnorm int flnorm(IFSIMG img1,float *norm) Returns the 2-norm of the image img1. The second argument is a POINTER to a float, and the norm (square root of sum of squares of pixels) will be returned. 80 2.3.14 CHAPTER 2. THE FLIP LIBRARY flrec Reciprocal of an image int flrec(IFSIMG img1, IFSIMG img2) Each pixel of the input image, img1, is divided into one, and the result stored in the corresponding pixel of img2. This function tests for divide by zero, reports an error, and exits early. 2.3.15 flsq Square pixel values int flsq(IFSIMG img1, IFSIMG img2) For every pixel, out[i] = in[i] * in[i] ; 2.3.16 flsqrt Square root of pixels int flsqrt (IFSIMG img1, IFSIMG img2) The square root of each pixel it taken. If any pixels are negative, the function will return FAILURE (0), else it will return SUCCESS (non-zero). 2.3.17 flsubs Scalar subtract. Subtract a scalar from every element of an image int flsubs(IFSIMG img1, IFSIMG img2,float scalar) 2.3.18 flsubv int flsubv(IFSIMG img1, IFSIMG img2, IFSIMG img3); Vector subtract Each pixel in the second image, img2 is subtracted from the corresponding pixel in img1, and the result stored in img3. Valid for any number of dimensions. 2.3.19 flthresh Threshold int flthresh(IFSIMG img1, IFSIMG img2,float scalar,float bkgnd) Each pixel of input image img1 is tested against scalar. If pixel > scalar, the pixel is unchanged, otherwise, the corresponding pixel in the output image is set to the value bkgnd. Valid for any number of dimensions. 2.4. IMAGE MANIPULATION FUNCTIONS 2.3.20 81 flthresh2 Threshold int flthresh2(IFSIMG img1, IFSIMG img2,float scalar,float bkgnd,float fgnd) Each pixel of input image img1 is tested against scalar. If pixel > scalar, the pixel is set to fgnd, otherwise, the corresponding pixel in the output image is set to the value bkgnd. Valid for any number of dimensions. 2.4 2.4.1 Image Manipulation Functions flone border int flone_border(IFSIMG img1, IFSIMG img2) Sets the left-most and right-most columns of the image to one. Then set the top row and bottom row to one. Result copied into img2. 2.4.2 flpad Image pad int flpad(IFSIMG img1, IFSIMG img2) Input image img1 is padded by taking the leftmost pixel on each row and replacing it by the next- to-leftmost. Same thing on right side, top, and bottom. If 3D, appropriate things are done to the first and last frame. 2.4.3 flplanar Image pad using linear interpolation. int flplanar(IFSIMG img1, IFSIMG img2) The leftmost pixel on each line is replaced by what it would be if the first three pixels were lin- early increasing in brightness – the zeroth pixel is the linear interpolation of the first and second. Similar on right side, top, and bottom. Only implemented for 2D images. 2.4.4 flrotate Rotate an ifs image about its center. int flrotate(IFSIMG input,IFSIMG output,float angle); 82 CHAPTER 2. THE FLIP LIBRARY Unlike most other flip functions, flrotate will accept input of any data type. It runs faster with unsigned byte and float. It will also rotate 3D IFS images, but all frames will be rotated by the same amount. (Thus a color image can be rotated). Returns: zero if it runs successfully. Returns: -2 if the input and output images have different dimensions. 2.4.5 flshx Shift image in the x direction int flshx(IFSIMG img1,int dx, IFSIMG img2) input image img1 is shifted by dx pixels in the x direction and the result stored in img2. Operation is valid for 3D images. 2.4.6 flshxy Shift image int flshxy( IFSIMG int img1,dx,int dy, IFSIMG img2) Input image img1 is shifted dx pixels in x and dy pixels in y. Operation is valid for 3D images. 2.4.7 flshy Shift image int flshy(IFSIMG img1,int dy, IFSIMG img2) Shifts image in y direction. Operation is valid for 3D images. 2.4.8 flzero border Set border pixels to zero. int flzero_border(IFSIMG img1, IFSIMG img2) Valid for two dimensional images. 2.5. 2.5 DERIVATIVE OPERATORS 83 Derivative Operators In computing image derivatives, (with the exception of flDoG), DO NOT CALL THESE FUNCTIONS IN-PLACE. That is, never do something like fldx(img,img); // bad bad bad Performing an image derivative in-place will radically distort the output. Always use different destination and source image. Because flDoG actually creates a temporary image, it is OK to use it in-place. Except for DoG (derivative of a Gaussian), all the derivative operators listed below support 1-D (signals) 2-D (images) and 3-D (volumes) data sets. In all cases, x denotes the column and y the row. flDoG only supports two-dimensional images, however, if the problem is 2D, it probably does a better job in the presence of noise. 2.5.1 flDoG Computes the derivative of an isotropic, zero mean Gaussian, and applies it to an image. This is by far the best derivative program in the flip library. int flDoG(IFSIMG a, IFSIMG b, float sigma, int order, int direction); The ifs image a will be differentiated and its derivative stored as image b. By choosing combinations of the arguments, order and direction, one can compute the blurs and derivatives in the table below. Sigma is the standard deviation of the Gaussian.. The equation of the Gaussian is 2 1 x + y2 exp − 2πσ 2σ 2 The kernel used will be computed by the program by extrapolating out to greater than 3 sigma. This could result in a large kernel and long run times. You may get a warning message to this effect, but the program will run anyway. Because the kernels may get large, the program checks that the image is at least large enough to hold the image. If not, the program will exit with an error message. The message “Something wrong with arguments to function ifsDoG” indicates that an impossible combination of order and direction were specified. 84 CHAPTER 2. THE FLIP LIBRARY Order 0 1 2 3 0 1 2 3 0 1 2 3 2.5.2 Direction 0 0 0 0 1 1 1 1 2 2 2 2 Function Convolution with zeroth order derivative of a Gaussian, which is a blur First deriv wrt x (column direction) Second deriv wrt x (column direction) Third deriv wrt x (column direction) Blur, same as 0 0 First derivative wrt y (row direction) Second derivative wrt y (row direction) Third derivative wrt y (row direction) Blur, same as 0 0 Undefined. Will produce an error message Cross second deriv (Partial**2 f )/ (Partial x Partial y) Undefined. Will produce an error message flGabor Performs a Gabor filtering on an image. The Gabor filter, applied to a point xy in an image, computes 02 x + γ 2 y 02 x0 g(x, y; σ, θ, λ, γ, ψ) = exp − cos 2π + ψ 2σ 2 λ Here, the Gabor is implemented by using the ifs function flGabor The normal to the line has the angle theta, not the line itself where x0 = x cos θ + y sin θ (2.2) 0 (2.3) y = −x sin θ + y cos θ The parameters involved in the construction of a 2D Gabor filter are: σ , The standard deviation of the Gaussian function θ , The orientation of the normal to the parallel stripes of the Gabor function λ , The wavelength of the sinusoidal function γ , The aspect ratio of the exponential. ψ , The phase of the sine wave. Note that flGabor gives the user the options of selecting ψ, the phase of the cosine, which allows the user to determine whether to be sensitive to lines, rising edges, or falling edges. A phase of zero means use a cosine centered at zero, which is best for finding lines (two opposite edges), One may detect very narrow lines by using a ψ of zero and a narrow 2.5. DERIVATIVE OPERATORS 85 wavelength. A ψ of −π/2 changes the cosine to a sine which makes it sensitive to finding positive edges. A ψ of π/2 changes the cosine to a downward sine which makes it sensitive to finding falling edges. USAGE: int flGabor(IFSIMG input,IFSIMG output,float sigma,float theta, float lambda, float gamma,float psi); The input and output images must both be float; They must be the same size. sigma is the standard deviation of the blurring Gaussian of the Gabor filter. theta is the orientation of the Gabor filter. It is an angle, measured in radians, relative to the x axis. If theta =0 (for example), the filter will prefer vertical edges. Lambda is the wavelength of the sinusoid. Good example settings for finding lines (not edges) are lambda = 4, psi = 0; 2.5.3 fldx Estimate partial deriviative in the x direction. Do not use in-place. int fldx(img1,img2); IFSIMG img1,img2; Compute an approximation of the first deriviative with respect to x by the difference between pixels in an image images. For each pixel, outrow[j][i] = (inrow[j][i+1] - inrow[j][i1])*.5 If all the inputs are not float, the function returns -1. If the input dimensions are not compatible, the function returns -2. Note that no error messages are printed, so the user must check the value returned. 2.5.4 fldx back Backward difference. Do not use in-place. The forward and backward differences both estimate the first partial derivative with respect to x, but do it with higher resolution (and higher noise sensitivity) than fldx. They are useful in iterative algorithms where you do one iteration using the forward difference, and the next using the backward. int fldx_back(IFSIMG img1, IFSIMG img2) Compute the backward difference between pixels in an image images. For each pixel, outrow[j][i] = inrow[j][i+1] - inrow[j][i]; is computed. Do not use in-place. If all the inputs are not float, the function returns -1. If the input dimensions are not compatible, the function returns -2. Note that no error messages are printed, so the user must check the value returned. 86 2.5.5 CHAPTER 2. THE FLIP LIBRARY fldx forw Forward difference. Do not use in-place. int fldx_forw(IFSIMG img1, IFSIMG img2) Compute the forward difference between pixels in an image images. For each pixel, outrow[j][i] = inrow[j][i] - inrow[j][i-1]; Do not use in-place. 2.5.6 fldxx Second partial derivative with respect to x. int fldxx(IFSIMG img1, IFSIMG img2) Uses a 3x1 kernel. Do not use in-place. If all the inputs are not float, the function returns -1. If the input dimensions are not compatible, the function returns -2. Note that no error messages are printed, so the user must check the value returned. 2.5.7 fldxy Second partial derivative with respect to x and y. int fldxy(IFSIMG img1, IFSIMG img2) Uses a 3x3 neighborhood. Do not use in-place. If all the inputs are not float, the function returns -1. If the input dimensions are not compatible, the function returns -2. Note that no error messages are printed, so the user must check the value returned. 2.5.8 fldxz Second partial wrt x,z. Do not use in-place. int fldxz(IFSIMG img1, IFSIMG img2) 2.5.9 fldy First partial derivative with respect to y. Do not use in-place. int fldy(IFSIMG img1, IFSIMG img2) If all the inputs are not float, the function returns -1. If the input dimensions are not compatible, the function returns -2. Note that no error messages are printed, so the user must check the value returned 2.5. DERIVATIVE OPERATORS 2.5.10 87 fldy back Backward difference The forward and backward differences both estimate the first partial derivative with respect to y, but do it with higher resolution (and higher noise sensitivity) than fldy. They are useful in iterative algorithms where you do one iteration using the forward difference, and the next using the backward. Do not use in-place. int fldy_back(IFSIMG img1, IFSIMG img2) Compute the backward difference between pixels in an image images. For each pixel, outrow[j][i] = (inrow[j+1][i] - inrow[j-1][i])*.5; is computed. Do not use in-place. If all the inputs are not float, the function returns -1. If the input dimensions are not compatible, the function returns -2. Note that no error messages are printed, so the user must check the value returned. 2.5.11 fldy forw Forward difference int fldy_forw(img1,img2) IFSIMG img1,img2; Compute the forward difference between pixels in an image images. For each pixel, outrow[j][i] = inrow[j][i] - inrow[j-1][i]; Do not use in-place. If all the inputs are not float, the function returns -1. If the input dimensions are not compatible, the function returns -2. Note that no error messages are printed, so the user must check the value returned. 2.5.12 fldyy Second partial derivative with respect to y. Do not use in-place. If all the inputs are not float, the function returns -1. If the input dimensions are not compatible, the function returns -2. Note that no error messages are printed, so the user must check the value returned. int fldyy(img1,img2); IFSIMG img1,img2; Uses a 3x1 kernel. 88 2.5.13 CHAPTER 2. THE FLIP LIBRARY fldyz Second partial derivative with respect to y and z. Do not use in-place. int fldyz(img1,img2) IFSIMG img1,img2; Uses a 3x3 kernel. Obviously, only meaningful for 3D data. If all the inputs are not float, the function returns -1. If the input dimensions are not compatible, the function returns -2. Note that no error messages are printed, so the user must check the value returned, 2.5.14 fldz First partial derivative with respect to z. Obviously, only meaningful for 3D data. Do not use in-place. int fldz(img1,img2) IFSIMG img1,img2; If all the inputs are not float, the function returns -1. If the input dimensions are not compatible, the function returns -2. Note that no error messages are printed, so the user must check the value returned. 2.5.15 fldzz Second partial derivative with respect to z. Only meaningful for 3D data. Do not use in-place. If all the inputs are not float, the function returns -1. If the input dimensions are not compatible, the function returns -2. Note that no error messages are printed, so the user must check the value returned. int fldzz(img1,img2) IFSIMG img1,img2; Uses a 3x1 kernel. 2.6 Running the FLIP functions from the command line Sometimes, users want to run a FLIP function on an image without bothering to write a program to call that function. Some programs have been written which allows the user to do just that. These are listed below 2.6. RUNNING THE FLIP FUNCTIONS FROM THE COMMAND LINE 2.6.1 89 flpg1: single input FLIP functions This program allows to multiple flip library functions from the command line. Switches: -i inputfilename -o outputfilename -f functionname clip - clips the image divs - divides by a scalar exp - takes the exponential of each pixel of the image log - takes the natural log of each pixel of the image independently mults - takes the exponential of each pixel of the image neg - Negate image pixels rec - Reciprocal of an image sq - Square pixel values curv - Curvature at every point sqrt - Square root of pixels subs - Scalar subtract. Subtract a scalar from every element of an image -s optional, function-specific parameter Example: flpg1 -i footprint.ifs -o footdarker.ifs -f subs -s 2.0 2.6.2 der1: take a derivative of an image This program allows to multiple flip library functions from the command line. Switches: -i inputfilename -o outputfilename -f functionname fldx - Estimate partial derivative in the x direction fldx_back - Backward difference fldx_forw - Forward difference fldxx - Second partial derivative with respect to x fldxy - Second partial derivative with respect to x and y fldxz - Second partial derivative with respect to x and z fldy - Estimate partial derivative in the x direction fldy_back - Backward difference fldy_forw - Forward difference fldyy - Second partial derivative with respect to y fldyz - Second partial derivative with respect to y and z 90 CHAPTER 2. THE FLIP LIBRARY fldz fldzz 2.6.3 - Estimate partial derivative in the z direction - Second partial derivative with respect to z ifsDoG:Apply a derivative of Gaussian kernel to an ifs image usage: ifsDoG [switches] switchs are -i infilenname, where infilename is an ifs image default: the null string -o outfilenname, where outfilename is an ifs image default: the null string -s sigma, std. dev of the filtering Gaussian default: sqrt of 3.0 -O order of the derivative zero is blur with the Gaussian, one is first deriv, etc, up to 3rd deriv -d direction. This flag is the letter c for col, r for row, b for both default: col b option only valid for second deriv example: ifsDoG -i myfile.ifs -o outfile.ifs -O 0 -d r 2.7 2.7.1 Image Manipulation ifsadd ifsadd - add two ifs images, point by point out(i, j) = in1(i, j) + in2(i, j) Usage: int ifsadd (in1, in2, out) IFSHDR *in1,*in2,*out; RETURNS 0 if successful, -1 if all three arguments do not have same dimensions -2 if data type unsupported (complex double) -3 if one input has type complex and output is real -4 if both inputs are real and output is complex CAUTION: if output is type char, values greater than 255 will be clipped to lie between 0 and 255. NOTES: if one image is real and the other complex, the output must be complex and the real parts of the images will be added. 2.7.2 ifsany2any Convert any ifs image to any data type. Usage: 2.7. IMAGE MANIPULATION status=ifsany2any(inputimage,outputimage); ** FUNCTION: convert data type of images, point by point ** CALL: ifsany2any (in1,out) ** where each argument is an ifs image ** RETURNS: 0 if successful, ** -1 if both arguments do not have the same dimensions ** -2 if input data type unsupported (complex) ** -3 if one input has type complex and output is real ** -4 if input is real and output is complex ** -5 if a zero occurs in the input 91 92 CHAPTER 2. THE FLIP LIBRARY Chapter 3 Image Processing Subroutines In this chapter, a number of subroutines are presented which are of general applicability. Most have been written using pointers and sophisticated code in order to optimize speed. 3.1 Geometric functions The following subroutines are available in the library /usr/local/libiptools.a 3.1.1 chainHull 2D Finds the convex hull of a set of 2D points. The set is an array of structures of type Point. Where Point is defined by typedef struct float x, float y Point; Usage: count = chainHull_2d(Point *S, int n, Point *H); count is an integer, the number of points in the convex hull (cannot be more than n) n in the number of points in the input data se// S is the array of input points// H will be filled in by the subroutine, the points in the convex hull This software was copied from freeware: http://softsurfer.com/Archive/algorithm 0109/algorithm 0109.htm#chainHull 2D%28%29 Note: the x,y pairs must be sorted on x, smallest first. If two pairs have the same x coordinate, then those need to be sorted by y. You can use the Unix soft program if that is convenient, or any of a large selection of sort subroutines. 3.1.2 compute curvature Given a set of x,y pairs, compute the curvature at every point. Usage: compute_curvature(struct point_xy parray[],int grid_spacing, int num_elems, double curvature[]); 93 94 CHAPTER 3. IMAGE PROCESSING SUBROUTINES The structure points is simply an x,y, pair defined as follows: struct point_xy { int x, int y }; The user should declare an array of these structures. num elems is the number of elements in this array. grid spacing is the pixel width; almost always set to 1. This would be changed only if the pixels are not square. curvature[] is an array of curvatures found by this program. 3.1.3 InsideTriangle Determine if a point is inside a triangle Usage: int InsideTriangle(int row, int col, double **X); X is an array of doubles created with X=dmatrix(1, 2, 1,3); The three columns of X refer to the coordinates of the 3 vertices of the triangle. The 1,1 entry in the matrix is the row coordinate of the first vertex, The 1,1 entry in the matrix is the column coordinate of the first vertex 3.1.4 InterpolateTriangle Given three points in an input image, and a corresponding 3 points in an output image, the second triangle will be deformed and filled in to match the first. Usage: status = InterpolateTriangle (inimg, outimg, X,U,IG); IFSIMG inimg, outimg; double **X, **G; int IG X and U are matrices created using the function dmatrix. IG is a switch which, if nonzero, will result in sub-pixel interpolation. (At the time of this writing, this feature is not implemented.) The matrix manipulation functions are in the flip library. See section 2.2.2. If the input image is three-dimensional and has three frames, it will be treated as color. Three dimensional images are interpolated only in a 2D sense. Simple Example: 3.1. GEOMETRIC FUNCTIONS 95 double **X, **Y; X=dmatrix(1,2,1,3); // X is a matrix with rows numbered //from 1 to 2 and columns numbered from 1 to 3. U=dmatrix(1,2,1,3); X[1][1] =0; X[2][1] = 0; // one corner of undistorted image U[1][1] =0; U[2][1] =0; // this point is not moved X[1][2] =0; X[2][2] = 10; // second corner of triangle, ten units to right of previous U[1][2] =0; U[2][2] =10; // this point is not distorted X[1][3] =10; X[2][3] = 5; // third corner of triangle, ten units down //and 5 units over from first U[1][3] =15; U[2][3] =10; // this point is moved, stretching // the triangle up and to the right InterpolateTriange(inputimge, outputimage,X,U,0); 96 CHAPTER 3. IMAGE PROCESSING SUBROUTINES Real Example #include <ifs.h> #include <ifsmatrix.h> int main(int argc, char *argv[]) { IFSIMG inimg; IFSIMG outimg; int row,col,nr,nc; int len[4]; double **X, **U; X=dmatrix(1,2,1,3); U=dmatrix(1,2,1,3); inimg = ifspin(argv[1]); len[2]=nr = ifsdimen(inimg,1); len[1]=nc = ifsdimen(inimg,0); len[0]=inimg->ifsdims; // two dimensional if(len[0]== 3) len[3]=ifsdimen(inimg,2); outimg = ifscreate(inimg->ifsdt,len,IFS_CR_ALL,0); { float ulr,ulc,urr,urc,llr,llc,lrr,lrc,mr,mc; ulr =0;ulc =0; urc=nc-1;urr=0; llr=nr-1;llc =0; lrr=nr-1;lrc=nc-1; mr = nr/2; mc =0; X[1][1] = ulr;X[2][1] =ulc; X[1][2] = urr;X[2][2] =urc; X[1][3] = mr;X[2][3] =mc; U[1][1] = ulr;U[2][1] =ulc; U[1][2] = urr;U[2][2] =urc; U[1][3] = 90;U[2][3] =mc; InterpolateTriangle(inimg,outimg,X,U,0); X[1][1] = urr;X[2][1] =urc; X[1][2] = mr;X[2][2] =mc; X[1][3] = lrr;X[2][3] =lrc; U[1][1] = urr;U[2][1] =urc; U[1][2] = 90;U[2][2] =mc; U[1][3] = lrr;U[2][3] =lrc; 3.1. GEOMETRIC FUNCTIONS 97 InterpolateTriangle(inimg,outimg,X,U,0); X[1][1] = mr;X[2][1] =mc; X[1][2] = lrr;X[2][2] =lrc; X[1][3] = llr;X[2][3] =llc; U[1][1] = 90;U[2][1] =mc; U[1][2] = lrr;U[2][2] =lrc; U[1][3] = llr;U[2][3] =llc; InterpolateTriangle(inimg,outimg,X,U,0); } ifspot(outimg,argv[2]); } Example makefile using InterpolateTriangle distort1: distort1.c cc -o distort1 distort1.c -I/Users/wes/src/ifs/MacX64/hdr \ /Users/wes/src/ifs/MacX64/ifslib/libiptools.a \ /Users/wes/src/ifs/MacX64/ifslib/libifs.a \ /Users/wes/src/ifs/MacX64/ifslib/libflip.a 3.1.5 cubic splines IFS library: libiptools.a usage: void cubic_int(int n,int m,float* f, float* t, float* fn, float* tn) n is the number of points in the input arrays (f and t), m is the number of points in the output arrays (fn and tn) both the time arrays, t and tn must be initialized example initialization // i n i t i a l i z e t for ( i =0; i <N; i ++) { f [ i ]= s i n ( 2 ∗ 3 . 1 4 ∗ i / ( f l o a t ) (N− 1 ) ) ; t [ i ]=( f l o a t ) i ; } // i n i t i a l i z e t n s t e p s i z e =(N−1)/( f l o a t ) (M−1); for ( i =0; i <M; i ++) { tn [ i ]= t [ 0 ] + i ∗ s t e p s i z e ; 98 CHAPTER 3. IMAGE PROCESSING SUBROUTINES fn [ i ]=0.0; } ∗/ void c u b i c i n t ( int n , int m, f l o a t ∗ f , f l o a t ∗ t , f l o a t ∗ fn , f l o a t ∗ tn ) 3.1.6 Resampling Curves IFS library: libiptools.a Resample a line or curve to ensure uniform (arc-length) sampling. Accepts a set of points, x-y pairs, and produces a set of x-y pairs. There are two functions which must be called to use this feature: resampleinit and resamplesub. Usage: #include <resample.h> struct rs * resampleinit(int m,int n); resampleinit sets up a structure in which to hold information about the resampled data. m is the number of points in the input image (the number of rows in the array). n is the number of points into which to divide the resampled output image. Once initialized, the resample function is void resamplesub(int m, int n, double **x, double **y,struct rs *p) The first two arguments are the same as above: m is the current number of points, n will be the number of points on the resampled curve. x and y are matrices, x2,m , y2,n holding the actual data. These are arrays created by resampleinit using dmatrix (see section 2.2.1). Their indices run from 1 to 2 (for the first index) and 1 to m or n. That is, they are created using x = dmatrix(1,2,1,m);y = dmatrix(1,2,1,n); . Note that while these functions are in libiptools, the matrix manipulation functions are in libflip, so you will need to link with both those libraries. Example resample In the example below is shown how to set up and call the two resample functions. It does not include details about how to read and write the ASCII input and output files. #include <math.h> #include <stdio.h> #include <ifsmatrix.h> 3.1. GEOMETRIC FUNCTIONS 99 #include <resample.h> #define EPSILON .0001 int main(int argc, char *argv[]) { double **x; /* the input shape, it has m points */ double **y; /* the output shape, it will have n points, uniformly spaced in arc length */ /* the shapes above are pairs of floats. The even numbered ones are x coords, the odd y */ int m; /* m is the number of points in the input shape */ int n; /* n is the number of points we demand the output shape will have */ struct rs *rsdata; // this is the structure that will persist between resampleinit // and resamplesub double median; FILE *fp, *fopen(); int j; int getshape(char *, double **, double *, double); // function to read the input file int getnumberofpoints(char *); void clparse(int,char *[],struct clp *);// function to parse command line, not provided here void resamplesub(int ,int,double **,double **,struct rs *); struct rs *resampleinit(int,int); /* call the read subroutine to read in the x,y pairs of points */ /* we pass the address of the shape pointer to getshape because the malloc will be done inside getshape */ m = getnumberofpoints(infile); // read the input file to get the m n = NUMBEROFOUTPUTPOINTS; x = (double **)dmatrix(1,m+1,1,2); y = (double **)dmatrix(1,m+1,1,2); m = getshape(infile,x,&median,(double) 0.0); // read the input file rsdata = resampleinit(m,n); resamplesub(m,n,x,y,rsdata); //inititalize the struct /* write out the y array */ /* actually write the x array, since we have already swaplped pointers */ fp = fopen(outfile,"w"); for(j = 1; j <=NUMBEROFOUTPUTPOINTS; j++) 100 CHAPTER 3. IMAGE PROCESSING SUBROUTINES { fprintf(fp,"%lf %lf\n",x[j][1],x[j][2]); } fclose(fp); return 0; } 3.1.7 Operations on FIFO’s The following operations are useful in manipulating first-in-first-out memories, or queues. All of them use a structure which contains information about the queue. The structure has the following form: struct myque{ int ∗q ; int f r o n t ; int r e a r ; int s t a r t ; int end ; int count ; }; fifo init; initialize the queue call: void fifo_init(int D,struct myque *queue); fifo add; add a new number to the queue call: int fifo_add(int item ,struct myque *queue); fifo remove Remove a number from the queue and return it. call: int fifo_remove(struct myque *queue); fifo empty Return true (nonzero) or false (zero) if the queue is or is not empty call: int fifo_empty(struct myque *queue); 3.1. GEOMETRIC FUNCTIONS 3.1.8 101 MinimumRegion This function finds and marks all minimum regions in an image. Every pixel in the output image either is a zero or has a distinct label A minimum region is all the same brightness and has no neighbors darker than itself. This function only runs on Unsigned Char images This function is an almost direct translation from algorithm 4.6 of Roerding and Meijster. Usage: int MinimumRegion(IFSIMG img, IFSIMG labelimg) Note: the source code for MinimumRegion is part of the source module Watershed.c 3.1.9 Watersheds A watershed is the boundary between two basins. int ifs_WaterShed(IFSIMG im,IFSIMG om); Both images must be ifs images of type int. The output image is a segmented version of the input image. It will contain uniquely labeled regions. WaterShed points will have brightness zero. Note that although watershed pixels are in principal the boundaries of basins, they are not necessarliy a single pixel thick. The WaterShed program (see section ??) adds additional features by erasing watershed pixels and assigning them to regions. The WaterShed program also provides the user with the ability to pseudocolor the output image. 3.1.10 ifs ccl IFS library: libiptools.a This function performs connected components on an image. It is the function called by the program named ccl. The program ccl simply reads the command line, fills in a structure from the command line, allocates some memory, and calls this function. The declaration for the call is void ifs_ccl(IFSIMG, IFSIMG, IFSIMG,struct PAR *parptr); Because there are many options, the structure is rather long. The process of defining the structure and filling it in is given below. The user is advised to simply cut and paste the block below. This block includes the call to ifs ccl, passing the images and the structure. The connect type field allows the user to specify which type of connivity is used to determine when two pixels/voxels are considered neighbors. In three dimensions, the three types of connectivity are shown in Figure 3.1. In two dimensions, FACE is 4-connected, EDGE is 8-connected. 102 CHAPTER 3. IMAGE PROCESSING SUBROUTINES Figure 3.1: Three types of connectivity may be used by the connected components function in 3D images. In 2D images, FACE is equivalent to 4-connected, and EDGE is equivalent to 8-connected 3.1. GEOMETRIC FUNCTIONS 103 { /∗ s t a r t o f t h e b l o c k ∗/ // t h i s i s t h e d e f i n i t i o n o f t h e s t r u c t u r e struct PAR { char InFileName [ 1 0 0 ] ; // not needed i f c a l l e d as a f u n c t i o n char OutFileName [ 1 0 0 ] ; // not needed i f c a l l e d as a f u n c t i o n float lower limit ; // low l i m i t o f p o i n t s c o n s i d e r e d , u s u a l l y z e r o float upper limit ; /∗ upper l i m i t o f p o i n t s c o n s i d r e d , u s u a l l y 255 ∗/ int connect type ; /∗ EDGE( 2 ) ,FACE( 1 ) or VERTEX( 4 ) ∗/ f l o a t c o n n t h r e s h o l d ; // c o n n e c t i o n t h r e s h o l d . two p i x e l s w i t h // g r e a t e r d i f f e r e n c e w i l l not be c o n n e c t e d int roi set ; // s e t t o one f o r Region o f I n t e r e s t int roi seed [ 3 ] ; /∗ r o i s e e d l o c a t i o n , 3 numbers ∗/ int r o i l a b e l ; /∗ l a b e l f o r r e g i o n o f i n t e r e s t ∗/ int roi seg out ; /∗ segment o u t t h e r o i components ∗/ int r o i s e g v a l u e ; /∗ v o x e l v a l u e s f o r r e g i o n o f i n t e r e s t ∗/ int l o w e r b g l a b e l ; /∗ l a b e l used f o r l o w e r b a c k g r o u n d ∗/ int u p p e r b g l a b e l ; /∗ l a b e l used f o r upper b a c k g r o u n d ∗/ int m i n l a b e l ; /∗ minimum l a b e l used ∗/ int m a x l a b e l ; /∗ maximum l a b e l used ∗/ int c a m s i z e ; /∗ s i z e o f c o n t e n t a d d r e s s a b l e memory a r r a y ∗/ unsigned int ∗cam ; /∗ p o i n t e r t o t h e cam ; ∗/ /∗ t h e f o l l o w i n g 3 numbers c o u l d be o b t a i n e d from t h e image b u t a r e i n c l u d e d i n t h e s t r u c t u r e o n l y f o r e f f i c i e n c y o f a c c e s s ∗/ int nr ; // number o f rows int nc ; // number o f columns int n f ; // number o f frames }; struct PAR mypar , ∗ p a r p t r ; // an i n s t a n c e o f t h e s t r u c t u r e and a p o i n t e r t o i t void i f s c c l ( IFSIMG , IFSIMG , IFSIMG , struct PAR ∗ ) ; unsigned int ∗ cam ptr ; int i ; par=&mypar ; // i t i a l i z e t h e p o i n t e r par−>InFileName [ 0 ] = 0 ; // not needed i f c a l l e d as a f u n c t i o n par−>OutFileName [ 0 ] = 0 ; // not needed i f c a l l e d as a f u n c t i o n par−>l o w e r l i m i t =0; // low l i m i t o f p o i n t s c o n s i d e r e d , u s u a l l y z e r o /∗ upper l i m i t o f p o i n t s c o n s i d r e d , u s u a l l y 255 ∗/ par−>u p p e r l i m i t =1; par−>c o n n e c t t y p e =1; /∗ EDGE( 2 ) ,FACE( 1 ) or VERTEX( 4 ) ∗/ par−>c o n n t h r e s h o l d =0; // c o n n e c t i o n t h r e s h o l d . two p i x e l s w i t h par−>r o i s e t =0; // s e t t o one f o r Region o f I n t e r e s t 104 CHAPTER 3. IMAGE PROCESSING SUBROUTINES par−>r o i s e e d [ 0 ] = 0 ; /∗ r o i s e e d l o c a t i o n , 3 numbers ∗/ par−>r o i l a b e l =0; /∗ l a b e l f o r r e g i o n o f i n t e r e s t ∗/ par−>r o i s e g o u t =0; /∗ segment o u t t h e r o i components ∗/ par−>r o i s e g v a l u e =1; /∗ v o x e l v a l u e s f o r r e g i o n o f i n t e r e s t ∗/ par−>l o w e r b g l a b e l =1; /∗ l a b e l used f o r l o w e r b a c k g r o u n d ∗/ par−>u p p e r b g l a b e l =500; /∗ l a b e l used f o r upper b a c k g r o u n d ∗/ par−>m i n l a b e l =1; /∗ minimum l a b e l used ∗/ par−>m a x l a b e l =5000; /∗ maximum l a b e l used ∗/ par−>c a m s i z e =64000; /∗ s i z e o f c o n t e n t a d d r e s s a b l e memory a r r a y ∗/ par−>cam=0; /∗ p o i n t e r t o t h e cam i n i t i a l i z e d l a t e r ∗/ /∗ t h e f o l l o w i n g 3 numbers c o u l d be o b t a i n e d from t h e image b u t a r e i n c l u d e d i n t h e s t r u c t u r e o n l y f o r e f f i c i e n c y o f a c c e s s ∗/ par−>nr=i f s d i m e n ( inimg , 1 ) ; // number o f rows par−>nc=i f s d i m e n ( inimg , 0 ) ; ; // number o f columns par−>n f =1; // number o f frames /∗ now t h a t t h e s t r u c t u r e i s i n i t i a l i z e d , we a r e r e a d y t o c a l l t h e c o n n e c t e d components f u n c t i o n ∗/ /∗ i n i t i a l i z e t h e c o n t e n t −a d d r e s s a b e memory∗/ /∗−−−−a l l o c a t e CAM and c a r d i n a l i t y a r r a y s ∗/ par−>cam = ( unsigned int ∗ ) c a l l o c ( par−>c a m s i z e , s i z e o f ( int ) ) ; i f ( par−>cam == NULL) { p r i n t f ( ” E r r o r : Unable t o a l l o c a t e %d e l e m e n t CAM\n” , par−>c a m s i z e ) ; e x i t ( −1); } /∗−−−− i n i t i a l i z e CAM ∗/ cam ptr = par−>cam ; for ( i = 0 ; i < par−>c a m s i z e ; i ++) ∗ cam ptr++ = i ; /∗ n o t i c e c c l t a k e s t h r e e image i n p u t s , however , t h e t h i r d one i s o n l y t o u c h e d i f ROI p r o c e s s i n g i s r e q u e s t e d , so we use outimg ∗/ /∗ FINALLY, we c a l l i t ! ∗/ i f s c c l ( inputimg , i m a g e a f t e r c c l , outimgwithROI , p a r p t r ) ; } 3.1. GEOMETRIC FUNCTIONS 3.1.11 105 ifscfft2d IFS library: libiptools.a ifscfft2d - perform in-place 2D fast Fourier transform Usage: len = cfft2d(img_ptr, type) IFSHDR * imgptr; int type; Ifscfftt2d performs an in-place 2-D fast Fourier transform on a complex ifs image. The transform is performed in place on 8BYTE-PER-PIXEL (complex float) data only! Note that ffts only work on images of dimension 2n×2n . The second argument is an indicator for forward or inverse fft, -1 for forward, +1 for inverse. If there is some error, the subroutine exits to the user with an error message. Possible errors are: • Image dimensions are not a power of two • Image data type is not complex float 106 CHAPTER 3. IMAGE PROCESSING SUBROUTINES 3.1.12 ifsc2imag IFS library: libiptools.a ifsc2imag - extract imaginary part of a complex ifs image, point by point Usage: val = ifsc2imag (in1, out) int val; IMSHDR *in1,*out; RETURNS 0 if successful, -1 if both arguments do not have same dimensions -2 if data type unsupported (complex double) CAUTION: if output is type char, values greater than 255 will be clipped to lie between 0 and 255. 3.1. GEOMETRIC FUNCTIONS 3.1.13 107 ifsc2mag IFS library: libiptools.a ifsc2mag - return magnitude of a complex ifs image, point by point Usage: val = ifsc2mag (in1, out) int val; IMSHDR * in1,*out; RETURNS 0 if successful, -1 if both arguments do not have same dimensions -2 if data type unsupported (complex double) CAUTION: if output is type char, values greater than 255 will be truncated to 255. 108 CHAPTER 3. IMAGE PROCESSING SUBROUTINES 3.1.14 ifsc2phase IFS library: libiptools.a ifsc2phase - return phase of a complex ifs image, point by point Usage: val = ifsc2phase (in1,out) int val; IMSHDR *in1,*out; RETURNS 0 if successful, -1 if both arguments do not have same dimensions, -2 if data type unsupported (complex double) CAUTION: if output is type char, values greater than 255 will be truncated to 255. 3.1. GEOMETRIC FUNCTIONS 3.1.15 109 ifsc2real IFS library: libiptools.a ifsc2real - return real part of a complex ifs image, point by point Usage: val = ifsc2real (in1,out) int val; IMSHDR *in1,*out; RETURNS 0 if successful, -1 if both arguments do not have same dimensions -2 if data type unsupported (complex double) CAUTION: if output is type char, values greater than 255 will be truncated to 255. 110 3.1.16 CHAPTER 3. IMAGE PROCESSING SUBROUTINES ifsInsert2Dinto3D IFS library: libiptools.a ifsInsert2Dinto3D - inserts a 2D image as a single frame into a 3D ifs image Usage: val = ifsInsert2Dinto3D (IFSIMG in,IFSIMG out,int frame) RETURNS 0 if successful, -1 if both arguments do not have same dimensions or if data type unsupported (complex double) CAUTION: if output is type char, values greater than 255 will be converted to char. 3.1. GEOMETRIC FUNCTIONS 3.1.17 111 ifsmult IFS library: libiptools.a ifsmult - multiply two ifs images, point by point Usage: int ifsmult (in1, in2,out) IFSHDR *in1,*in 2,*out; RETURNS 0 if successful, -1 if all three arguments do not have same dimensions -2 if data type unsupported (complex double) -3 if one input has type complex and output is real -4 if both inputs are real and output is complex CAUTION: if output is type char, values greater than 255 will be truncated to 255. NOTES: if one image is real and the other complex, the output must be complex and the real parts of the images will be added. 112 CHAPTER 3. IMAGE PROCESSING SUBROUTINES 3.1.18 ifsrecip IFS library: libiptools.a ifsrecip take reciprocal of an ifs image, point by point Usage: int ifsrecip (in1,out) IFSHDR *in1,*out; RETURNS 0 if successful, -1 if both arguments do not have same dimensions -2 if data type unsupported (complex double) -3 if one input has type complex and output is real -4 if both inputs are real and output is complex CAUTION: if output is type char, values greater than 255 will be truncated to 255. NOTES: if one image is real and the other complex, the output must be complex and the real parts of the images will be added. 3.1. GEOMETRIC FUNCTIONS 3.1.19 113 ifssub IFS library: libiptools.a ifssub subtracts two ifs images, point by point. The second argument is subtracted from first. Usage: int ifssub (in1, in2, out) IFSHDR *in1,*in2,*out; RETURNS 0 if successful, -1 if all three arguments do not have same dimensions -2 if data type unsupported (complex double) -3 if one input has type complex and output is real -4 if both inputs are real and output is complex CAUTION: if output is type char, values greater than 255 will be truncated to 255. NOTES: if one image is real and the other complex, the output must be complex and the real parts of the images will be added. 114 3.1.20 CHAPTER 3. IMAGE PROCESSING SUBROUTINES ifsvidscale IFS library: libiptools.a ifsvidscale converts an ifs image, of any data type, to an unsigned char ifs image. The brightness values are scaled to lie between 0 and 255. Usage: int ifsvidscale (IFSHDR in1, IFSIMG out,float *minvalptr,float *maxvalptr, int switch3d) The two arguments minvalptr and maxvalptr are pointers to floats, and will be returned by ifsvidscale, reporting the minimum and maximum of the input images, respectively. The switch3d argument, if not ==0, indicates that the frames of the image should be scaled independently. Note that in this case, the minvalptr and maxvalptr apply only to the last frame in the sequence. RETURNS 0 if successful The function will scale minimum brightness - maximum brightness to 0 to 255. NOTES: The second image must be unsigned char. Example: img2=ifscreate("u8bit",len,IFS_CR_ALL,0); ifsvidscale(inimage, img2,&mymin,&mymax,0); 3.2 3.2.1 Functions to modify images ifscolormap IFS library: libiptools.a The function ifscolormap is similar to the program ColorMap in that it allows you to assign a number of different colors to an 8-bit, unsigned image. That is, each of the possible 256 brightness levels will be assigned a color. There are many ways to assign an R, G, and B value to a single pixel brightness. The function offers several different ways to interpret the brightnesses. Usage: void ifscolormap( IFSIMG inputimage, IFSIMG outputimage, int X); Where inputimage is an unsigned 8 bit fs image, and X is an integer between 0 and 6 which tells the program which color map to use as follows: 0 grey scale 1 inverse gray scale 2 bronson 3 hot metal 4 heated spectrum 5 log 6 random 3.2. FUNCTIONS TO MODIFY IMAGES 115 The input image must be unsigned 8 bit, since there are only 256 unique colors . The input image must be two-dimensional. The output file must be a 3 D unsigned 8 bit ifs image, with 3 frames, with the usual interpretation that frame 0 is red, frame 1 is green, and frame 2 is blue. The function does not create this image, a pointer to it is passed by the calling function. example use int l e n [ 4 ] ; IFSIMG inimage , outimg ; extern void i f s c o l o r m a p ( IFSIMG , IFSIMG , int ) ; ... len [0]=3; l e n [ 1 ] = i f s d i m e n ( inimage , 0 ) ; // g e t number o f c o l s l e n [ 2 ] = i f s d i m e n ( inimage , 1 ) ; // g e t number o f rows l e n [ 3 ] = 3 ; // image w i l l have 3 frames outimg=i f s c r e a t e ( ” u 8 b i t ” , l e n , IFS CR ALL , 0 ) ; i f s c o l o r m a p ( inimg , outimg , 3 ) ; // use a h o t m e t a l c o l o r map ... i fs C Vp ot ( outimg , ”myimage . png” ) ; ... 3.2.2 Lower Complete Images To understand this, first recall that in a digital image, a maximum is a connected set of pixels, which are all the same brightness, with the property that no pixel in this set is adjacent to any brighter pixel. A minimum is a similarly defined set. A plateau is a connected set of pixels, which are all the same brightness, but which has at least one neighboring pixel which is brighter and one which is darker. Plateaus cause probems to some algorithms. A lower complete image is one in which every pixel is either a maximum, a minimum, or has at least one lower neighbor. That is, a lower complete image has no plateaus. This function provides that capability. void Build_Lower_Complete(IFSIMG inimage,IFSIMG LowerCompleteImage) The input, inimage, must be unsigned 8 bit. The output, LowerCompleteImage, must be type int. The brightness values will be changed to ensure the image is lowercomplete. 3.2.3 zoomupdown Will zoom an image Example usage: 116 CHAPTER 3. IMAGE PROCESSING SUBROUTINES img1 = ifspin("/Users/wes/Images/asterix256.ifs"); len[0]=2; len[1]= ifsdimen(img1,0) * 2; len[2] =ifsdimen(img1,0) * 1; img2 = ifscreate(img1->ifsdt,len,IFS_CR_ALL,0); zoomupdown(img1,img2); The input image will be zoomed to the size of the output image. The output image will be overwritten with the zoomed version of the input image. The two images do not have to have proportional dimensions. For example, inputimage could be 512 x 512 and output image could be 640 x 480. Of course, unless the images have proportional dimensions, the output image will be distorted. 3.3 3.3.1 Random number generators gaussrand IFS library: libiptools.a double gaussrand() returns a Gaussian-destributed random number with standard deviation of one and mean of zero. Chapter 4 Image Synthesis Programs 4.1 Qsyn-synthesize range images Qsyn generates synthetic altitude images of objects which are composed of quadric surfaces or pieces of quadric surfaces. Usage: qsyn [-f][-l labelfile.ifs] [-o depthfile.ifs] formatfile.q The -f switch is optional and if used will cause the output file to be floating point. The -l switch is optional and if used will cause qsyn to also output a label image, in which each surface is a different brightness – the image is segmented. If the -o switch is not used to provide a name for the altitude output image, then after running, the program will ask for the name of the output altitude image. The label image is an image in which every pixel belonging to the same region is labeled the same. Thus, the label image is equivalent to the output of an ideal segmenter. This can be used to test the performance of segmentation algorithms. Qsyn is a program which generates synthetic altitude images of objects which are composed of quadric surfaces or pieces of quadric surfaces. The image data is in an unsigned byte format, although a few minor changes could be made to Qsyn to allow for some other output data type. Image manipulation is done using the IFS image manipulation routines in use at Communication Unlimited. Qsyn generates altitude images, i.e., two dimensional images which contain three dimensional information, where the coordinates of a pixel (its row and column index) correspond directly to the x and y values for the pixel, and the pixel value itself (the datum) corresponds directly to the altitude or z value for the point. Hence, a point in three-space at position [x, y, z] corresponds to some pixel in an image I: [x, y, z] → I[r, c] (4.1) where I[r,c] is the value of the pixel at row r, column c of the image. r, c, and I[r,c] are linearly related to y, x, and z, respectively. In Qsyn, the linear relationship is simply taken 117 118 CHAPTER 4. IMAGE SYNTHESIS PROGRAMS to be r = y, c = x, and I[r, c] = z. Note that an altitude image is not the same as a range image, which is also commonly used to represent three-dimensional images. In a range image, the pixel value represents the distance from some point in three space to a fixed reference position (i.e., the view point), whereas an altitude image is based on the distance to some reference plane, hence a range image is actually a perspective projection of an altitude image. Qsyn generates images composed of quadric surfaces. An image may contain any number of surfaces; in addition, each surface may also have constraints placed on it. These constraints are also quadric surfaces (quadric inequalities). A quadric surface is a 3-dimensional surface which may be described by a general quadric equation: q(x, y, z) = Ax2 + By2 + Cz2 + F yz + Gxz + Hxy + P x + Qy + Rz + K = 0 (4.2) This includes common shapes such as spheres, cones, and planes. Qsyn works by generating a quadric surface which is bounded by a set of quadric constraints. For example, an image of an open-ended can maybe produced by synthesizing an image of a cylinder which is constrained by two planes perpendicular to the cylinder. The constraints would specify those points on the cylindrical surface which lie above the lower plane and below the upper plane. As a matter of terminology, I will use the term quadric section to refer to a quadric surface along with a set of constraints on that surface. In order to use Qsyn, you must understand the coordinate systems it uses to orient surfaces and sections. Theoretically, you could place surfaces wherever you wanted by specifying the appropriate coefficients in the quadric equation 4.2. In practice, this is a pain since the coefficients are a function of the objects position and orientation as well as its shape. E.g., x2 + y 2 + z 2 = r 2 (4.3) describes a sphere of radius r centered at the origin. The quadric coefficients are A = B = C = 1; K = −(r2 ). Moving this sphere so that its center is at location (x, y, z) = (10, 5, 0) gives: (x − 10)2 + (y − 5)2 + z 2 = r2 (4.4) which when put into the form of equation 4.5 looks like x2 + y 2 + z 2 − 20x − 10y + (125 − r2 ) = 0. (4.5) Rotating an object affects the quadric coefficients in a still more complicated way. Qsyn allows you to specify a surface using any coordinate system you desire; you may then translate or rotate the object to move it to a different coordinate system. Qsyn uses several different coordinate systems to ease the task of creating images which are composed of multiple surfaces. Figure 4.1 shows the various coordinate systems used, and are described here. Each surface (including constraints) is defined in terms of its own local coordinate system. Typically you would choose the coordinate system in which it was 4.1. QSYN-SYNTHESIZE RANGE IMAGES 119 easiest to describe the shape you want. Each quadric section has its own coordinate system, known as a section or object coordinate system. The latter term is perhaps misleading in that what you think of as an object may actually consist of more than one section. By specifying the relationship between the local coordinate system for each surface in a section to the sections coordinate system, you specify how the various parts of the section fit together. This essentially is used to relate the constraints to the actual surface being synthesized, with the coordinate system of the surface itself (its local system) typically being coincident with the section coordinate system. This is not a requirement though; the surface and its constraints are all placed relative to a common section system, rather than the constraints being placed relative to the local system of the surface. The next higher level coordinate system is the reference or base coordinate system. This is the base coordinate system for the entire image to be synthesized. Its relationship to the object coordinate systems is the same as that of the object to local coordinate systems. By specifying the relative locations of each object coordinate system in the base system, you define how the various quadric sections fit together, and define what the over all image will look like. The highest level coordinate system is the viewpoint coordinate system. This corresponds to the coordinate system for the image array, and hence, the display equipment. The x and y axes correspond to the horizontal and vertical axes of the display, and the z axis is the actual pixel value, i.e., the brightness or color of the pixel indicates the altitude. The relation between the view coordinate system and the base coordinate system specifies the position which you are actually seeing the image from. In many cases the two coordinate systems may be coincident, or one merely a translation of the other. Note that the term “viewpoint system” is somewhat misleading in that this is not a range image; this transform really defines a plane of projection for the image (which is fully described at the level of the base system). The projection plane itself is the xy plane of the viewpoint coordinate system. The image array itself is just a finite piece of this infinite projection plane. Specifically, the origin [x, y] = [0, 0] corresponds with the pixel at location [col, row] = [0, 0] in the image array (which is in one corner of the image). Hence, if you define the objects in your image to lie around the origin (in the base coordinate system), when you display the image you will probably find that all of the objects will lie in one corner of the image, unless you have displaced the base system relative to the viewpoint system. Put simply, the origin of the base system will be in one corner of the image you synthesize unless you make sure to move it – and you may end up not seeing parts of your objects since they will be clipped at the image borders. In Qsyn, the relations between coordinate systems are expressed in terms of six basic motions: translations along the three coordinate axes, and rotations about the axes. Motions along the axes go by the names of movex, movey, and movez. Rotations about the axes go by the names of rotx, roty, and rotz, or alternatively as yaw, pitch, and roll, respectively. When specifying the relationship between two coordinate systems, the motions are given in terms of the higher coordinate system, i.e., the higher level system is the base 120 CHAPTER 4. IMAGE SYNTHESIS PROGRAMS Figure 4.1: Coordinate systems used by Qsyn 4.1. QSYN-SYNTHESIZE RANGE IMAGES 121 Figure 4.2: Order of motions system. For example, to specify that the local coordinate system for a constraint has its origin at location (x, y, z) = (10, 5, 2) in the section coordinate system, you would specify the motion as the motion as (movex 10, movey 5, movez 2), as this would be specifying the origin of the higher system (the section system) in terms of the lower (the local system). This is easy to see for motions which are pure translations, but may provide a source of confusion when rotations are involved. The best way to regard the motions is as being object oriented. Although you are specifying the relationship between two coordinate systems, the lower coordinate system can be regarded as an object in the higher coordinate system (imagine that the lower level system has a cube sitting at its origin, and you are moving the cube around in the higher level system). Initially, the two coordinate systems start out with coincident axes, i.e., the lower system is an object sitting at location (0, 0, 0) in the higher system. If you specify a motion of movex10, then all objects in the higher level system are displaced 10 units down the x axis. If you specify a motion of roll20, then all objects swivel around the z axis of the higher system. This is not the same as simply rotating the lower coordinate systems coordinate system by 20 degrees! If the lower systems origin coincides with the higher systems origin, then the effects are the same; however, if the origin points do not coincide, then the lower systems origin will be seen to swing on an arc around the higher systems axis. Hence, the rotation will also cause a translation in two of the axes of the higher 122 CHAPTER 4. IMAGE SYNTHESIS PROGRAMS system. Figure 4.1 illustrates this, and also show how the order of motions is important. Qsyn works by reading a file which describes the image to be synthesized. This file contains the quadric coefficients for each surface and constraints (in their own local coordinate system), and movement commands which specify how the coordinate systems are located. Qsyn reads this specification file and generates the image; when it is done, it prompts for the name of a file to write the image to. The output file is a 2-d IFS format image. The data type for the image will be unsigned byte or float (depending on a command line switch), with the value of a pixel indicating its height. The nearer a pixel is, the higher its pixel value. The format for the image specification file is relatively simple. Presented below is a sample specification file; the format is described below. It is a text file composed of several blocks. These blocks may contain other blocks within them. At the beginning of the file is a header block which specifies the size (number of rows and columns) of the image to be generated, the number of quadric sections to synthesize, and a set of motions which will translate the reference coordinate system to the viewpoint coordinate system. The motions which specify the relationship between the two coordinate systems are actually an instance of a type of sub-block known as a coordinate transform block, or just transform. These transforms occur in several places, and always have the same format. There are six basic motions which may be specified in a transform block. There are also several complex motions which are simply composites of the basic motions. All of the motions are specified by some keyword describing the motion to perform, followed by the parameters appropriate for that keyword. The six basic motions are those mentioned earlier: movex, movey, movez, rotz(roll), roty(pitch), and rotx(yaw). The movex, movey, and movez commands can also be shortened to x, y, and z. Each motion takes a single argument which is the amount to move or the angle to rotate (in degrees). To specify a complete transform block, you merely specify an arbitrary number of basic motions (in arbitrary order), followed by the keyword end. The basic motions are performed in the order specified. A sample transform block might look like: movex 20 movey 10 pitch 30 end This will shift an object 20 units along the x axis, 10 units in y, and swing the object 30 degrees around the y axis. The composite motions are just shortcuts for specifying certain common sets of motions. The combination ‘movex 10 movey 20 movez 30’ can be specified more rapidly as ‘movexyz 10 20 30’ or just ‘xyz 10 20 3’. Similarly, rpy 10 20 30 is short for roll 10 pitch 20 yaw 30. All six basic motions can be expressed using the commands rpyt θz , θy , θx , ∆x , ∆y , ∆z and trpy θz , θy , θx , ∆x , ∆y , ∆z . Rpyt does the rotations first, then the translations; trpy performs the translations first. Note that the syntax for trpy is inconsistent in that although the translations are performed first, they are the last arguments specified for the command. After the header block there comes a set of section blocks, one block for each quadric section to synthesize. Each block describes a surface to generate, and all the constraints 4.2. 3DSYN-SYNTHESIZE DENSITY IMAGES 123 for the surface. The quadric section blocks are in turn composed of smaller blocks. The first sub-block is a transform block which converts from the section coordinate system to the base coordinate system. This is followed by a surface block. A surface block contains a set of quadric coefficients to describe a single quadric surface, and also contains a transform block which translates the surfaces local coordinate system to the section coordinate system. After the surface block comes the number of constraints, followed by a set of constraint blocks. A constraint block is identical to a surface block except that it contains a flag indicating which way the constraint inequality goes (e.g., choose all points in the surface below some plane ). 4.2 3dsyn-synthesize density images CONVERSION TO LATEX NOT FINISHED 3dsyn generates synthetic three dimensional density images of objects which are composed of quadric surfaces or pieces of quadric surfaces. Usage: 3dsyn format file.q 3dsyn is a program which generates synthetic three dimensional density images of objects which are composed of quadric surfaces or pieces of quadric surfaces. The image data is in an unsigned byte format, although a few minor changes could be made to 3dsyn to allow for some other output data type. Image manipulation is done using the IFS image manipulation routines in use at Communication Unlimited. 3dsyn generates density images, i.e., three dimensional images which contain three dimensional information, where the coordinates of a voxel (its row and column and frame index) correspond directly to the x, y, and z values for the voxel, and the voxel value itself (the datum) corresponds directly to the density for the point. Hence, a point in three-space at position [x, y, z] corresponds to some voxel in an image I: [x, y, z] → [f, r, c] (4.6) where I[f, r, c] is the value of the voxel at frame f, row r, column c of the image. The variables, f, r, c, and I[f, r, c] are linearly related to z, y, and x, respectively. In 3dsyn, the linear relationship is simply taken to be f = z, r = y, and c = x, and I[f,r,c] = density. 3dsyn generates images composed of quadric surfaces. An image may contain any number of surfaces; in addition, each surface may also have constraints placed on it. These constraints are also quadric surfaces (quadric inequalities). A quadric surface is a 3-dimensional surface which may be described by a general quadric equation: q(x, y, z) = Ax2 + By 2 + Cz 2 + F yz + Gxz + Hxy + P x + Qy + Rz + K = 0. (4.7) This includes common shapes such as spheres, cones, and planes. 3dsyn works by generating a quadric surface which is bounded by a set of quadric constraints. For example, an 124 # # # # # CHAPTER 4. IMAGE SYNTHESIS PROGRAMS This is a Qsyn description file which will generate a simple altitude image of a clipped lead sticking through a hole in the under side of a printed circuit board. The lead will have a "clinch angle" (angle that lead is bent away from pointing straight up) of 80 degrees, and a "lead angle" (angle in the xy plane -- the plane representing the PC board) of 30 degrees. #The image is composed of 4 pieces (quadric sections): # 1. A cylindrical piece which is the body of the lead. # 2.A plane with a hole in it which represents the circuit board. # The cylinder in (1) goes through the hole. # 3.A sphere at one end of the cylinder in (1) [same radius as the # cylinder] which terminates the lower end of the lead. # 4.A second spherical section which caps the other end of the lead. # # This second sphere has a larger radius than the sphere, so that # # the higher end of the cylinder is clipped almost in a plane. # # Note that if this cap wasnt here, youd be able to see inside the # # cylinder in (1)! # # # # NOTE: This file is not directly suitable to be passed as input to Qsyn. # # Qsyn understands comments in a file (comments going from # # the # symbol to the end of the line). If you insist on removing them, a little # # cleverness under Unix systems will make it suitable: # # # # sed s/#.*$//example.q | Qsyn # # # # The strange looking "sed" command will edit out the comments before # # piping the file into Qsyn. # # itself. # # # ##################################################################### Figure 4.3: Qsyn expample page 1 4.2. 3DSYN-SYNTHESIZE DENSITY IMAGES 125 #-------------------------Header section------------------------------------128 128 #Dimensions of image 4 # Number of quadric sections in image # This is the ’base’ to ’viewpoint’ coordinate system transform block: roll 030 #0 # Rotate 30 degrees about the Z axis # This rotates EVERYTHING by 30 degrees, and is # what gives the lead a "lead angle" of 30 degrees. # Note that Im really rotating the board too, but # since the board is an infinite xy-plane, you cant # tell it. Hence, a more technically accurate, but # slightly more cumbersome way to do this is to have # the "roll 30" in the section to base transforms # of each of the actual pieces making up the lead. movex 64 # Now Ill do a translation in X and Y so that movey 64 # the object is centered in the image rather movez 75 # than in the lower left corner. end # movez 75 is just cause I want board at Z = 75. \ # #----------------------End of header section--------------------------------# This is the first quadric section. It describes the plane which represents # the printed circuit board. # SECTION to BASE coordinate system transform block. # All of the surfaces in this sections (that is, including the constraint ) end # A Null block (i.e., the two systems here # are coincident). ####### Define quadric surface: # The quadric surface coefficients: 000 000 001 0 # The plane "Z = 0" # and the transform relating the LOCAL system to the SECTION system: end # Null block. Systems are coincident #######end of definition for the quadric surface. Figure 4.4: Qsyn example , page2 126 CHAPTER 4. IMAGE SYNTHESIS PROGRAMS # Now: define the constraints on the above surface: 1 # this is the number of constraints. # 1 1 1 # constraint quadric coefficients 0 0 0 # X*X+Y*Y+Z*Z=100, i.e., a sphere of 0 0 0 -100 # radius 10. # #LOCAL to SECTION transform for this constraint: end #Once again, no transform. # And lastly, a "<" or ">" symbol which indicates on which side of the # constraint surface the object must lie: > # The ">" specifies that my constraint # equation actually is # X*X + Y*Y + Z*Z > =100 # Hence, only points on the plane Z = 0 which # are OUTSIDE this sphere are valid. # This puts a hole at the center of my plane. # # # # # # # # This is the second quadric section. Its the cylinder which makes up the body of the lead. I originally define the cylinder as lying on the Z axis (which also makes it easy to specify constraints on it). Then I use the SECTION to BASE transform to tip the cylinder (and its constraints) over to give the appearance of a clinched lead. The SECTION to BASE transform: lead is clinched 80 degrees. The "movez 6" displaces the cylinder upwards 6 units, which is needed because otherwise the lead will be embedded in the board plane, rather than lying just above it pitch 080 movez 6 end # Define my cylinder: cylinder on Z axis with radius 6: 110 000 000 -36 end # No transform. Figure 4.5: Qsyn example, page3 4.2. 3DSYN-SYNTHESIZE DENSITY IMAGES 127 # Now, specify my constraints. Remember that the cylinder is defined as # lying on the Z axis (even in the SECTION system, since the above transform # was null), so the constraints clip the cylinder at right angles to its # axis. Now, the SECTION to BASE transform applies to both the cylinder \# and its constraints, so the net effect is to pitch the CLIPPED cylinder # by 80 degrees. # 2 # there will be two constraints. 0 0 0 0 0 0 0 0 1 0 end > # Constraint 1: Z > =0 0 0 0 0 0 0 0 0 1-34 end< #Constraint 2: Z<=34 # # So, now I have a cylindrical piece lying between Z = 0 and Z = 34. # Note that the cylinder is NOT capped at the ends. # Section 3. This is a sphere which will cap off the lower end of the lead. movez 6 end # The "movez 6" is same as in section 2. 1 1 1 0 0 0 # Sphere of radius 6 (at the origin in the local 0 0 0 # system)... -36 end #... and at the origin in the SECTION system... # but centered at x, y, z = 0,0,6 in the BASE system. 0 # Zero constraints. Figure 4.6: Qsyn example, page4 128 # # # # # # CHAPTER 4. IMAGE SYNTHESIS PROGRAMS Lastly, section 4, the sphere capping off the upper end of the lead. You need to pay careful attention to the movements for this piece to observe how the spherical patch does indeed end up capping off the cylinder described in section 2. Note that the movements given here certainly do not describe the ONLY valid way to get the patch; any of a variety of movements would do the trick. pitch 080 movez 6 end 1 1 1 # sphere of radius 8. 0 0 0 0 0 0 -64 movez 28. 7085 end # That goofy number you have to work out from # the geometry of the situation. The sphere # is placed so that it will sit right at the # end of the clipped cylinder. The sphere # will intersect the cylinder at a height of # Z = 34 (or Z = 40 after the "movez 6" is # applied). 1 # 1 constraint: 0 0 0 0 0 0 0 0 1 -34 end > #only want that part of the # sphere which will cap off # the cylinder; I dont want # to put a big ball at the # end of the cylinder. #### and now, the name of the file to write the image to: pcb_lead.ifs Figure 4.7: Sample Qsyn input file, page5 4.2. 3DSYN-SYNTHESIZE DENSITY IMAGES 129 128 128 2 end end 000 000 1 0 -1 -20 end 4 000 000 1 0 0 -20 end > 000 000 1 0 0 -30 end < 000 000 0 1 0 -20 end > 000 000 0 1 0 -30 end < end 000 000 -2 0 -1 +70 end 4 000 000 1 0 0 -30 end > 000 000 1 0 0 -35 end < 000 000 0 1 0 -20 end > THIS IS NOT COMPLETE Figure 4.8: Another example Qsyn description: a plane at z = 0 with two sloped planes in a rectangular area between x = 20 and x = 35 . 130 CHAPTER 4. IMAGE SYNTHESIS PROGRAMS image of an open-ended can may be produced by synthesizing an image of a cylinder which is constrained by two planes perpendicular to the cylinder. The constraints would specify those points on the cylindrical surface which lie above the lower plane and below the upper plane. As a matter of terminology, I will use the term quadric section to refer to a quadric surface along with a set of constraints on that surface. In order to use 3dsyn, you must understand the coordinate systems it uses to orient surfaces and sections. Theoretically, you could place surfaces wherever you wanted by specifying the appropriate coefficients in the quadric equation 7. In practice, this is a pain since the coefficients are a function of the objects position and orientation as well as its shape. E.g., x2 + y 2 + z 2 = r 2 (4.8) describes a sphere of radius r centered at the origin. The quadric coefficients are A = B = C = 1, K = −(r2 ). Moving this sphere so that its center is at location (x, y, z) = (10, 5, 0) gives: (x − 102 + (y − 5)2 + z 2 = r2 which when put into the form of equation 7 looks like x2 + y 2 + z 2 ?20x?10y + (125?r)2 = 0. (10) Rotating an object affects the quadric coefficients in a still more complicated way. 3dsyn allows you to specify a surface using any coordinate system you desire; you may then translate or rotate the object to move it to a different coordinate system. 3dsyn uses several different coordinate systems to ease the task of creating images which are composed of multiple surfaces. Figure 3.1 shows the various coordinate systems used, and are described here in the text. Each surface (including constraints) is defined in terms of its own local coordinate system. Typically you would choose the coordinate system in which it was easiest to describe the shape you want. Each quadric section has its own coordinate system, known as a section or object coordinate system. The latter term is perhaps misleading in that what you think of as an object may actually consist of more than one section. By specifying the relationship between the local coordinate system for each surface in a section to the sections coordinate system, you specify how the various parts of the section fit together. This essentially is used to relate the constraints to the actual surface being synthesized, with the coordinate system of the surface itself (its local system) typically being coincident with the section coordinate system. This is not a requirement though; the surface and its constraints are all placed relative to a common section system, rather than the constraints being placed relative to the local system of the surface. The next higher level coordinate system is the reference or base coordinate system. This is the base coordinate system for the entire image to be synthesized. Its relationship to the object coordinate systems is the same as that of the object to local coordinate systems. By specifying the relative locations of each object coordinate system in the base system, you define how the various quadric sections fit together, and define what the overall image will look like. The highest level coordinate system is the view point coordinate system. This corresponds to the coordinate system for the image array, and hence, the display equipment. 4.2. 3DSYN-SYNTHESIZE DENSITY IMAGES 131 The relation between the view coordinate system and the base coordinate system specifies the position which you are actually seeing the image from. In many cases the two coordinate systems may be coincident, or one merely a translation of the other. Note that the term viewpoint system is somewhat misleading in that this is not a range image; this transform really defines a plane of projection for the image (which is fully described at the level of the base system). The projection plane itself is the xy plane of the viewpoint coordinate system. The image array itself is just a finite piece of this infinite projection plane. Specifically, the origin [x, y, z] = [0, 0, 0] corresponds with the voxel at location [f rame, col, row] = [0, 0, 0] in the image array (which is in one corner of the image). Hence, if you define the objects in your image to lie around the origin (in the base coordinate system), when you display the image you will probably find that all of the objects will lie in one corner of the image, unless you have displaced the base system relative to the viewpoint system. Put simply, the origin of the base system will be in one corner of the image you synthesize unless you make sure to move it - and you may end up not seeing parts of your objects since they will be clipped at the image borders. In 3dsyn, the relation between coordinate systems is expressed in terms of six basic motions: translations along the three coordinate axes, and rotations about the axes. Motions along the axes go by the names of movex, movey, and movez. Rotations about the axes go by the names of rotx, roty, and rotz, or alternatively as yaw, pitch, and roll, respectively. When specifying the relationship between two coordinate systems, the motions are given in terms of the higher coordinate system, i.e., the higher level system is the base system. For example, to specify that the local coordinate system for a constraint has its origin at location (x,y,z) = (10,5,2) in the section coordinate system, you would specify the motion as (movex 10, movey 5, movez 2). Note that you do not specify the motion as (movex -10, movey -5, movez -2), as this would be specifying the origin of the higher system (the section system) in terms of the lower (the local system). This is easy to see for motions which are pure translations, but may provide a source of confusion when rotations are involved. The best way to regard the motions is as being object oriented. Although you are specifying the relationship between two coordinate systems, the lower coordinate system can be regarded as an object in the higher coordinate system (imagine that the lower level system has a cube sitting at its origin, and you are moving the cube around in the higher level system). Initially, the two coordinate systems start out with coincident axes, i.e., the lower system is an object sitting at location (0, 0, 0) in the higher system. If you specify a motion of movex 10, then all objects in the higher level system are displaced 10 units down the x axis. If you specify a motion of roll 20, then all objects swivel around the z axis of the higher system. This is not the same as simply rotating the lower coordinate systems coordinate system by 20 degrees! If the lower systems origin coincides with the higher systems origin, then the effects are the same; however, if the origin points do not coincide, then the lower systems origin will be seen to swing on an arc around the higher systems axis. Hence, the rotation will also cause a translation in two of the axes of the higher system. Figure 3.1 illustrates this, and also shows how the order of motions is 132 CHAPTER 4. IMAGE SYNTHESIS PROGRAMS important. 3dsyn works by reading a file which describes the image to be synthesized. This file contains the quadric coefficients for each surface and constraint (in their own local coordinate system), the density of the material contained within that surface, and movement commands which specify how the coordinate systems are located. 3dsyn reads this specification file and generates the image; when it is done, it prompts for the name of a file to write the image to. The output file is a 3-d IFS format image. The data type for the image will be unsigned byte, with the value of a voxel indicating its density. The format for the image specification file is relatively simple. Figure 3.8 shows a sample specification file; the format (described below), is identical to the description for Qsyn except for the inclusion of density value on each line describing a quadric. It is a text file composed of several blocks. These blocks may contain other blocks within them. At the beginning of the file is a header block which specifies the size (number of frames, rows and columns) of the image to be generated, the number of quadric sections to synthesize, and a set of motions which will translate the reference coordinate system to the view point coordinate system. The motions which specify the relationship between the two coordinate systems are actually an instance of a type of sub-block known as a coordinate transform block, or just transform. These transforms occur in several places, and always have the same format. There are six basic motions which may be specified in a transform block. There are also several complex motions which are simply composites of the basic motions. All of the motions are specified by some keyword describing the motion to perform, followed by the parameters appropriate for that keyword. The six basic motions are those mentioned earlier: movex, movey, movez, rotz (roll), roty (pitch), and rotx (yaw). The movex, movey, and movez commands can also be shortened to x, y, and z. Each motion takes a single argument which is the amount to move or the angle to rotate (in degrees). To specify a complete transform block, you merely specify an arbitrary number of basic motions (in arbitrary order), followed by the keyword end. The basic motions are performed in the order specified. A sample transform block might look like: movex 20 movey 10 pitch 30 end This will shift an object 20 units along the x axis, 10 units in y, and swing the object 30 degrees around the y axis. The composite motions are just shortcuts for specifying certain common sets of motions. The com- bination movex10movey20movez30 can be specified more rapidly as movexyz102030 or just xyz102030. Similarly, rpy102030 is short for roll10pitch20yaw30. All six basic motions can be expressed using the commands rpyt ?z?y?xDeltaxDeltayDeltaz and trpy ?z?y?xxyz. Rpyt does the rotations first, then the translations; trpy performs the translations first. Note that the syntax for trpy is inconsistent in that although the translations are performed first, they are the last arguments specified for the command. After the header block there comes a set of section blocks, one block for each quadric section to synthesize. Each block describes a surface to generate, and all the constraints for the surface. The quadric section blocks are in turn composed of smaller blocks. The first sub-block is a transform block which converts from the section coordinate system to 4.3. MATTE - SYNTHESIZE LUMINANCE IMAGES 133 32 32 32 7 rpyt 0.0 0.0 0.0 15.0 15.0 15.0 end end 0.7164 0.4030 0.4030 0 0 0 0 0 0 -87.3151 255.0 0.0 end 0 rpyt 0.0 0.0 0.0 0.0 -0.2944 -0.2944 end 0.5835 0.3352 0.3352 0 0 0 0 0 0 -65.5430 -255.0 0.0 end 0 rpyt -18.0 0.0 0.0 3.52 0.0 0.0 end 0.00923521 0.00116281 0.00116281 0 0 0 0 0 0 -0.028607 31.0 end 0 rpyt 18.0 0.0 0.0 -3.52 0.0 0.0 end 0.02825761 0.00430336 0.00430336 0 0 0 0 0 0 -0.1851891 31. rpyt 0.0 0.0 0.0 0.0 5.6 0.0 end 0.00390625 0.00275625 0.00275625 0 0 0 0 0 0 -0.04410 23.0 0.0 end 0 rpyt 0.0 0.0 0.0 0.0 1.6 0.0 end 1.0 1.0 1.0 0 0 0 0 0 0 -0.541696 47.0 0.0 end 0 rpyt 0.0 0.0 0.0 0.0 -1.6 0.0 end 1.0 1.0 1.0 0 0 0 0 0 0 -0.541696 47.0 0.0 end 0 Figure 13: Figure3.8: Example 3Dsyn input file (A synthetic head) the base coordinate system. This is followed by a surface block. A surface block contains a set of quadric coefficients to describe a single quadric surface, the interior and exterior densities of the object, and also contains a transform block which translates the surfaces local coordinate system to the section coordinate system. After the surface block comes the number of constraints, followed by a set of constraint blocks. A constraint block is identical to a surface block except that it contains a flag indicating which way the constraint inequality goes (e.g., choose all points in the surface below some plane). 4.3 Matte - synthesize luminance images CONVERSION TO LATEX NOT FINISHED Name: matte.c Action: Produces a matte luminance image given a range image and one or more light sources of any brightnesses. That is, the range image is modeled as being a Lambertian reflector. matte converts a 2-D range image into a matte luminance image. USAGE: usage: matte -i infile -o outfile -s FLAGS: command line args are... -h help-screen -i Input file name -o output file name -s Ignore shadowing LIGHTS: This program generates a matte image illuminated by a set of light sources that you specify. The user is prompted for the locations of the light sources. Notes • Comments (like in the example) aren’t allowed • Be careful with the z coordinate. Large positive z values place the light source in front of the object: good. Negative z, or even small positive z, may place the light BEHIND the object: (bad), which may generate a null image. • 50 lights max. 134 CHAPTER 4. IMAGE SYNTHESIS PROGRAMS Example: matte -i pcblead.ifs -o leadbrightness.ifs Enter number of light sources>2 For each source, enter position (col,row,height) and brightness>64 64 200 10 20 30 200 2 ALGORITHM Read lights from user (or redirect of standard input) call ifsderiv to compute gradients of range image for every pixel Compute normal to this pix; Compute vector from this pix to each light; Compute cosine of angle between normal and lights; Light this pix by summing the source brightness times the cosine. 4.4 Tomosim - simulate tomographic X-ray source CONVERSION TO LATEX NOT FINISHED This program is used to simulate a 3-D beam tomographic sensor. Either cone-beam or parallel- beam sensors may be simulated. An ifs 3D image is used as input (as produced, for example, by 3dsyn). The program produces a set of ifs 2D images, where each of the output images corresponds to one projection USAGE: tomosim inputimage numofpoints radius detector rows detector cols¡-o¿ ¡-d n¿ IFSIMG input image; int numofpoints; /*center int radius; /*three dimensional*/ /*The number of points around a 360 degree circle,*/ /*centered at the*/ of the volume specified by the input image*/ /*The distance (in voxels) from the center of the*/ /*volume to the detector. Will be treated as*/ /*identical as the distance from the */ /*center of the volume to the center of the detector array*/ int detector rows; /*number of rows on the detector*/ int detector cols; /*number of columns on the detector*/ The names of the output files are read from stdin as they are needed. Since the program may take quite a while to run, manually typing these names is tedious. The recommended way to run the program is to first create a file containing the names of all the output image files, and then to run tomosim redirecting stdin to this file. Switches -o The -o switch, if used, will use parallel-beam (orthographic) rather than cone beam projection -d The -d switch, if used, means that the next argument will be the debug control value (really only of interest to the programmer) Application: For cone beam, just specify the number of points. The sensor rotates in x-y plane, about an origin at the center of the 3D volume provided. For fan beam, simply specify a detector with only one row. The -o switch provides parallel beam simulation in either single row or multiple row cases. Chapter 5 Programs for processing images The following is a list of programs which exist in the ifs bin directory. (Depending of local installations, this is usually /usr/local/bin/ifs) These programs are for the most part, simply mains wrapped around some of the standard subroutines documented in earlier chapters. These programs are only documented briefly here, since the operation is generally obvious. Generally, on-line help for any program can be obtained by simply starting that program up, but providing it an incorrect number of arguments. Most programs also support the -h switch. For example, add -h will tell you how to use add. Most programs us the -x switch convention. For example, program -i infilename -o outfilename 5.1 add add two ifs images, point by point Author: Wes Snyder 5.2 addhdr adds an IFS header to a raw data file. rmvhdr is the reverse function. Perpetrator: Mark Lanzo 5.3 atoi Converts an ascii file to ifs. Input file is to be in the format produced by itoa using the -v switch. The -v switch on itoa adds two lines at the beginning of the file which specifies the 135 136 CHAPTER 5. PROGRAMS FOR PROCESSING IMAGES size and data type. Author: Wesley Snyder example: Image has 4 rows and 4 columns Data format is u8bit 0 0 0 0 0 1 0 0 0 0 2 0 0 0 0 0 /end{verbatim} Usage: \begin{verbatim} atoi imga.txt imga.ifs Note this program does not use the -i -o convention. 5.4 any2any convert data types Converts any IFS image to or from (almost) any other data format including other ifs data types usage: any2any [switches] -i inputfile.ifs -o outputfile.xxx -d datatype switches are datatype is an ifs data type, such as byte, ubyte, char, uchar, u8bit, short, ushort, u16bit, int, float 32flt, double, 64flt, etc. For other file types, such as bmp, jpg, png, etc, the type is determined by the file name. If outfile is not ifs, dtype IS required to be uchar, (for this version), even if neither in nor out is ifs. Examples: convert an ifs image of some unspecified data type to an ifs image of type float any2any -i startrack.ifs -o startrackfloat.ifs -d float convert an ifs image of unspecified data type to png. Note that this may not work if the input if 3-D. any2any -i startrack.ifs -o startrack.png -d uchar convert a jpeg input image to a float ifs image. any2any -i lena.jpg -o lenafloat.ifs -d float 5.5. C2IMAG 5.5 137 c2imag take imaginary part of an ifs image, point by point Author: Wesley Snyder 5.6 c2mag take magnitude of an ifs image, point by point Author: Wesley Snyder 5.7 c2phase take phase of an ifs image, point by point Author: Wesley Snyder 5.8 c2real take real part of an ifs image, point by point Author: Wesley Snyder 5.9 compmag produces an ifs file (type float) equal to the log of the square of the magnitude of a complex image Victim: Wesley Snyder 5.10 ChooseFrame Select a single frame from an image. This is particularly useful for images which have been read as color (say, JPEG) and you wish to store a single frame of the RGB image. ChooseFrame -i inputimage -o outputimage -f framenumber The default frame number is zero. 5.11 gauss add Gaussian-distributed noise to an image Switches: -i inputfilename -o outputfilename -m mean -s stddev -n (no argument) - don’t allow negative values for noise -w (no argument) -don’t allow overflows (wrap arounds) e.g. adding a value of 3 to an 8bit 138 CHAPTER 5. PROGRAMS FOR PROCESSING IMAGES pixel with value of 254 will produce a pixel with value of 1 -S IntegerSeedForRandomNumGen (normally dont use this) 5.12 ifsDoG Apply a derivative of Gaussian kernel to an ifs image usage: ifsDoG [switches] switchs are -i infilenname, where infilename is an ifs image default: the null string -o outfilenname, where outfilename is an ifs image default: the null string -s sigma, std. dev of the filtering Gaussian default: sqrt of 3.0 -O order of the derivative zero is blur with the Gaussian, one is first deriv, etc, up to 3rd deriv direction. -d This flag is the letter c for col, r for row, b for both default: columns b option only valid for second deriv example: ifsDoG -i myfile.ifs -o outfile.ifs -O 0 -d r 5.13 itoa converts an image to printable ASCII. The output is written to the terminal. Output can be redirected to a file using the Unix redirect command. Examples: 1) to output an image to the screen: itoa site14.c.ifs 2) to ouptut an image to a file itoa site14.c.ifs > site14.c.txt 3) to output an image to a file with a prefix specifying the rows, columns, and data type itoa -v site14.c.ifs If the -v switch is used the first two lines output will look like this: Image has 48 rows and 32 columns Data format is 16bit Author: Mark Lanzo 5.14. MKDOC 5.14 139 mkdoc makes a LaTeX compatible version of this index on standard out. Author: Wesley Snyder 5.15 mult multiply two ifs images, point by point Author: Wesley Snyder 5.16 profile Take a cross section of an IFS 2D image. Output is in standard plot filter format (to stdout). Author: Mark Lanzo 5.17 prthdr Print the header structure for an IFS image (in human readable format). Author: Mark Lanzo 5.18 rmvhdr Remove the header from an IFS image to yield a raw data file. Author: Mark Lanzo 5.19 subsample subsamples an arbitrary ifs image to be of a speci ed size: Author: Wesley Snyder 5.20 recip take reciprocal of an ifs image, point by point Author: Wesley Snyder 5.21 sub subtract two ifs images, point by point Author: Wesley Snyder 140 5.22 CHAPTER 5. PROGRAMS FOR PROCESSING IMAGES triangulate Find an optimal set of triangles which completely covers a set of points. Usage: triangulate inputimage outputimage (Note that this program, at this time, does not use the standard -i, -o designation for arguments. Therefore, the order of the arguments IS important.) This program accepts an input file, a standard text file, which contains the set of row, column coordinates of vertex points. The output file will contain descriptions of triangles which cover that set of points. 5.22.1 Input File Format First line, the number of vertices all other lines, row, column pair example: 4 0 1 1 0 0 0 10 10 5.22.2 Output File Format First line: number of triangles found. all other lines, row, col coordinates of the vertices in this triangle example: 2 0 10 0 0 1 0 1 0 1 10 0 10 5.23 vidscale video scale an ifs image, that is, produce an output image which is the same size as the input image, but scaled to be between 0 and 255, and be unsigned char. vidscale -i infile.ifs -o outfileu8bit.ifs -s 5.24. WINDOW 5.24 141 window This program extracts a window from an ifs image. The resultant output image is of the same data type as the input. Usage: window input output xleft ylower xright yupper input and output are two dimensional ifs image files. Output will be created by this program. xleft is the index of the left-most column of the input image which should be in the window. ylower is the index of the lowest-index row of the desired window. xright and yupper are the other extremes. NOTE: yupper must be greater than ylower. Thus, upper and lower correspond to indices, not to a top-bottom relation on a display screen. Author: Wesley Snyder 5.25 zoomupdown This is a program which is really just a wrapper called the iptools function by the same name. Usage: zoomupdown inputimage outputimage numrowsofOutputImage numcolsofOutputImage Program will read the input image and will create an output image with the specified number of rows and columns. Then the input image will be resized to be of the specified number of dimensions. No interpolation is done across frames, in the case of 3D images. If you need to do that, use squp. If the input image is 3D, and has 3 frames, it will be treated as if it were color. 142 CHAPTER 5. PROGRAMS FOR PROCESSING IMAGES Chapter 6 Programs for Analyzing Images In this section, programs are provided which do image analysis. 6.1 Harris-Laplace This program reads an image file and computes the output of the Harris corner detector over scale, and applies a Laplacian over the same range of scales. Usage: HarrisLaplace [switches] Switches are: -i inputfilename -H Harris measure out. Default: HarrisMeasure.ifs -L Laplace measure out. Default: LaplaceMeasure.ifs The output images are ifs 3D images, data type of these images is float. 6.2 PCON - Piecewise-constant image noise removal This program does Edge-preserving smoothing and noise removal using a piecewise-constant prior. USAGE: pcon [switches] . Switchs are -g input filenname, where infilename is an ifs image; default: the null string -s sigma The std dev of the noise. default: 1.0 -r r step size, smaller is more stable but slower. default: 0.02 143 144 CHAPTER 6. PROGRAMS FOR ANALYZING IMAGES -b b The coefficient in front of the prior term. Beta of Eq. 6.41 in Snyder and Qi -t t1 initial temperature. default: 2.0 -T t2 final temperature default: 0.0005 -l dlt rate by which the temperature drops. default: 0.99 -o outcount output a temporary file every this many iterations. default: 50 example: pcon -g foofile.ifs -s 3 SEE Snyder and Qi, Machine Vision, Cambridge University Press, 2005, Equation 6.41. This program works by finding the image f which minimizes X (fij − gij )2 −|∇|ij bX − (6.1) exp 2σ 2 τ 2τ 2 ij ij where g is a measured image, σ is the standard deviation of the noise, and the notation |∇fij | denotes some scalar measure of the image gradient in the vicinity of pixel ij. There are five parameters to this program: • sigma which is the standard deviation of the (assumed additive, Gaussian, white) noise. • b, the strength of the second term, relative to the first. The second term is called the “prior” term, since it is a function of only the (unknown) true imagef and not of the measured, noisy image g. • τinitial is the initial value of τ . In most literature, the variable τ is called the temperature because the algorithm bears similarity to the process of annealing in metallurgy. The algorithm implemented in pcon is an approximation to simulated annealing, called “mean-field annealing.” The optimal value of τiniital is problem dependent, but a good approximation can be found by performing the following analysis: Find the largest pixel-to-adjacent-pixel difference which should be considered noise and not an edge. Set τiniital to twice that value. • τf inal is the final of τ at which the algorithm will stop. I suggest you allow the temperature difference be two-to-four orders of magnitude. E.g., if τinitial is 10.0, τf inal should be something like 0.01. • λ is the rate of decrease of temperature. The program uses a geometric annealing schedule (as opposed to a logarithmic schedule) following τ = λτ . A good value is typically 0.99. Values closer to one (e.g. 0.999) will run slower but give better results. Example:6.1 illustrates a noisy image, a cardiac angiogram, to which pcon is applied to produce figure 6.2. Notice that some bright points are preserved. These are points where the random noise was sufficient to make the pixel-to-pixel difference significantly larger than τinitial , therefore these points are considered by the algorithm to be edges and are 6.2. PCON - PIECEWISE-CONSTANT IMAGE NOISE REMOVAL Figure 6.1: Input image Figure 6.2: Piecewise-constant image 145 146 CHAPTER 6. PROGRAMS FOR ANALYZING IMAGES Figure 6.3: Profile across an artery, showing the piecewise-constant property of the solution not removed. The profile illustrated in Figure 6.2 across one of the arteries in the output shows the piecewise- constant result. The implementation of PCON is optimized for speed, using pointer arithmetic and other programming hacks. 6.3 PLIN - Piecewise-linear image noise removal This program does Edge-preserving smoothing and noise removal using a piecewise-linear prior. USAGE: plin -i infile [-s sigma] [-r stepsize] [-b priorgain] [-t initialtemp] [-T finaltemp] [-l dlt] [-o n] Once the program is running, it will prompt the user for control variables, these are listed below, along with good values to use sigma: The std dev of the noise. default 1.0 r,step size, smaller is more stable but slower. default is 0.02 b, The coefficient in front of the prior term. Beta of Eq. 6.41 in Snyder and Qi, good value is .5 t, initial temperature. default 2.0 6.3. PLIN - PIECEWISE-LINEAR IMAGE NOISE REMOVAL 147 t2, final temperature default 0.005 lambda: rate by which the temperature drops. good value : 0.99 n: used with the -o switch. The program will output a temporary image every n iterations example: plin -i G SEE Snyder and Qi, Machine Vision, Cambridge University Press, 2005, Equation 6.41. This program works by finding the image f which minimizes X (fij − gij )2 −|∇2 |ij bX − exp 2σ 2 τ 2τ 2 ij (6.2) ij where g is a measured image, σ is the standard deviation of the noise, and the notation |∇fij | denotes some scalar measure of the image gradient in the vicinity of pixel ij. There are six parameters to this program: • sigma which is the standard deviation of the (assumed additive, Gaussian, white) noise. • r, The step size of the gradient descent term. • b, the strength of the second term, relative to the first. The second term is called the “prior” term, since it is a function of only the (unknown) true imagef and not of the measured, noisy image g. • τinitial is the initial value of τ . In most literature, the variable τ is called the temperature because the algorithm bears similarity to the process of annealing in metallurgy. The algorithm implemented in pcon is an approximation to simulated annealing, called “mean-field annealing.” The optimal value of τiniital is problem dependent, but a good approximation can be found by performing the following analysis: Find the largest pixel-to-adjacent-pixel difference which should be considered noise and not an edge. Set τiniital to twice that value. • τf inal is the final of τ at which the algorithm will stop. I suggest you allow the temperature difference be two-to-four orders of magnitude. E.g., if τinitial is 10.0, τf inal should be something like 0.01. • λ is the rate of decrease of temperature. The program uses a geometric annealing schedule (as opposed to a logarithmic schedule) following τ = λτ . A good value is typically 0.99. Values closer to one (e.g. 0.999) will run slower but give better results. 148 CHAPTER 6. PROGRAMS FOR ANALYZING IMAGES Figure 6.4: Piecewise-linear image Example:6.1 illustrates a noisy image, a cardiac angiogram, to which plin is applied to produce figure 6.4. Notice that some bright points are preserved. These are points where the random noise was sufficient to make the pixel-to-pixel difference significantly larger than τinitial , therefore these points are considered by the algorithm to be edges and are not removed. The profile illustrated in Figure 6.5 across one of the arteries in the output shows the piecewise- linear result. The implementation of PLIN is optimized for speed, using pointer arithmetic and other programming hacks. 6.4 WaterSheds The program WaterShed is a wrapper around the function ifs WaterShed, allowing the function to be called from the command line. In addition, the user may select several post-processing features. Usage: WaterShed -i infilename -o outfilename -c connectedtype [-C filename] [-n filename] outfile will contain watershed points -c is connection type, either 4-connected or 8-connected. -C file will be in color -n file will not have watershed points 6.5. CCL CONNECTED-COMPONENT LABELING 149 Figure 6.5: Profile across an artery, showing the piecewise-linear property of the solution The input image must be unsigned char ifs image. The output image will be int. The program first finds all minima in the image and assigns each a label. Those labels become the labels of regtions. Figure 6.6 illustrates an image, with a surround which is minimal, a brightness which grows positive and then drops in two places (a volcano with a vent). Figure ?? shows the watershed output, illustrating the presence of watershed pixels. Figure 6.7 illustrates a labeling with all the watershed pixels assigned to regions, and Figure ?? shows a color labeling of that image. 6.5 ccl Connected-component Labeling This program uniquely labels the connected components of an ifs image. It uses the algorithm described in Snyder and Qi, Machine Vision, Cambridge University Press, 2005. This program only supports images in the following data types: unsigned char, short, and float. Switches: -h : print out this message -i <input_image_file_name> -o <output_image_file_name> This will be the label image, in which is stored at each pixel -p <parameter_file_name> (optional) -l <lower limit for labeling region> (default 0) Normally this is the background -u <upper limit for labeling region> (default 255) -[f|e|v] : use face/edge/vertex connectivity (default face) 150 CHAPTER 6. PROGRAMS FOR ANALYZING IMAGES Figure 6.6: Left:Original image (Volcano with a vent and a zero surround) Right: watershed segmentation showing watershed pixels Figure 6.7: Left:Region Labeling with watershed pixels assigned to regions. Right: Region Labeling in pseudocolor, using a random color map 6.6. RESAMPLE CURVE 151 -t <threshold for connectivity> (two pixels which differ by more than this will not be merged-(default 2) -s <row> <column> <frame> (Seed Location of Region of Interest) Normally, ROIs are not used. -r <label of ROI> (default 1) -g : outimg is ROI_seg_out image (default label image) -j <pixel value for ROI_seg\_out image > (default 128) -a <upper background label> (default 0) -b <lower background label> (default 0) -m <minimum label used> (default 0) -x <maximum label used> (default 32767) -c <Size of the content-addressable memory used to resolve equivalent region labels.> (default 4096) ccl is a wrapper around the function ifs ccl. It parses the command line, fills in the structure used by ifs ccl, initializes some things, and then calls ifs ccl. If you need to call connected components from inside a program, see the description of the function ifs ccl. See the documentation for ifs ccl for additional documentation, including figure 3.1 which defines the types of connectivity. 6.6 resample curve The program resample is simply a wrapper for resampleinit and resamplesub. See section 3.1.6. It resamples a discrete curve and returns a set of points equally far apart (arc-length sampling). usage: resample -i infile -o outimage -n numpoints inputfile is an ascii file of x-y pairs. the first line is a sharp sign, a space, and the number of pairs, e.g. # 798 The output file will be written in the same format, but the numbers will be float 152 CHAPTER 6. PROGRAMS FOR ANALYZING IMAGES Chapter 7 Programs for Viewing IFS images 7.1 ColorMap The program ColorMap allows you to assign a number of different colors to an 8-bit, unsigned image. That is, each of the possible 256 brightness levels will be assigned a color. There are many ways to assign an R, G, and B value to a single pixel brightness. The program offers several different ways to interpret the brightnesses. Usage: ColorMap -i inputfile.ifs -o outputfile.ifs -m X -f Y Where inputfile is an ifs image. and X is an integer between 0 and 6 which tells the program which color map to use: 0 grey scale 1 inverse gray scale 2 bronson 3 hot metal 4 heated spectrum 5 log 6 random The input image may be any ifs format, however, if it is not unsigned 8 bit, the user will get a warning message that only brightnesses between 0 and 255 will be mapped. If the user has this problem, he or she should probably use vidscale to convert the darkest-brightest values to 0-255. Should the input file be 3D, the program will convert frame 0 by default. Using the -f switch, the frame to be converted can be selected. The output file will the 3 D ifs image, with 3 frames, with the usual interpretation that frame 0 is red, frame 1 is green, and frame 2 is blue. 153 154 7.2 CHAPTER 7. PROGRAMS FOR VIEWING IFS IMAGES Eigenimages Program to find the principal eigenimage of a set of images. The program will optionally also calculate the projection of another image onto the principal eigenimage. Usage: Eigenimage -c controlfile -o outfile [-t projfile] The control file contains a single number (number of files followed by a list of file names, one per line. Example: 2 file1.ifs file2.ifs file3.ifs The output file is an ifs image of the principal eigenimage. The -t switch allows the user to specify the name of a file to project onto the eigenimage, and measure the length of the projection All images must have the same dimensions. 7.3 ifsview – view ifs images This is a new program with ifs release 8. It supercedes wxifsview, which may still run on some computers. The application ifsview provides the ability to view, zoom, or probe ifs images. It uses the openCV software system. To run ifsview, use the following command: ifsview -i image [-c] [-I ignoreswitch] [-s] image is the input image. image can be any format of ifs, or jpg, tiff, bmp, and png. If ifs, it can be monochromatic or color. If monochromatic, it may have two or three dimensions. colorswitch The optional color switch, if it exists, tells ifsview that if the input image happens to be three dimensional and have three frames, it should be displayed as a color image, rather than a 3D image. ignoreswitch If this brightness is entered, then any pixels of this value will not enter the calculation of contrast. -s If the -s switch is present, frames in a 3D image with be brightness-scaled independently. Otherwise, the brightest and darkest points in the entire image will be used for scaling. Once you have started up ifsview, you have a variety of options: 7.3. IFSVIEW – VIEW IFS IMAGES 155 • LOUPE As soon as the image pops up, and you move the mouse over it, another image will pop up which is a zoomed version of the original image, zoomed about where the mouse is. We will refer to this second image as the “loupe” image, as in a jewler’s loupe. As you move the mouse, the second image will move around also. • stopping the tracking A right click on the original image will freeze the loupe image. A second right click will turn tracking back on. On the mac, a right click is accomplished by hitting the trackpad with two fingers simultaneously. • Additional zoom With the pointer on the original image, you can use right and left arrow keys to increase or decrease zooming (respectively). Note that you will not see the result of the zoom until you move the mouse again, which will refresh the loupe image. • Image values – original image Clicking on the original image will return the brightness at the point of the click, or if color, will return the R,G,B values. • Image values – loupe image To look at points in great detail, first move the mouse to get to where you want to be in the original image. Then right click to turn off tracking. Move the pointer to the loupe image, and click on any point. The brightness or color of that point will be returned. • Exploring 3D images With the mouse on the original image (tracking can be on or off), the up and down arrow will display different frames of the 3D image. Remember that these values don’t show up in the loupe image until you move the mouse. On some computers, the arrow keys don’t work with this application. As an alternative to the arrow keys, you can use m i j k c control-c L l frame up frame down zoom down zoom up toggle contrast enhancement on/off exit program increase size of loupe image decrease size of loupe image • Contrast enhancement The lower-case c key will toggle contrast enhancement of the loupe image on and off. Should you simply wish to display an image and obtain information about it, use the program ifsview, which is just a wrapper around ifsCVPopup, and that way, you won’t need to mess with linking openCV, which can be a painful hassle. IMPORTANT NOTE ABOUT ifsview: 156 CHAPTER 7. PROGRAMS FOR VIEWING IFS IMAGES ifsview uses the openCV functions. OpenCV supports ONLY dynamic libraries. This means you must either have openCV installed on your computer, or you must have the openCV libraries available, even though you actually aren’t writing any software that will use them. We tried (unsuccessfully) to get openCV to generate static libraries so it would be portable, but we failed, and learned from web conversations that it does not seem to be possible. The openCV libraries are in the ifslib that you downloaded. 7.4 makecolor This program accepts a 2D ifsimage as input and produces a jpg, png, or other output. This is necessary because ifs uses openCV to convert images from ifs to other format. openCV thinks all jpg, png, etc. images are color, so if you give it an input which is a 2D image, it will fail, producing an output which is not readable. Usage: example: makecolor -i input.ifs -o output.ifs 7.5 PlayMovie- play a 3D ifs image as a movie Plays a 3d ifs image as a movie Usage:PlayMovie [arguments] switches are -i inputfile.ifs -z floating point zoom factor. Will zoom image prior to playing. Default: 1.0 -h this usage -s time (in microseconds) to delay between frames (minimum 1, max 999999). If the argument of the -s switch is greater than 1,000,000, the program will wait for the user to hit a key before going to the next frame. -d direction if direction is 0, the movie will be played forward, if 1, backward, if 2 forward then back. This program is just a wrapper around CreateIFSDisplayWindow and WriteToIFSDisplayWindow. It plays a 3D image as a movie with controllable zoom and speed. IMPORTANT NOTE ABOUT PlayMovie: PlayMovie uses the openCV functions. OpenCV supports ONLY dynamic libraries. This means you must either have openCV installed on your computer, or you must have the openCV libraries available, even though you actually aren’t writing any software that will use them. We tried (unsuccessfully) to get openCV to generate static libraries so it would be portable, but we failed, and learned from web conversations that it does not seem to be possible. The openCV libraries are in the ifslib that you downloaded. 7.6. PLOTCONTOUR 7.6 157 Plotcontour Plotcontour: a program which will plot a 1D contour into an ifs image. The contour will be white on a black background. usage: plotcontour -i infile -o outimage -s scale -r imagerows -c imagecols infile is an ascii file of x,y point pairs, the first line of which is sharp sign, space, number of points e.g. # 799 On each following line, the format is ”x y” Normally, x is columns and y is rows example: # 4 0 200 200 0 0 0 200 200 the outimage file is the name of an ifs file containing white dots on a black background optional argument scale will multiply x and y coords by scale optional arguments imagerows, imagecols will force the image output to be that size. Note that if the points go off the image, they will be clipped. the -p switch will write precisely the coordinates specified in the file. 7.7 C2LaTeX-convert source code to LaTeX This program allows the user to include his/her source code into a LaTeX document. Any line which starts with //l(the ell character) will not only be a comment to C or C++, but allows the user to include any LaTeX command at all. (Well, almost any). The exception is you may not include the string \end{verbatim} You may of course, use the \textbackslash with no problem. You might also consider using the listing environment rather than the verbatim environment. Usage: C2LaTeX -i inputfile.c -o outputfile.tex -m ValueOrFilename 158 CHAPTER 7. PROGRAMS FOR VIEWING IFS IMAGES if the -m switch as a value of zero: (e.g. below) C2LaTeX -i inputfile.c -o outputfile.tex -m 0 Then the output LaTeX file will not contain a header (the stuff before the \begin{document}) or the \end{document} . This is particularly useful if you intend to include or input this LaTeX file into another file. If it is to be stand-alone, the -m switch should specify the name of the header file you want the program to use, e.g.: C2LaTeX -i inputfile.c -o outputfile.tex -m myheader.tex
© Copyright 2024