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/
本文作者 snowysong@live.com
发布时间 2025-04-23
许可协议 CC BY-NC-SA 4.0
发表新评论