OpenCVSharp 4.5 去除运动模糊

用OpenCVSharp 4.5 跑一遍 OpenCV 官方教程

原官方教程链接:OpenCV: Motion Deblur Filter

注:下面的程序运行是没问题的,遗憾的是我并没有找到一组合适的参数来重现原教程的效果,原OpenCV (c++)程序也是如此。(这种问题似乎很常见)

using OpenCvSharp;
using System;


namespace ConsoleApp1
{
    class tutorial31 : ITutorial
    {
        public void Run()
        {
            int len = 6  ; 
            double theta = 15; 
            double snr = 700;
            
           Mat imgIn = Cv2.ImRead("I:\\csharp\\images\\motion_blur.jpg", ImreadModes.Grayscale);
            if (imgIn.Empty()) //check whether the image is loaded or not
            {
                Console.WriteLine("ERROR : Image cannot be loaded..!!");
                return;
            }
            Mat imgOut = new Mat();
            // it needs to process even image only
            Rect roi = new Rect(0, 0, imgIn.Cols & -2, imgIn.Rows & -2);
            
            //Hw calculation (start)
            Mat Hw = new Mat();
            Mat h = new Mat();
            calcPSF(out h, roi.Size, len,theta);
            calcWnrFilter(h, out Hw, 1.0 / snr);
            //Hw calculation (stop)

            imgIn.ConvertTo(imgIn, MatType.CV_32F);
            edgetaper(imgIn, out imgIn);

            // filtering (start)
            filter2DFreq( imgIn[roi], out imgOut, Hw);
            // filtering (stop)

            imgOut.ConvertTo(imgOut, MatType.CV_8U);
            Cv2.Normalize(imgOut, imgOut, 0, 255, NormTypes.MinMax);
            Cv2.ImShow("result.jpg", imgOut);
            Cv2.WaitKey();
        }

        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];
        }

        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];
        }

        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 Rect(0, 0, cx, cy));
            Mat q1 = new Mat(outputImg, new Rect(cx, 0, cx, cy));
            Mat q2 = new Mat(outputImg, new Rect(0, cy, cx, cy));
            Mat q3 = new Mat(outputImg, new 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);
        }

        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;
            Mat output = new Mat();
            Cv2.Divide(planes[0], denom, output);
            output_G = output;
        }

        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<float>();

                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<float>(0,i,f);
                    x += dx;
                }
                                

                float dy = (float)(2.0 * Cv2.PI / Ny);
                float y = (float)(-Cv2.PI);
                //var p2 = w2.GetGenericIndexer<float>();

                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<float>(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;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值