Emgucv4.4.0.4099版本PCB开发板纠偏(直线倾斜角度计算方法、确定参考点坐标)MinEnclosingCircle(拟合圆函数)

原图

PCB原图文件百度云链接:
https://pan.baidu.com/s/1Q4JYpmY6epPoO6dP45GcRw
提取码:zzxd

代码

//计算直线倾斜角度
public double ComputeAngle(CircleF referencePoint , CircleF rightPoint)
        {
            float left_rightXValue = referencePoint.Center.X - rightPoint.Center.X;
            float left_rightYValue = referencePoint.Center.Y - rightPoint.Center.Y;
            float kValue = left_rightYValue / left_rightXValue;
            float slopeValue = 0;
            float angle = 0;
            double Result = 0;
            if (left_rightXValue == 0.0)
                slopeValue = (float)(Math.PI / 2.0);
            else
                slopeValue = (float)Math.Atan(Math.Abs(kValue));
            if (left_rightYValue >= 0.0)
                angle = (float)slopeValue * -1;
            else if (left_rightYValue < 0.0)
                angle = slopeValue;
            else if ((left_rightXValue >= 0.0) && (left_rightYValue < 0.0))
                angle = slopeValue;
            //Angle
            Result = -(180 / Math.PI) * angle;
            return Result;
        }
//主函数代码
private void FindAngle_Click(object sender, EventArgs e)   // return angle
        {
            //不用旋转
            Bitmap bmp = (Bitmap)pb1.Image;
            Image<Gray, byte> grayImage = bmp.ToImage<Gray, byte>();
            ResultImage = grayImage.Clone().Convert<Bgr, byte>();
            //threshold
            Image<Gray, byte> thresholdImage = new Image<Gray, byte>(grayImage.Width, grayImage.Height);
            CvInvoke.Threshold(grayImage, thresholdImage, 80, 255, ThresholdType.Binary);
            thresholdImage.Save(@"D:\1test\pcb\1thresholdImage.bmp");
            //------------------find contours && fill up--------------------------------------------------------------------------------------------            
            VectorOfVectorOfPoint thresholdCountours = new VectorOfVectorOfPoint();
            VectorOfVectorOfPoint totalCircleCoutours = new VectorOfVectorOfPoint();
            Mat h_mat_1 = new Mat();
            CvInvoke.FindContours(thresholdImage, thresholdCountours, h_mat_1, Emgu.CV.CvEnum.RetrType.External, ChainApproxMethod.ChainApproxSimple);
            Image<Gray, byte> mask_1 = new Image<Gray, byte>(grayImage.Width, grayImage.Height);
            List<double> Perimeters = new List<double>();
            List<double> Areas = new List<double>();
            informations.Text = "";
            //---------------------Retain circles
            for (int i = 0; i < thresholdCountours.Size; i++)
            {
                var area = CvInvoke.ContourArea(thresholdCountours[i], false);
                double perimeter = CvInvoke.ArcLength(thresholdCountours[i], true);  //length                
                if (area > 7500)
                {
                    Areas.Add(area);
                    if (perimeter < 500 && perimeter > 320)
                    {                        
                        Perimeters.Add(perimeter);
                        totalCircleCoutours.Push(thresholdCountours[i]);
                        informations.Text += "area-" + area.ToString() + "ArcLength:" + perimeter.ToString();  //121779
                        informations.Text += Environment.NewLine;
                        //CvInvoke.FillPoly(mask_1, contours_1[i], new MCvScalar(255, 255, 255));
                        CvInvoke.DrawContours(mask_1, thresholdCountours, i, new MCvScalar(255, 255, 255), 2);
                    }
                }
            }
            mask_1.Save(@"D:\1test\pcb\2mask_1.bmp");
            
            #region
            //all circle
        
            //mask_1.Save(@"D:\1test\pcb\2fillup.bmp");
            //------------------fit smallest circle
            Image<Gray, byte> MinEnclosingCircleImage = new Image<Gray, byte>(grayImage.Width, grayImage.Height);
            List<double> yPositions = new List<double>();
            List<double> xPositions = new List<double>();
            List<PointF> totalPoints = new List<PointF>();
            List<CircleF> circleFs = new List<CircleF>();
            int pointIndex = 0;
            for (int i = 0; i < totalCircleCoutours.Size; i++)
            {
                CvInvoke.DrawContours(mask_1, totalCircleCoutours, i, new MCvScalar(255, 255, 255), 2);
                CircleF circleF = CvInvoke.MinEnclosingCircle(totalCircleCoutours[i]);
                MinEnclosingCircleImage.Draw(circleF, new Gray(255), 1);
                xPositions.Add(circleF.Center.X);        //point y position
                yPositions.Add(circleF.Center.Y);        //point y position
                totalPoints.Add(new PointF(circleF.Center.X, circleF.Center.Y));   //point position
                circleFs.Add(circleF);
                pointIndex++;
            }
            
            #endregion
            #region//------------------------------------小的PCB------------------------------------
            if (pointIndex <= 6)   //the point count == 6 small
            {
                thresholdImage.Save(@"D:\1test\pcb\temp\1-1thresholdImage.bmp");
                //------------------find biggest circle contours  && fill up--------------------------------------------------------------------------------------------            
                VectorOfVectorOfPoint contours_2 = new VectorOfVectorOfPoint();
                Mat h_mat_2 = new Mat();
                CvInvoke.FindContours(thresholdImage, contours_2, h_mat_2, Emgu.CV.CvEnum.RetrType.External, ChainApproxMethod.ChainApproxSimple);
                Image<Bgr, byte> TheBiggestCircleCountours = new Image<Bgr, byte>(grayImage.Width, grayImage.Height);
                List<double> perimeters = new List<double>();
                List<double> Areas2 = new List<double>();
                VectorOfVectorOfPoint BiggestCircleContours = new VectorOfVectorOfPoint();
                informations.Text = "";
                //find big circle
                for (int i = 0; i < contours_2.Size; i++)
                {
                    var area = CvInvoke.ContourArea(contours_2[i], false);
                    double perimeter = CvInvoke.ArcLength(contours_2[i], false);  //length                    
                    //if (area > 7500 && area < 9000)
                    if (area > 20000)
                    {
                        //Areas2.Add(area);
                        //perimeters.Add(perimeter);
                        //if (perimeter > 300 && perimeter < 450)
                        if (perimeter > 300)
                        {
                            informations.Text += "i-" + "area-" + area.ToString() + "ArcLength:" + perimeter.ToString();  //121779
                            informations.Text += Environment.NewLine;
                            //CvInvoke.FillPoly(mask_1, contours_1[i], new MCvScalar(255, 255, 255));
                            CvInvoke.DrawContours(TheBiggestCircleCountours, contours_2, i, new MCvScalar(255, 255, 255), 2);
                            BiggestCircleContours.Push(contours_2[i]);
                        }
                    }
                }
                TheBiggestCircleCountours.Save(@"D:\1test\pcb\temp\1-2TheBiggestCircleCountours.bmp");
                //follow circle countours to fit big circle 
                //Image<Gray, byte> circle_gray2 = TheBiggestCircleCountours.Clone().Convert<Gray, byte>();
                Image<Gray, byte> MinEnclosingCircleImage_2 = new Image<Gray, byte>(grayImage.Width, grayImage.Height);  //display
                List<double> yPositions_2 = new List<double>();
                List<double> xPositions_2 = new List<double>();
                List<PointF> BiggestCircleTotal = new List<PointF>();
                int pointIndex2 = 0;
                for (int i = 0; i < BiggestCircleContours.Size; i++)
                {
                    CircleF circleF = CvInvoke.MinEnclosingCircle(BiggestCircleContours[i]);
                    MinEnclosingCircleImage.Draw(circleF, new Gray(255), 1);
                    xPositions_2.Add(circleF.Center.X);        //point y position
                    yPositions_2.Add(circleF.Center.Y);        //point y position
                    BiggestCircleTotal.Add(new PointF(circleF.Center.X, circleF.Center.Y));   //point position
                    pointIndex2++;
                    CvInvoke.DrawContours(MinEnclosingCircleImage_2, BiggestCircleContours, i, new MCvScalar(255, 255, 255), 2);
                }
                MinEnclosingCircleImage_2.Save(@"D:\1test\pcb\temp\1-3MinEnclosingCircleImage_2.bmp");

                //except top and bottom 
                double minY_2 = yPositions_2.ToArray().Min();
                double maxY_2 = yPositions_2.ToArray().Max();
                List<PointF> theTwoPoints_2 = new List<PointF>();
                double y_length_2 = (maxY_2 - minY_2) / 4;
                for (int i = 0; i < BiggestCircleTotal.Count; i++)
                {
                    //compare point position
                    if (Convert.ToDouble(BiggestCircleTotal[i].Y) > (minY_2 + y_length_2) &&
                        Convert.ToDouble(BiggestCircleTotal[i].Y) < (maxY_2 - y_length_2))  //except top and bottom 
                    {
                        theTwoPoints_2.Add(BiggestCircleTotal[i]);
                    }
                }
                //float angle_temp_2 = 0;
                //float xx_2, yy_2;
                List<float> xTwo_2 = new List<float>();
                List<float> yTwo_2 = new List<float>();
                CircleF centerPointF2 = new CircleF();//small pcb centerPoint
                leftCircleF = new CircleF();         //左点
                rightCircleF = new CircleF();        //右点
                for (int i = 0; i < theTwoPoints_2.Count; i++)
                {
                    xTwo_2.Add(theTwoPoints_2[i].X);
                    yTwo_2.Add(theTwoPoints_2[i].Y);
                }
                // conference leftCircleF and rightCircleF
                for (int i = 0; i < theTwoPoints_2.Count; i++)
                {
                    if (theTwoPoints_2[i].X == xTwo_2.Min())
                    {
                        leftCircleF.Center = theTwoPoints_2[i];
                    }
                    else
                    {
                        rightCircleF.Center = theTwoPoints_2[i];
                    }
                }              
                Image<Bgr, byte> smallPcbResultImage = grayImage.ToBitmap().ToImage<Bgr, byte>();
                x = leftCircleF.Center.X;
                y = leftCircleF.Center.Y;
                // conference ReferencePoint
                ReferencePointF = leftCircleF;
                //----compute Angle----
                //Angle = ComputeAngle(ReferencePointF, rightCircleF);
                //----log----
                //informations.Text += Angle.ToString();
                informations.Text += "圆左点坐标:" + x.ToString() + "," + y.ToString();
                informations.Text += Environment.NewLine;
                centerPointF2.Center = new PointF(float.Parse(x.ToString()), float.Parse(y.ToString()));
                centerPointF2.Radius = 5;
                //----draw----
                smallPcbResultImage.Draw(centerPointF2, new Bgr(255, 0, 0), 5);
                CvInvoke.Line(smallPcbResultImage, new Point((int)rightCircleF.Center.X, (int)rightCircleF.Center.Y), new Point((int)ReferencePointF.Center.X, (int)ReferencePointF.Center.Y), new MCvScalar(255, 255, 255), 2, LineType.EightConnected, 0);                
                //--save--
                smallPcbResultImage.Save(@"D:\1test\pcb\temp\1-4smallPcbResultImage.bmp");
                //pb2.Image = smallPcbResultImage.ToBitmap();
               
            }
            #endregion/* ------------------------------------小的PCB End------------------------------------*/
            else 
            { 
                //------------------------------- using y position to order the point position save center point------------------------------- 
                double minY = yPositions.ToArray().Min();
                double maxY = yPositions.ToArray().Max();
                double minX = xPositions.ToArray().Min();
                double maxX = xPositions.ToArray().Max();
                PointF centerPoint = new PointF();
                CircleF centerCircleF = new CircleF();
           
                List<PointF> theTwoPoints = new List<PointF>();
                double y_length = (maxY - minY) / 4;
                double x_length = (maxX - minX) / 4;
                //x top line
                CvInvoke.Line(ResultImage, new Point((int)(minX + x_length), (int)(minY + y_length)), new Point((int)(maxX - x_length), (int)(minY + y_length)), new MCvScalar(0, 255, 255), 20, LineType.EightConnected, 0);
                //y left line
                CvInvoke.Line(ResultImage, new Point((int)(minX + x_length), (int)(minY + y_length)), new Point((int)(minX + x_length), (int)(maxY - y_length)), new MCvScalar(255, 0, 255), 20, LineType.EightConnected, 0);
                //x bottom line
                CvInvoke.Line(ResultImage, new Point((int)(minX + x_length), (int)(maxY - y_length)), new Point((int)(maxX - x_length), (int)(maxY - y_length)), new MCvScalar(0, 255, 255), 20, LineType.EightConnected, 0);
                //y right line
                CvInvoke.Line(ResultImage, new Point((int)(maxX - x_length), (int)(minY + y_length)), new Point((int)(maxX - x_length), (int)(maxY - y_length)), new MCvScalar(255, 0, 255), 20, LineType.EightConnected, 0);
                for (int i = 0; i < totalPoints.Count; i++)
                {
                    //save center point
                    if (Convert.ToDouble(totalPoints[i].Y) > (minY + y_length) &&
                        Convert.ToDouble(totalPoints[i].Y) < (maxY - y_length) &&                         // except top and botton
                        Convert.ToDouble(totalPoints[i].X) > (minX + x_length) &&
                        Convert.ToDouble(totalPoints[i].X) < (maxX - x_length))  //except left and right 
                    {
                        centerPoint = totalPoints[i];
                        centerCircleF.Center = centerPoint;
                        centerCircleF.Radius = 5;
                        MinEnclosingCircleImage.Draw(centerCircleF, new Gray(255), 1);
                    }
                    else if (Convert.ToDouble(totalPoints[i].Y) > (minY + y_length) &&      //find left and right points
                        Convert.ToDouble(totalPoints[i].Y) < (maxY - y_length) &&                         // except top and botton
                        ((Convert.ToDouble(totalPoints[i].X) > (minX - x_length) && Convert.ToDouble(totalPoints[i].X) < (minX + x_length)) ||
                        (Convert.ToDouble(totalPoints[i].X) < (maxX + x_length) && Convert.ToDouble(totalPoints[i].X) > (maxX - x_length))))  //except left and right 
                    {
                        theTwoPoints.Add(totalPoints[i]);
                    }
                }
                x = centerPoint.X;
                y = centerPoint.Y;
                ReferencePointF.Center = centerPoint;
                informations.Text += "圆中心点坐标:" + x.ToString() + "," + y.ToString();
                informations.Text += Environment.NewLine;
                //leftPoint and rightPoint
                if (theTwoPoints[0].X - theTwoPoints[1].X > theTwoPoints[1].X - theTwoPoints[0].X)
                {
                    rightCircleF.Center = theTwoPoints[0];
                    leftCircleF.Center = theTwoPoints[1];
                }
                else
                {
                    rightCircleF.Center = theTwoPoints[1];
                    leftCircleF.Center = theTwoPoints[0];
                }
                pb2.Image = MinEnclosingCircleImage.ToBitmap();
            }
            //Follow center point to resure left point and right point
            //double roiTopX = grayImage.Width;
            //double roiTopY = grayImage.Height;            
           
            //draw left and right points            
            leftCircleF.Radius = 10;
            rightCircleF.Radius = 10;
            ReferencePointF.Radius = 3;
            ResultImage.Draw(leftCircleF, new Bgr(0, 255, 0), 20);
            ResultImage.Draw(rightCircleF, new Bgr(0, 255, 0), 20);
            ResultImage.Draw(ReferencePointF, new Bgr(0, 0, 255), 10);
            //dra line
            CvInvoke.Line(ResultImage, new Point((int)rightCircleF.Center.X, (int)rightCircleF.Center.Y), new Point((int)ReferencePointF.Center.X, (int)ReferencePointF.Center.Y), new MCvScalar(255, 255, 255), 2, LineType.EightConnected, 0);
            //compute angle
            Angle = ComputeAngle(ReferencePointF, rightCircleF);
            double Angle2 = ComputeAngle(leftCircleF, rightCircleF);
            //--log--
            informations.Text += "Angle:" + Angle.ToString() ;
            informations.Text += "Angle2:" + Angle2.ToString();
            ResultImage.Save(@"D:\1test\pcb\4smallPcbResultImage.bmp");
            pb2.Image = ResultImage.ToBitmap();
        }

步骤描述:

  • 1、二值化
  • 2、寻找二值化后图像的轮廓(设置轮廓周长以及面积范围,保留圆轮廓)
  • 3、使用保留的轮廓进行MinEnclosingCircle(拟合圆)
  • 4、根据圆心计算参考点以及直线的倾斜角度
  • 注意:因为有三种不同的PCB所以对于其中一种使用了小的PCB检测方法

结果图:

描述:考虑到畸变影响因素,大的PCB以中间圆(红色点)为参考点,小的PCB以中间左边圆为参考点,白色线为旋转角度参考线

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值