C# 基于OpenCV实现运动图像去模糊
首先在在工程里添加OpenCvSharp的依赖项。
0X00.引用
using OpenCvSharp;
using Size = OpenCvSharp.Size;
using Point = OpenCvSharp.Point;
using OpenCvSharp.Extensions;
0X01.添加图像源
private async void PickAFileButton_Click(object sender, RoutedEventArgs e)
{
var openPicker = new FileOpenPicker();
var window = WindowHelper.GetWindowForElement(this);
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(window);
WinRT.Interop.InitializeWithWindow.Initialize(openPicker, hwnd);
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
openPicker.FileTypeFilter.Add(".jpg");
openPicker.FileTypeFilter.Add(".jpeg");
openPicker.FileTypeFilter.Add(".png");
openPicker.FileTypeFilter.Add(".bmp");
var file = await openPicker.PickSingleFileAsync();
if (file != null)
{
consoleTextBlock.Text += "Picked photo: " + file.Name + "\r\n";
filePathUri = file.Path;
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.UriSource = new Uri(filePathUri);
sourceImage.Source = bitmapImage;
}
}
0X02.传入len theta snr参数进行处理
private void Run(int len, double theta, double snr)
{
Mat imgIn = Cv2.ImRead(filePathUri, ImreadModes.Grayscale);
if (imgIn.Empty()) //check whether the image is loaded or not
{
consoleTextBlock.Text += "ERROR : Image cannot be loaded..!!" + "\r\n";
return;
}
Mat imgOut = new Mat();
OpenCvSharp.Rect roi = new OpenCvSharp.Rect(0, 0, imgIn.Cols & -2, imgIn.Rows & -2);
Mat Hw = new Mat();
Mat h = new Mat();
calcPSF(out h, roi.Size, len, theta);
calcWnrFilter(h, out Hw, 1.0 / snr);
imgIn.ConvertTo(imgIn, MatType.CV_32F);
edgetaper(imgIn, out imgIn);
filter2DFreq(imgIn[roi], out imgOut, Hw);
imgOut.ConvertTo(imgOut, MatType.CV_8U);
Cv2.Normalize(imgOut, imgOut, 0, 255, NormTypes.MinMax);
MemoryStream memoryStream = new MemoryStream();
imgOut.ConvertTo(imgOut, MatType.CV_8U);
imgOut.ToBitmap().Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png);
mat = imgOut;
memoryStream.Position = 0;
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(memoryStream.AsRandomAccessStream());
resultImage.Source = bitmapImage;
Cv2.WaitKey();
}0X03.calcPSF方法//点扩散
private void calcPSF(out Mat outputImg, Size filterSize, int len, double theta)
{
Mat h = Mat.Zeros(filterSize, MatType.CV_32F);
Point point = new Point(filterSize.Width / 2, filterSize.Height / 2);
Cv2.Ellipse(h, point, new Size(0, Math.Round((float)len / 2.0)), 90.0 - theta, 0, 360, new Scalar(255), Cv2.FILLED);
Scalar summa = Cv2.Sum(h);
outputImg = h / summa[0];
}
0X04.filter2DFreq方法//滤波
private void filter2DFreq(Mat inputImg, out Mat outputImg, Mat H)
{
inputImg.Clone().ConvertTo(inputImg, MatType.CV_32F);
Mat[] planes = { inputImg, Mat.Zeros(inputImg.Size(), MatType.CV_32F) };
Mat complexI = new Mat();
Cv2.Merge(planes, complexI);
Cv2.Dft(complexI, complexI, DftFlags.Scale);
H.Clone().ConvertTo(H, MatType.CV_32F);
Mat[] planesH = { H, Mat.Zeros(H.Size(), MatType.CV_32F) };
Mat complexH = new Mat();
Cv2.Merge(planesH, complexH);
Mat complexIH = new Mat();
Cv2.MulSpectrums(complexI, complexH, complexIH, 0);
Cv2.Idft(complexIH, complexIH);
Cv2.Split(complexIH, out planes);
outputImg = planes[0];
}
0X05.fftshift方法//傅里叶变换
private void fftshift(Mat inputImg, out Mat outputImg)
{
outputImg = inputImg.Clone();
int cx = outputImg.Cols / 2;
int cy = outputImg.Rows / 2;
Mat q0 = new Mat(outputImg, new OpenCvSharp.Rect(0, 0, cx, cy));
Mat q1 = new Mat(outputImg, new OpenCvSharp.Rect(cx, 0, cx, cy));
Mat q2 = new Mat(outputImg, new OpenCvSharp.Rect(0, cy, cx, cy));
Mat q3 = new Mat(outputImg, new OpenCvSharp.Rect(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);
}0X06.calcWnrFilter方法//维纳滤波
private void calcWnrFilter(Mat input_h_PSF, out Mat output_G, double nsr)
{
Mat h_PSF_shifted = new Mat();
fftshift(input_h_PSF, out h_PSF_shifted);
Mat[] planes = { h_PSF_shifted.Clone(), Mat.Zeros(h_PSF_shifted.Size(), MatType.CV_32F) };
Mat complexI = new Mat();
Cv2.Merge(planes, complexI);
Cv2.Dft(complexI, complexI);
Cv2.Split(complexI, out planes);
Mat denom = new Mat();
Cv2.Pow(Cv2.Abs(planes[0]), 2, denom);
denom += nsr;//如果OpenCvSharp4版本为4.10以上,denom += Scalar.All(nsr);
Mat output = new Mat();
Cv2.Divide(planes[0], denom, output);
output_G = output;
}0X07.edgetaper方法//边缘渐变
private void edgetaper(Mat inputImg, out Mat outputImg, double gamma = 5.0, double beta = 0.2)
{
int Nx = inputImg.Cols;
int Ny = inputImg.Rows;
Mat w = new Mat();
using (Mat w1 = Mat.Zeros(new Size(Nx, 1), MatType.CV_32F))
using (Mat w2 = Mat.Zeros(new Size(1, Ny), MatType.CV_32F))
{
float dx = (float)(2.0 * Cv2.PI / Nx);
float x = (float)(-Cv2.PI);
//var p1 = w1.GetGenericIndexer();
for (int i = 0; i < Nx; i++)
{
float f = (float)(0.5 * (Math.Tanh((x + gamma / 2) / beta) - Math.Tanh((x - gamma / 2) / beta)));
w1.Set(0, i, f);
x += dx;
}
float dy = (float)(2.0 * Cv2.PI / Ny);
float y = (float)(-Cv2.PI);
//var p2 = w2.GetGenericIndexer();
for (int j = 0; j < Ny; j++)
{
float f = (float)(0.5 * (Math.Tanh((y + gamma / 2) / beta) - Math.Tanh((y - gamma / 2) / beta)));
w2.Set(j, 0, f);
y += dy;
}
w = w2 * w1; //w1:431x1, w2:1x240 = w:431x240
}
Mat output = new Mat();
Cv2.Multiply(inputImg, w, output); //inputImg: 240x431
outputImg = output;
}
C# 基于OpenCV实现运动图像去模糊
https://blog.async.website/index.php/archives/3379/