1 /* 2 Copyright (c) 2011-2021 Timur Gafarov 3 4 Boost Software License - Version 1.0 - August 17th, 2003 5 6 Permission is hereby granted, free of charge, to any person or organization 7 obtaining a copy of the software and accompanying documentation covered by 8 this license (the "Software") to use, reproduce, display, distribute, 9 execute, and transmit the Software, and to prepare derivative works of the 10 Software, and to permit third-parties to whom the Software is furnished to 11 do so, all subject to the following: 12 13 The copyright notices in the Software and this entire statement, including 14 the above license grant, this restriction and the following disclaimer, 15 must be included in all copies of the Software, in whole or in part, and 16 all derivative works of the Software, unless such copies or derivative 17 works are solely in the form of machine-executable object code generated by 18 a source language processor. 19 20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 DEALINGS IN THE SOFTWARE. 27 */ 28 29 /** 30 * Morphologic filters 31 * 32 * Copyright: Timur Gafarov 2011-2021. 33 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0). 34 * Authors: Timur Gafarov 35 */ 36 module dlib.image.filters.morphology; 37 38 import dlib.image.color; 39 import dlib.image.image; 40 import dlib.image.arithmetics; 41 42 /// Morphologic operation 43 enum MorphOperation 44 { 45 Dilate, 46 Erode 47 } 48 49 /// Apply morphologic operation 50 SuperImage morphOp(MorphOperation op)(SuperImage img, SuperImage outp) 51 in 52 { 53 assert(img.data.length); 54 } 55 do 56 { 57 // TODO: 58 // add support for other structuring elements 59 // other than box (disk, diamond, etc) 60 61 SuperImage res; 62 if (outp) 63 res = outp; 64 else 65 res = img.dup; 66 67 uint kw = 3, kh = 3; 68 69 foreach(y; 0..img.height) 70 foreach(x; 0..img.width) 71 { 72 static if (op == MorphOperation.Dilate) 73 { 74 Color4f resc = Color4f(0, 0, 0, 1); 75 } 76 static if (op == MorphOperation.Erode) 77 { 78 Color4f resc = img[x, y]; 79 } 80 81 foreach(ky; 0..kh) 82 foreach(kx; 0..kw) 83 { 84 int iy = y + (ky - kh/2); 85 int ix = x + (kx - kw/2); 86 87 // Extend 88 if (ix < 0) ix = 0; 89 if (ix >= img.width) ix = img.width - 1; 90 if (iy < 0) iy = 0; 91 if (iy >= img.height) iy = img.height - 1; 92 93 // TODO: 94 // Wrap 95 96 auto pix = img[ix, iy]; 97 98 static if (op == MorphOperation.Dilate) 99 { 100 if (pix > resc) 101 resc = pix; 102 } 103 static if (op == MorphOperation.Erode) 104 { 105 if (pix < resc) 106 resc = pix; 107 } 108 } 109 110 res[x, y] = resc; 111 } 112 113 return res; 114 } 115 116 /// Ditto 117 SuperImage morph(MorphOperation op) (SuperImage img) 118 { 119 return morphOp!(op)(img, null); 120 } 121 122 /// Dilate 123 alias dilate = morph!(MorphOperation.Dilate); 124 /// Erode 125 alias erode = morph!(MorphOperation.Erode); 126 127 /// Morphologic open 128 SuperImage open(SuperImage img) 129 { 130 return dilate(erode(img)); 131 } 132 133 /// ditto 134 SuperImage open(SuperImage img, SuperImage outp) 135 { 136 if (outp is null) 137 outp = img.dup; 138 auto outp2 = outp.dup; 139 140 auto e = morphOp!(MorphOperation.Erode)(img, outp2); 141 auto d = morphOp!(MorphOperation.Dilate)(outp2, outp); 142 outp2.free(); 143 return d; 144 } 145 146 /// Morphologic close 147 SuperImage close(SuperImage img) 148 { 149 return erode(dilate(img)); 150 } 151 152 /// ditto 153 SuperImage close(SuperImage img, SuperImage outp) 154 { 155 if (outp is null) 156 outp = img.dup; 157 auto outp2 = outp.dup; 158 159 auto d = morphOp!(MorphOperation.Dilate)(img, outp2); 160 auto e = morphOp!(MorphOperation.Erode)(outp2, outp); 161 outp2.free(); 162 return e; 163 } 164 165 /// Morphologic gradient 166 SuperImage gradient(SuperImage img) 167 { 168 return subtract(dilate(img), erode(img)); 169 } 170 171 /// ditto 172 SuperImage gradient(SuperImage img, SuperImage outp) 173 { 174 if (outp is null) 175 outp = img.dup; 176 auto outp2 = outp.dup; 177 178 auto d = morphOp!(MorphOperation.Dilate)(img, outp2); 179 auto e = morphOp!(MorphOperation.Erode)(img, outp); 180 auto s = subtract(d, e, outp); 181 outp2.free(); 182 return s; 183 } 184 185 /// White top-hat transform 186 SuperImage topHatWhite(SuperImage img) 187 { 188 return subtract(img, open(img)); 189 } 190 191 /// ditto 192 SuperImage topHatWhite(SuperImage img, SuperImage outp) 193 { 194 if (outp is null) 195 outp = img.dup; 196 auto o = open(img, outp); 197 auto s = subtract(img, o, outp); 198 return s; 199 } 200 201 /// Black top-hat transform 202 SuperImage topHatBlack(SuperImage img) 203 { 204 return subtract(img, close(img)); 205 } 206 207 /// ditto 208 SuperImage topHatBlack(SuperImage img, SuperImage outp) 209 { 210 if (outp is null) 211 outp = img.dup; 212 auto o = close(img, outp); 213 auto s = subtract(img, o, outp); 214 return s; 215 }