OpenCV卡尺工具2

1. 卡尺区域的生成及绘制,基于GDI+完成图形绘制

  实现代码:

else if(regionEx?.Region is SectorF)
            {
                SectorF sectorF=(SectorF)regionEx.Region;

                graphics.DrawEllipse(MyPens.assist, sectorF.x / sizeratio, sectorF.y / sizeratio,
                  sectorF.width / sizeratio, sectorF.height / sizeratio);

                graphics.DrawPie(new Pen(regionEx.Color, regionEx.Size),
                    sectorF.x / sizeratio, sectorF.y / sizeratio, 
                    sectorF.width / sizeratio, sectorF.height / sizeratio, 
                    sectorF.startAngle, sectorF.sweepAngle);
            }

2. 生成扇形卡尺区域:

///


        /// 生成扇形卡尺区域
        ///

        ///
        ///
        ///
        ///
        static private List gen_calipers_region(SectorF sectorF, float calipersWidth = 30, int calipersNum=4)
        {
            List rotatedRectFs = new List();
            float cenPx = sectorF.centreP.X;
            float cenPy = sectorF.centreP.Y;
            float radius = (float)sectorF.getRadius;
            SectorF inner = sectorF.getInnerSector();
            SectorF outer = sectorF.getOuterSector();
            double height = outer.getRadius - inner.getRadius;
            float startA=  sectorF.startAngle;
            float endA = sectorF.getEndAngle;
            float offsetA = 0;
            if ( Math.Abs(Math.Abs(sectorF.sweepAngle) - 360)<=1)//起点和终点重合,重合度允许1度的误差
                offsetA = 360 / calipersNum;
            else
                offsetA = sectorF.sweepAngle / (calipersNum - 1);//可正可负,依据起点与终点的位置来定

            //获取圆周上的左边点作为卡尺工具的中心
            //x = cx + r * cos(a)
            //y = cy + r * sin(a)
         
            for(int i=0;i< calipersNum;i++)
            {
                float angle = startA + offsetA * i;
                double rad = angle / 180 * Math.PI;
                float cx = (float)(cenPx + radius * Math.Cos(-rad));
                float cy = (float)(cenPy - radius * Math.Sin(-rad));
                RotatedRectF rotatedRectF1 = new RotatedRectF(cx, cy, (float)height,
                    calipersWidth, angle);
                rotatedRectFs.Add(rotatedRectF1);
            }
            return rotatedRectFs;
        } 

3. 图像非裁切旋转:

///


        /// 图像不裁剪方式旋转
        ///

        ///
        ///
        ///
        ///
        ///
        ///
        public static Mat RotateAffine(this Mat img, double angle, ref Point2f point,ref float Tx,ref float Ty)
        {
            // angle 0-360
            while (angle < 0) angle += 360;
            if (angle > 360) angle %= 360;
            // 计算旋转后的图像尺寸
            int w0 = img.Width, h0 = img.Height;
            double arc = -Math.PI * angle / 180f;
            double c = Math.Cos(arc);
            double s = Math.Sin(arc);
            double minx = Math.Min(Math.Min(w0 * c - h0 * s, 0), Math.Min(w0 * c, -h0 * s));
            double maxx = Math.Max(Math.Max(w0 * c - h0 * s, 0), Math.Max(w0 * c, -h0 * s));
            double miny = Math.Min(Math.Min(w0 * s + h0 * c, 0), Math.Min(w0 * s, h0 * c));
            double maxy = Math.Max(Math.Max(w0 * s + h0 * c, 0), Math.Max(w0 * s, h0 * c));
            float w = (float)(maxx - minx);
            float h = (float)(maxy - miny);

            Point2f center = new Point2f(w0 / 2f, h0 / 2f);
            Mat m = Cv2.GetRotationMatrix2D(center, angle, 1.0);
            // 将原图像中心平移到旋转后的图像中心
            var mIndex = m.GetGenericIndexer();
            Tx= (w - w0) / 2f;
            Ty= (h - h0) / 2f;
            mIndex[0, 2] += (w - w0) / 2f;
            mIndex[1, 2] += (h - h0) / 2f;

            var x = point.X * m.At(0, 0) + point.Y * m.At(0, 1) + m.At(0, 2);
            var y = point.X * m.At(1, 0) + point.Y * m.At(1, 1) + m.At(1, 2);
            point.X = (float)Math.Round(x, 3);
            point.Y = (float)Math.Round(y, 3);

            Mat rotated = new Mat();
            Cv2.WarpAffine(img, rotated, m, new CVSize(w, h));
            return rotated;
        }

4. 查找边缘点:

///


        /// 边缘点查找
        ///

        /// 输入图
        /// 投影方向
        /// 边缘阈值
        /// 边缘点坐标集合
        ///
        static public Mat FindEdges(Mat srcImage, byte edgeThreshold, ref List zeroPList)
        {
            CVRect boundary = srcImage.BoundingRect();
            Mat GaussMat = Filter.ImageFilter.GaussImage(srcImage, new Size(3, 3), 0);

            float cenY = (boundary.Y + boundary.Height) / 2;
            Mat projectMat = VerticalLine(GaussMat);//平均值灰度投影
            Mat thdMat = new Mat();
            Cv2.Threshold(projectMat, thdMat, edgeThreshold, 255, ThresholdTypes.Binary);
            Mat CannyMat = on_Canny(thdMat, edgeThreshold, 255);//二阶求导零点
            //Mat mat = CannyMat.FindNonZero();
            //CannyMat.GetArray(out byte[] bytearray);
            zeroPList = new List();//极值点坐标集合
            for (int i = 0; i < CannyMat.Cols; i++)
            {
                if (CannyMat.Get(0, i) == 255
                    && i > 5 && i < CannyMat.Cols - 5)//去掉首位干扰点
                    zeroPList.Add(new Point2f(i, cenY));
            }
            return CannyMat;

        }

5. 圆拟合:

#A:最小二乘法:

///


       /// 圆拟合
       ///
  
       ///
       ///
        static public M_CIRCLE fitCircle( List fitPList)
        {
            if (fitPList.Count < 3) return default;

            float  Radius = 0.0f;
            Point2f center = new Point2f();
            double sum_x = 0.0f, sum_y = 0.0f;
            double sum_x2 = 0.0f, sum_y2 = 0.0f;
            double sum_x3 = 0.0f, sum_y3 = 0.0f;
            double sum_xy = 0.0f, sum_x1y2 = 0.0f, sum_x2y1 = 0.0f;
            int N = fitPList.Count();
            for (int i = 0; i < N; i++)
            {
                double x = fitPList.ElementAt(i).X;
                double y = fitPList.ElementAt(i).Y;
                double x2 = x * x;
                double y2 = y * y;
                sum_x += x;
                sum_y += y;
                sum_x2 += x2;
                sum_y2 += y2;
                sum_x3 += x2 * x;
                sum_y3 += y2 * y;
                sum_xy += x * y;
                sum_x1y2 += x * y2;
                sum_x2y1 += x2 * y;
            }
            double C, D, E, G, H;
            double a, b, c;
            C = N * sum_x2 - sum_x * sum_x;
            D = N * sum_xy - sum_x * sum_y;
            E = N * sum_x3 + N * sum_x1y2 - (sum_x2 + sum_y2) * sum_x;
            G = N * sum_y2 - sum_y * sum_y;
            H = N * sum_x2y1 + N * sum_y3 - (sum_x2 + sum_y2) * sum_y;
            a = (H * D - E * G) / (C * G - D * D);
            b = (H * C - E * D) / (D * D - G * C);
            c = -(a * sum_x + b * sum_y + sum_x2 + sum_y2) / N;
            center.X = (float)a / (-2);
            center.Y = (float)b / (-2);
            Radius = (float)Math.Sqrt(a * a + b * b - 4 * c) / 2;
            if (double.IsNaN(Radius))
                return default;

            return new M_CIRCLE { centreP= center,radius= Radius };
            //得分验证
            //double sum = 0;
            //for (int i = 0; i < N; i++)
            //{
            //    Point2f pti = fitPList.ElementAt(i);
            //    double ri = Math.Sqrt(Math.Pow(pti.X - center.X, 2) + Math.Pow(pti.Y - center.Y, 2));             
            //    sum += ri / radius > 1 ? ri / radius - 1 : 1 - ri / radius;
            //}
            //double sorce = 1 - sum / N;
            //return (float)sorce;         
        }

#B:随机采样一致性:

///


        /// Ransac随机一致性圆拟合
        ///

        ///
        ///
        ///
        ///
        ///
        static public M_CIRCLE RansacCircleFiler(List points, out List vpdExceptPoints,
           int iterations = 1000, double sigma = 1.0)
        {
            int n = points.Count;
            vpdExceptPoints = new List();

            if (n < 3)
            {
                return default;
            }

            Random random = new Random();
            double bestScore = -1.0;
            //List vpdTemp = new List();
            //int iterations = (int)(Math.Log(1 - 0.99) / (Math.Log(1 - (1.00 / n))) * 10);
            M_CIRCLE m_CIRCLE1=new M_CIRCLE () ;
            for (int k = 0; k < iterations; k++)
            {
                int i1 = 0, i2 = 0, i3 = 0;
                Point2f p1 = new Point2f(0, 0), p2 = new Point2f(0, 0), p3 = new Point2f(0, 0);
                while (true)
                {
                    i1 = random.Next(n);
                    i2 = random.Next(n);
                    i3 = random.Next(n);
                    if ((i1 != i2 && i1 != i3 && i2 != i3))
                    {
                        if ((points[i1].Y != points[i2].Y) && (points[i1].Y != points[i3].Y))
                        {
                            break;
                        }
                    }
                }
                p1 = points[i1];
                p2 = points[i2];
                p3 = points[i3];

                //use three points to caculate a circle
                Point2f pdP12 = GetPPCenter(p1, p2);
                double dK1 = -1 / GetLineSlope(p1, p2);
                double dB1 = pdP12.Y - dK1 * pdP12.X;
                Point2f pdP13 = GetPPCenter(p1, p3);
                double dK2 = -1 / GetLineSlope(p1, p3);
                double dB2 = pdP13.Y - dK2 * pdP13.X;
                Point2f pdCenter = new Point2f(0, 0);
                pdCenter.X = (float)((dB2 - dB1) / (dK1 - dK2));
                pdCenter.Y = (float)(dK1 * pdCenter.X + dB1);
                double dR = GetPPDistance(pdCenter, p1);
                double score = 0;
                //vpdTemp.Clear();
                for (int i = 0; i < n; i++)
                {
                    double d = dR - GetPPDistance(points[i], pdCenter);
                    if (Math.Abs(d) < sigma)
                    {
                        score += 1;
                    }
                    //else
                    //{
                    //    vpdTemp.Add(points[i]);
                    //}
                }
                if (score > bestScore)
                {
                    bestScore = score;
                    //vpdExceptPoints = vpdTemp;
                    m_CIRCLE1 = new M_CIRCLE {centreP= pdCenter ,radius= (float)dR };
                }
            }
            return m_CIRCLE1;
        }

6. 检测效果图

PS:好东西要拿出来大家一起分享,共同进步!

你可能感兴趣的:(opencv,c#,opencv)