原图

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);elseslopeValue = (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;//AngleResult = -(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>();//thresholdImage<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 circlesfor (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();  //121779informations.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 circleImage<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 positionyPositions.Add(circleF.Center.Y);        //point y positiontotalPoints.Add(new PointF(circleF.Center.X, circleF.Center.Y));   //point positioncircleFs.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 circlefor (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();  //121779informations.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);  //displayList<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 positionyPositions_2.Add(circleF.Center.Y);        //point y positionBiggestCircleTotal.Add(new PointF(circleF.Center.X, circleF.Center.Y));   //point positionpointIndex2++;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 positionif (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 centerPointleftCircleF = 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 rightCircleFfor (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 ReferencePointReferencePointF = 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 lineCvInvoke.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 lineCvInvoke.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 lineCvInvoke.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 lineCvInvoke.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 pointif (Convert.ToDouble(totalPoints[i].Y) > (minY + y_length) &&Convert.ToDouble(totalPoints[i].Y) < (maxY - y_length) &&                         // except top and bottonConvert.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 pointsConvert.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 rightPointif (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 lineCvInvoke.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 angleAngle = 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以中间左边圆为参考点,白色线为旋转角度参考线



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

  1. Allegro PCB 开发板制作超级详细步骤

    Allegro PCB 开发板制作总结 一.        所需软件:Orcad captures CIS.allegro.DB  Doctor.pad designed.cam350.对于元器件比较 ...

  2. 海思Hi3519A开发(4.移植OpenCV4.0.1到Hi3519A开发板)

    文章目录 1 准备工作 2 设置 cmake 3 编译 4 移植 5 编译静态库 6 下载 1 准备工作 在 ubuntu 上安装 cmake-gui sudo apt-get install cma ...

  3. win7下将rtt1.2.0移植到4088开发板上

    1.准备工作: 下载rtt1.2.0源码: 安装python2.7: 安装scons: 安装编译器mdk 4.72; 安装串口工具putty; 2.编译源码包: 打开命令窗口cmd,进入rtt1.2. ...

  4. Shp文件导入MySql数据库工具包,只是针对于8.0+以上版本定制开发

    由于最新的geotools工具类不支持8.0+以上的MySQL数据库,故而开发该工具用于数据处理.采用javaFX开发的一个很简单的数据导入工具,对于5.0+的版本,大家参考网上的相关代码即可,也可在 ...

  5. SkylineGlobe 7.0.1 7.0.2版本Web开发 如何实现土方量计算

    土方量计算,或者叫填挖方计算,体积计算,Skyline在很早的版本中就提供了这个的功能. 目前的软件版本,不仅仅可以对地形修改对象进行土方量计算,还可以在FLY工程中导入DEM数字高程模型数据,计算不 ...

  6. ESP8266作为arduino D1 wifi模块应用时引脚序号说明(与UNO对比异同)2.5.0版本开发板库

    在前期的文章中,提到了用D1模块连接阿里云,然后通过APP控制该模块上的LED等开关. 参考文章: 使用arduino D1 wifi模块(WeMos D1)连接阿里云物联网平台并成功实现APP点亮板 ...

  7. 0.1.3 合宙CORE-ESP32-C3开发板用arduino点亮ST7735 1.8寸TFT屏【已更新失效链接2022.07.10】

    9.9的ESP32开发板想用arduino开发,无奈都是用luatos玩,于是折腾了下 目的 用arduino驱动合宙ESP32-C3开发板点亮S7735TFT屏 材料 CORE-ESP32-C3开发 ...

  8. ARMBoot-1.1.0 在 mini2440 开发板上的移植 之稻草人手记

    ARMBoot-1.1.0 在 mini2440 开发板上的移植 之稻草人手记 < snallieATtomDOTcom > 作为U-boot的鼻祖-ARMboot以其小巧玲珑(代码压缩包 ...

  9. ARM开发板移植android4.0流程

    今天用了一块210开发板实现了android4.0的移植. 开发板开箱: 1.210开发板一块, 2.一条双孔交叉串口线, 3.一条网线, 4.一条Mini Usb线, 5.一个电源适配器, 可以自己 ...

最新文章

  1. CVD和ALD薄膜沉积技术应用领域
  2. Visual Studio插件
  3. arthas使用示例:profiler火焰图(CPU)
  4. mysql表的增删查改
  5. 年夜饭之 -- 红烧羊肉
  6. 计算机科学与技术的应用图,安徽农业大学计算机科学与技术视图及其应用.ppt...
  7. Linux串口工具ckermit打印 android log
  8. M1 Mac 屏幕截图录像工具:CleanShot X
  9. pandas + sqlalchemy mysql
  10. c语言二级考试报名费,c语言二级考试(计算机二级c语言报名)
  11. Mac OS下安装MangoDB及其使用配置
  12. 提取文本手机号 易语言代码
  13. 一文带你搞懂Python中的文件操作
  14. 离散数学-2 命题逻辑等值演算
  15. 四种常见的post请求中的参数形式
  16. Python numpy.median函数方法的使用
  17. “由于无法验证发行者,所以WINDOWS已经阻止此软件”的解决方法
  18. 后台管理系统-登录页面
  19. DICOM 图像传输:使用 LeadTools 实现 C-Store SCP 服务
  20. 光电耦合器如何选型以及型号推荐

热门文章

  1. zotero安装教程
  2. springcloud 微服务鉴权_springcloud 微服务权限校验JWT模式获取 token 实战(十二)...
  3. 推免复习之数据结构与算法 佛洛依德算法
  4. 如何使用Wisdom RESTClient定制满足您个性化需求的API文档?
  5. 复旦非全日制研究生计算机,2018年复旦大学信息科学与工程学院非全日制招生计划...
  6. 2013年软件考试报名
  7. 流程图制作软件使用方法:绘制一份漂亮的流程图也很简单
  8. mice和mouse的区别是啥?
  9. 微信相框亮相CES Asia:新增设备物联并打通内容服务
  10. 解决SecureCRT串口日志突然出现乱码的问题