SplitItem.cs 7.3 KB
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AccImage
{
    public class SplitItem
    {
        public static double DIFF_PERCENT = 0.4;
        public bool isEnd = false;
        public double avgRadius = 0;
        public int centerX = 0;
        public int centerY = 0;
        public double currentMaxRadius = 0;
        public List<Circle> circles = new List<Circle>();

        /// <summary>
        /// 一遍结束后调用, 返回当前圆是否有效
        /// </summary>
        public Circle calOneItem(double theFixRadius=-1)
        {
            //该半径是否有效
            bool isValid = false;
            if (avgRadius == 0)
            {
                isValid = true;
            }
            else
            {
                //与平均半径差值在50%以内,认为OK
                double diff = avgRadius - currentMaxRadius;
                if (diff/avgRadius <= DIFF_PERCENT)
                {
                    isValid = true;
                }
            }
            if (isValid)
            {
                if(currentMaxRadius == 0)
                {
                    isEnd = true;
                    return null;
                }
                Circle circle = new Circle();
                if(theFixRadius != -1 && currentMaxRadius > theFixRadius)
                {
                    currentMaxRadius = theFixRadius;
                }
                circle.radius = currentMaxRadius;
                circle.x = centerX;
                circle.y = centerY;
                circles.Add(circle);
                currentMaxRadius = 0;
                centerX = 0;
                centerY = 0;
                if(circle.radius > avgRadius)
                {
                    avgRadius = circle.radius;
                }
                return circle;
            }
            else
            {
                isEnd = true;
            }

            return null;
            
        }
        

        public List<List<Circle>> groupCircles(double w, double h, Point2d center)
        {
            foreach(Circle c in circles)
            {
                c.calDistanceToCenter(center);
            }
            //排序
            circles.OrderBy(c => c.distanceToCenter);
            List<List<Circle>> lineCircles = new List<List<Circle>>();
            List<int> allreadyLabel = new List<int>();
            //与圆心距离在h范围内的分为一组
            while (true)
            {
                List<Circle> lineCircle = new List<Circle>();
                Circle firstLineCircle = null;
                for (int i = 0; i < circles.Count; i++)
                {
                    if (!allreadyLabel.Contains(i))
                    {
                        Circle c = circles[i];
                        if (firstLineCircle == null)
                        {
                            firstLineCircle = c;
                            allreadyLabel.Add(i);
                            lineCircle.Add(c);
                        }
                        else
                        {
                            //到圆心的距离差小于H
                            if (Math.Abs(c.distanceToCenter - firstLineCircle.distanceToCenter) < h)
                            {
                                lineCircle.Add(c);
                                allreadyLabel.Add(i);
                            }
                        }
                    }
                }
                lineCircles.Add(lineCircle);
                if (allreadyLabel.Count == circles.Count)
                {
                    break;
                }
            }
            
            //再按长度划分
            List<List<Circle>> allGroupCircle = new List<List<Circle>>();
            foreach (var lineCircle in lineCircles)
            {
                //排序
                lineCircle.OrderBy(c => c.x);
                List<int> lineAllreadyLabel = new List<int>();
                while (true)
                {
                    List<Circle> groupCircle = new List<Circle>();
                    Scalar color = Scalar.Yellow;
                    for (int i = 0; i < lineCircle.Count; i++)
                    {
                        if (!lineAllreadyLabel.Contains(i))
                        {
                            Circle c = lineCircle[i];
                            //圆心之间的距离+直径小于W认为是同一个元器件
                            bool inGroup = true;
                            foreach (var gCircle in groupCircle)
                            {
                                if (c.distanceToCircle(gCircle) > w)
                                {
                                    inGroup = false;
                                }
                            }
                            if (inGroup)
                            {
                                c.color = color;
                                groupCircle.Add(c);
                                lineAllreadyLabel.Add(i);
                            }

                        }
                    }
                    
                    allGroupCircle.Add(groupCircle);
                    if (lineAllreadyLabel.Count == lineCircle.Count)
                    {
                        break;
                    }

                }
            }
            return allGroupCircle;
        }

        /// <summary>
        /// 该点是否与其他圆内,或与圆的中心距离在半径内
        /// </summary>
        /// <param name="px"></param>
        /// <param name="py"></param>
        /// <returns></returns>
        public double minDistanceToCircles(int px, int py,  double oneBlobWidth =-1, double oneBlobRadius = -1)
        {
            Point2d point = new Point2d(px, py);
            double minDistanceToCircle = -1;
            List<Circle> neighbourCircles = circles;
            if (oneBlobRadius > 0)
            {
                neighbourCircles = neighbourCircles.Where(c => Math.Abs(c.x - px) <= 2 * oneBlobRadius && Math.Abs(c.y - py) <= 2 * oneBlobRadius).ToList();
            }
            foreach (Circle c in neighbourCircles)
            {
                Point2d circleCenter = new Point2d(c.x, c.y);
                double distanceToCircle = point.DistanceTo(circleCenter) - c.radius;
                if (distanceToCircle <= DIFF_PERCENT * c.radius)
                {
                    return 0;
                }

                if (minDistanceToCircle == -1 || distanceToCircle < minDistanceToCircle)
                {
                    minDistanceToCircle = distanceToCircle;
                }
            }
            return minDistanceToCircle;
        }

    };

    public class Circle
    {
        public int x;
        public int y;
        public double radius;
        public Scalar color = Scalar.Green;
        public double distanceToCenter = 0;

        public double distanceToCircle(Circle c)
        {
            double distance = new Point2d(x, y).DistanceTo(new Point2d(c.x, c.y));
            return distance + radius + c.radius;
        }
        public void calDistanceToCenter(Point2d center)
        {
            if(center.X > 0 && distanceToCenter <= 0)
            {
                distanceToCenter = center.DistanceTo(new Point2d(x, y));
            }
        }
    }
}