OpenCV how to smooth contour, reducing noise

前端 未结 2 1606
小鲜肉
小鲜肉 2021-01-20 03:07

I extracted the contours of an image, that you can see here:

However, it has some noise. How can I smooth the noise? I did a close up to make clearer what I want to

相关标签:
2条回答
  • 2021-01-20 03:49

    I don't know if is it ok to provide Java code - but I implemented Gaussian smoothing for openCV contour. Logic and theory is taken from here https://www.morethantechnical.com/2012/12/07/resampling-smoothing-and-interest-points-of-curves-via-css-in-opencv-w-code/

    package CurveTools;
    
    import org.apache.log4j.Logger;
    import org.opencv.core.Mat;
    import org.opencv.core.MatOfPoint;
    import org.opencv.core.Point;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import static org.opencv.core.CvType.CV_64F;
    import static org.opencv.imgproc.Imgproc.getGaussianKernel;
    
    class CurveSmoother {
    
        private double[] g, dg, d2g, gx, dx, d2x;
        private double gx1, dgx1, d2gx1;
    
        public double[] kappa, smoothX, smoothY;
        public double[] contourX, contourY;
    
        /* 1st and 2nd derivative of 1D gaussian  */
        void getGaussianDerivs(double sigma, int M) {
    
            int L = (M - 1) / 2;
            double sigma_sq = sigma * sigma;
            double sigma_quad = sigma_sq * sigma_sq;
    
            dg = new double[M];
            d2g = new double[M];
            g = new double[M];
    
            Mat tmpG = getGaussianKernel(M, sigma, CV_64F);
    
            for (double i = -L; i < L + 1.0; i += 1.0) {
                int idx = (int) (i + L);
    
                g[idx] = tmpG.get(idx, 0)[0];
    
                // from http://www.cedar.buffalo.edu/~srihari/CSE555/Normal2.pdf
                dg[idx] = -i * g[idx] / sigma_sq;
                d2g[idx] = (-sigma_sq + i * i) * g[idx] / sigma_quad;
            }
        }
    
        /* 1st and 2nd derivative of smoothed curve point */
        void getdX(double[] x, int n, double sigma, boolean isOpen) {
    
            int L = (g.length - 1) / 2;
    
            gx1 = dgx1 = d2gx1 = 0.0;
            for (int k = -L; k < L + 1; k++) {
                double x_n_k;
                if (n - k < 0) {
                    if (isOpen) {
                        //open curve - mirror values on border
                        x_n_k = x[-(n - k)];
                    } else {
                        //closed curve - take values from end of curve
                        x_n_k = x[x.length + (n - k)];
                    }
                } else if (n - k > x.length - 1) {
                    if (isOpen) {
                        //mirror value on border
                        x_n_k = x[n + k];
                    } else {
                        x_n_k = x[(n - k) - x.length];
                    }
                } else {
                    x_n_k = x[n - k];
                }
    
                gx1 += x_n_k * g[k + L]; //gaussians go [0 -> M-1]
                dgx1 += x_n_k * dg[k + L];
                d2gx1 += x_n_k * d2g[k + L];
            }
        }
    
        /* 0th, 1st and 2nd derivatives of whole smoothed curve */
        void getdXcurve(double[] x, double sigma, boolean isOpen) {
    
            gx = new double[x.length];
            dx = new double[x.length];
            d2x = new double[x.length];
    
            for (int i = 0; i < x.length; i++) {
                getdX(x, i, sigma, isOpen);
                gx[i] = gx1;
                dx[i] = dgx1;
                d2x[i] = d2gx1;
            }
        }
    
        /*
            compute curvature of curve after gaussian smoothing
            from "Shape similarity retrieval under affine transforms", Mokhtarian & Abbasi 2002
            curvex - x position of points
            curvey - y position of points
            kappa - curvature coeff for each point
            sigma - gaussian sigma
        */
        void computeCurveCSS(double[] curvex, double[] curvey, double sigma, boolean isOpen) {
            int M = (int) Math.round((10.0 * sigma + 1.0) / 2.0) * 2 - 1;
            assert (M % 2 == 1); //M is an odd number
    
            getGaussianDerivs(sigma, M);//, g, dg, d2g
    
            double[] X, XX, Y, YY;
    
            getdXcurve(curvex, sigma, isOpen);
            smoothX = gx.clone();
            X = dx.clone();
            XX = d2x.clone();
    
            getdXcurve(curvey, sigma, isOpen);
            smoothY = gx.clone();
            Y = dx.clone();
            YY = d2x.clone();
    
    
            kappa = new double[curvex.length];
    
            for (int i = 0; i < curvex.length; i++) {
                // Mokhtarian 02' eqn (4)
                kappa[i] = (X[i] * YY[i] - XX[i] * Y[i]) / Math.pow(X[i] * X[i] + Y[i] * Y[i], 1.5);
            }
        }
    
        /* find zero crossings on curvature */
        ArrayList<Integer> findCSSInterestPoints() {
    
            assert (kappa != null);
    
            ArrayList<Integer> crossings = new ArrayList<>();
    
            for (int i = 0; i < kappa.length - 1; i++) {
                if ((kappa[i] < 0.0 && kappa[i + 1] > 0.0) || kappa[i] > 0.0 && kappa[i + 1] < 0.0) {
                    crossings.add(i);
                }
            }
            return crossings;
        }
    
        public void polyLineSplit(MatOfPoint pl) {
            contourX = new double[pl.height()];
            contourY = new double[pl.height()];
    
            for (int j = 0; j < contourX.length; j++) {
                contourX[j] = pl.get(j, 0)[0];
                contourY[j] = pl.get(j, 0)[1];
            }
        }
    
        public MatOfPoint polyLineMerge(double[] xContour, double[] yContour) {
    
            assert (xContour.length == yContour.length);
    
            MatOfPoint pl = new MatOfPoint();
    
            List<Point> list = new ArrayList<>();
    
            for (int j = 0; j < xContour.length; j++)
                list.add(new Point(xContour[j], yContour[j]));
    
            pl.fromList(list);
    
            return pl;
        }
    
        MatOfPoint smoothCurve(MatOfPoint curve, double sigma) {
            int M = (int) Math.round((10.0 * sigma + 1.0) / 2.0) * 2 - 1;
            assert (M % 2 == 1); //M is an odd number
    
            //create kernels
            getGaussianDerivs(sigma, M);
            polyLineSplit(curve);
    
            getdXcurve(contourX, sigma, false);
            smoothX = gx.clone();
    
            getdXcurve(contourY, sigma, false);
            smoothY = gx;
    
            Logger.getRootLogger().info("Smooth curve len: " + smoothX.length);
    
            return polyLineMerge(smoothX, smoothY);
        }
    }
    
    0 讨论(0)
  • 2021-01-20 03:55

    Try an upgraded to OpenCV 3.1.0. After some code adaptations for the new version as shown below, I tried it out with OpenCV version 3.1.0 and did not see any of the effects you are describing.

    import cv2
    import numpy as np
    
    print cv2.__version__
    
    rMaskgray = cv2.imread('5evOn.jpg', 0)
    (thresh, binRed) = cv2.threshold(rMaskgray, 50, 255, cv2.THRESH_BINARY)
    
    _, Rcontours, hier_r = cv2.findContours(binRed,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_SIMPLE)
    r_areas = [cv2.contourArea(c) for c in Rcontours]
    max_rarea = np.max(r_areas)
    CntExternalMask = np.ones(binRed.shape[:2], dtype="uint8") * 255
    
    for c in Rcontours:
        if(( cv2.contourArea(c) > max_rarea * 0.70) and (cv2.contourArea(c)< max_rarea)):
            cv2.drawContours(CntExternalMask,[c],-1,0,1)
    
    cv2.imwrite('contour1.jpg', CntExternalMask)
    

    0 讨论(0)
提交回复
热议问题