1 /* 2 Copyright (c) 2013-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 * 2D signal consisting of complex number data 31 * 32 * Copyright: Timur Gafarov 2013-2021. 33 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0). 34 * Authors: Timur Gafarov 35 */ 36 module dlib.image.signal2d; 37 38 private 39 { 40 import dlib.core.memory; 41 import dlib.math.vector; 42 import dlib.math.complex; 43 import dlib.math.fft; 44 import dlib.image.image; 45 import dlib.image.color; 46 } 47 48 /// Signal domain 49 enum SignalDomain 50 { 51 Spatial, 52 Frequency 53 } 54 55 /** 56 * 2D signal consisting of complex number data 57 */ 58 class Signal2D 59 { 60 Complexf[] data; 61 uint width; 62 uint height; 63 SignalDomain domain = SignalDomain.Spatial; 64 65 this(uint w, uint h) 66 { 67 width = w; 68 height = h; 69 data = New!(Complexf[])(width * height); 70 } 71 72 this(SuperImage img, uint channel) 73 { 74 width = img.width; 75 height = img.height; 76 data = New!(Complexf[])(width * height); 77 78 foreach(y; 0..height) 79 foreach(x; 0..width) 80 { 81 auto col = img[x, y]; 82 size_t index = (y * width + x); 83 data[index].re = col.vec[channel]; 84 data[index].im = 0.0f; 85 } 86 } 87 88 ~this() 89 { 90 Delete(data); 91 } 92 93 void fft() 94 { 95 foreach(y; 0..height) 96 foreach(x; 0..width) 97 { 98 if (((x + y) & 0x1) != 0) 99 { 100 size_t index = (y * width + x); 101 data[index].re = data[index].re * -1; 102 data[index].im = data[index].im * -1; 103 } 104 } 105 106 fft2(true); 107 domain = SignalDomain.Frequency; 108 } 109 110 void fftInverse() 111 { 112 if (domain != SignalDomain.Frequency) 113 return; 114 115 fft2(false); 116 domain = SignalDomain.Spatial; 117 118 foreach(y; 0..height) 119 foreach(x; 0..width) 120 { 121 if (((x + y) & 0x1) != 0) 122 { 123 size_t index = (y * width + x); 124 data[index].re = data[index].re * -1; 125 data[index].im = data[index].im * -1; 126 } 127 } 128 } 129 130 void multiply(Signal2D img, Signal2D dest) 131 { 132 assert(img.width == width && img.height == height && dest.width == width && dest.height == height); 133 134 dest.domain = domain; 135 136 foreach(i, v; data) 137 { 138 dest.data[i] = v * img.data[i]; 139 } 140 } 141 142 void divide(Signal2D img, Signal2D dest) 143 { 144 assert(img.width == width && img.height == height && dest.width == width && dest.height == height); 145 146 dest.domain = domain; 147 148 foreach(i, v; data) 149 { 150 if (img.data[i].re == 0.0f) 151 dest.data[i] = v; 152 else 153 dest.data[i] = v / img.data[i]; 154 } 155 } 156 157 Complexf opIndex(int x, int y) 158 { 159 while(x >= width) x = width-1; 160 while(y >= height) y = height-1; 161 while(x < 0) x = 0; 162 while(y < 0) y = 0; 163 164 return data[y * width + x]; 165 } 166 167 void fft2(bool forward) 168 { 169 // process rows 170 Complexf[] row = New!(Complexf[])(width); 171 for (int y = 0; y < height; y++) 172 { 173 for (int x = 0; x < width; x++) 174 { 175 auto index = y * width + x; 176 row[x] = data[index]; 177 } 178 179 fastFourierTransform(row, forward); 180 181 for (int x = 0; x < width; x++) 182 { 183 auto index = y * width + x; 184 data[index] = row[x]; 185 } 186 } 187 188 // process columns 189 Complexf[] col = New!(Complexf[])(height); 190 for (int x = 0; x < width; x++) 191 { 192 for (int y = 0; y < height; y++) 193 { 194 auto index = y * width + x; 195 col[y] = data[index]; 196 } 197 198 fastFourierTransform(col, forward); 199 200 for (int y = 0; y < height; y++) 201 { 202 auto index = y * width + x; 203 data[index] = col[y]; 204 } 205 } 206 207 Delete(row); 208 Delete(col); 209 } 210 } 211 212 /// Convert Signal2D to SuperImage 213 void signalToImage(Signal2D chRed, Signal2D chGreen, Signal2D chBlue, SuperImage img) 214 { 215 float maxIntensityR = 0.0f; 216 float maxIntensityG = 0.0f; 217 float maxIntensityB = 0.0f; 218 Vector3f[] fpImage = New!(Vector3f[])(img.width * img.height); 219 220 for(int i = 0; i < chRed.data.length; i++) 221 { 222 float mr, mg, mb; 223 224 mr = chRed.data[i].magnitude; 225 if (mr > maxIntensityR) 226 maxIntensityR = mr; 227 mg = chGreen.data[i].magnitude; 228 if (mg > maxIntensityG) 229 maxIntensityG = mg; 230 mb = chBlue.data[i].magnitude; 231 if (mb > maxIntensityB) 232 maxIntensityB = mb; 233 234 fpImage[i] = Vector3f(mr, mg, mb); 235 } 236 237 foreach(ref v; fpImage) 238 { 239 v.r /= maxIntensityR; 240 v.g /= maxIntensityG; 241 v.b /= maxIntensityB; 242 } 243 244 foreach(y; 0..img.height) 245 foreach(x; 0..img.width) 246 { 247 size_t index = (y * img.width + x); 248 Vector3f m = fpImage[index]; 249 img[x, y] = Color4f(m); 250 } 251 252 Delete(fpImage); 253 }