/
Methods.cs
240 lines (191 loc) · 7.29 KB
/
Methods.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
using Emgu.CV;
using Emgu.CV.Cuda;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.Util;
using Emgu.CV.XPhoto;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Numerics;
namespace RasDenoise
{
static class Methods
{
public static void NlMeans(NlMeansArgs args)
{
Console.WriteLine("Reading image "+args.src);
var imgData = CvInvoke.Imread(args.src,ImreadModes.AnyColor);
var outData = new Mat(imgData.Size,imgData.Depth,imgData.NumberOfChannels);
Console.WriteLine("Denoising using "+nameof(NlMeans));
CvInvoke.FastNlMeansDenoising(imgData,outData,(float)args.h,args.templateWindowSize,args.searchWindowSize);
Console.WriteLine("Saving "+args.dst);
outData.Bitmap.Save(args.dst);
}
public static void NlMeansColored(NlMeansColoredArgs args)
{
Console.WriteLine("Reading image "+args.src);
var imgData = CvInvoke.Imread(args.src,ImreadModes.AnyColor);
var outData = new Mat(imgData.Size,imgData.Depth,imgData.NumberOfChannels);
Console.WriteLine("Denoising using "+nameof(NlMeansColored));
CvInvoke.FastNlMeansDenoisingColored(imgData,outData,(float)args.h,(float)args.hColor,args.templateWindowSize,args.searchWindowSize);
Console.WriteLine("Saving "+args.dst);
outData.Bitmap.Save(args.dst);
}
public static void Dct(DctArgs args)
{
Console.WriteLine("Reading image "+args.src);
var imgData = CvInvoke.Imread(args.src,ImreadModes.AnyColor);
var outData = new Mat();
Console.WriteLine("Denoising using "+nameof(Dct));
XPhotoInvoke.DctDenoising(imgData,outData,args.sigma.Value,args.psize);
Console.WriteLine("Saving "+args.dst);
outData.Bitmap.Save(args.dst);
}
public static void TVL1(TVL1Args args)
{
var observations = new List<Mat>();
foreach (string s in args.srcList)
{
Console.WriteLine("Reading image " + s);
var imgData = CvInvoke.Imread(s, ImreadModes.AnyColor);
observations.Add(imgData);
}
var outData = new Mat();
Console.WriteLine("Denoising using " + nameof(TVL1));
CvInvoke.DenoiseTVL1(observations.ToArray(), outData, args.lambda.Value, args.niters.Value);
Console.WriteLine("Saving " + args.dst);
outData.Bitmap.Save(args.dst);
}
#if false
//Followed this source code mostly
//https://github.com/opencv-java/fourier-transform/blob/master/src/it/polito/teaching/cv/FourierController.java
public static void DFTForward(DFTArgs args)
{
var imgSrc = CvInvoke.Imread(args.src,ImreadModes.Grayscale | ImreadModes.AnyDepth);
//get optimal dimensions (power of 2 i think..)
int xdftsz = CvInvoke.GetOptimalDFTSize(imgSrc.Rows);
int ydftsz = CvInvoke.GetOptimalDFTSize(imgSrc.Cols);
//pad input image to optimal dimensions
CvInvoke.CopyMakeBorder(imgSrc,imgSrc,
0,xdftsz - imgSrc.Rows,0,ydftsz - imgSrc.Cols,
BorderType.Constant,new MCvScalar(0)
);
imgSrc.PrintInfo("1");
//use 32F format for calcs
imgSrc.ConvertTo(imgSrc,DepthType.Cv32F);
imgSrc.PrintInfo("2");
//create a 2 channel mat using the input as the fist channel
var planes = new VectorOfMat();
planes.Push(imgSrc);
planes.Push(new Mat(imgSrc.Size,DepthType.Cv32F,1));
Mat complex = new Mat();
CvInvoke.Merge(planes,complex);
complex.PrintInfo("3");
//do the fourrier transform
CvInvoke.Dft(complex,complex,DxtType.Forward,0);
complex.PrintInfo("4");
//split channels into real / imaginary
var compos = new VectorOfMat(2);
CvInvoke.Split(complex,compos);
//convert real / imaginary to magnitude / phase - which is easier to deal with when looking for artifacts
Mat mag = new Mat();
Mat phs = new Mat();
CvInvoke.CartToPolar(compos[0],compos[1],mag,phs);
mag.PrintInfo("5m");
//convert to log scale since magnitude tends to have a huge range
Helpers.AddS(mag,1.0,mag);
CvInvoke.Log(mag,mag);
mag.PrintInfo("6m");
phs.PrintInfo("6p");
//regular DFT puts low frequencies in the corners - this flips them to the center
RearrangeQuadrants(mag);
RearrangeQuadrants(phs);
double magMax, magMin;
CvInvoke.MinMaxIdx(mag,out magMin,out magMax,null,null);
//Console.WriteLine("-mi "+magMin+","+magMax+"]");
double phsMax, phsMin;
CvInvoke.MinMaxIdx(phs,out phsMin,out phsMax,null,null);
//convert to a 'normal' format and scale the data
Mat magOut = new Mat();
Mat phsOut = new Mat();
CvInvoke.Normalize(mag,magOut,0,65535,NormType.MinMax,DepthType.Cv16U);
CvInvoke.Normalize(phs,phsOut,0,65535,NormType.MinMax,DepthType.Cv16U);
string name = Path.GetFileNameWithoutExtension(args.dst);
magOut.PrintInfo("7m");
phsOut.PrintInfo("7p");
Console.WriteLine("-mi " + magMin + " -mx " + magMax + " -pi " + phsMin + " -px " + phsMax);
magOut.Save(name+"-mag.png");
phsOut.Save(name+"-phs.png");
}
public static void DFTInverse(IEnumerable<string> srcList, string dst, double mi, double mx, double pi, double px)
{
string magName = null, phsName = null;
int index = 0;
foreach(string src in srcList) {
if (index == 0) { magName = src; }
if (index == 1) { phsName = src; }
index++;
}
var magSrc = CvInvoke.Imread(magName,ImreadModes.Grayscale | ImreadModes.AnyDepth);
var phsSrc = CvInvoke.Imread(phsName,ImreadModes.Grayscale | ImreadModes.AnyDepth);
magSrc.PrintInfo("1m");
phsSrc.PrintInfo("1p");
Mat mag = new Mat();
Mat phs = new Mat();
CvInvoke.Normalize(magSrc,mag,mi,mx,NormType.MinMax,DepthType.Cv32F);
CvInvoke.Normalize(phsSrc,phs,pi,px,NormType.MinMax,DepthType.Cv32F);
mag.PrintInfo("2m");
phs.PrintInfo("2p");
//flip these back to original positions
RearrangeQuadrants(mag);
RearrangeQuadrants(phs);
//de-log the magnitude data
CvInvoke.Exp(mag,mag);
Helpers.AddS(mag,-1.0,mag);
mag.PrintInfo("3m");
//back to real / imaginary from magnitude / phase
Mat real = new Mat();
Mat imag = new Mat();
CvInvoke.PolarToCart(mag,phs,real,imag);
real.PrintInfo("4r");
imag.PrintInfo("4i");
//merge real / imaginary into one complex Mat
var planes = new VectorOfMat();
planes.Push(real);
planes.Push(imag);
Mat complex = new Mat();
CvInvoke.Merge(planes,complex);
complex.PrintInfo("5");
//do the inverse fourrier transform
CvInvoke.Dft(complex,complex,DxtType.Inverse,0);
complex.PrintInfo("6");
//split into spatial / (empty)
var compos = new VectorOfMat(2);
CvInvoke.Split(complex,compos);
//the real part should contain the orignal data - we can throw away the imaginary part
Mat img = compos[0];
Mat imgOut = new Mat();
CvInvoke.Normalize(img,imgOut,0,65535,NormType.MinMax,DepthType.Cv16U);
imgOut.Save(dst);
}
static void RearrangeQuadrants(Mat image)
{
int cx = image.Width / 2;
int cy = image.Height / 2;
Mat q0 = new Mat(image,new Rectangle(0,0,cx,cy));
Mat q1 = new Mat(image,new Rectangle(cx,0,cx,cy));
Mat q2 = new Mat(image,new Rectangle(0,cy,cx,cy));
Mat q3 = new Mat(image,new Rectangle(cx,cy,cx,cy));
Mat tmp = new Mat();
q0.CopyTo(tmp);
q3.CopyTo(q0);
tmp.CopyTo(q3);
q1.CopyTo(tmp);
q2.CopyTo(q1);
tmp.CopyTo(q2);
}
#endif
}
}