最近遇到需要求图形轮廓中距离最远的点,即长轴。

网上查了一些资料,思路如下。

1. 利用OpenCV提取图形的轮廓点。

2. 把提取到的所有轮廓点当做一个集合,再次提取最外面的轮廓。

3. 用凸包旋转卡克方法求解。

  1         private async void Calculate()
  2         {
  3
  4
  5             var a = new Image<Bgr, byte>((Bitmap)pictureBox1.Image);
  6             var b = new Image<Gray, byte>(a.Width, a.Height);
  7             var c = new Image<Gray, byte>(a.Width, a.Height);
  8             var d = new Image<Bgr, byte>(a.Width, a.Height);
  9
 10             var t1 = trackBar1.Value;
 11             var t2 = trackBar2.Value;
 12
 13             CvInvoke.Canny(a, b, t1, t2);
 14             var con = new VectorOfVectorOfPoint();
 15             CvInvoke.FindContours(b, con, c, RetrType.Ccomp, ChainApproxMethod.ChainApproxSimple);
 16
 17
 18             var con1 = con.ToArrayOfArray();
 19             var con2 = Array.ConvertAll<Point[], PointF[]>(con1, new Converter<Point[], PointF[]>(PointToPointF));
 20
 21             var points = new List<PointF>(con2.Length);
 22             foreach (PointF[] t in con2)
 23             {
 24                 for (int j = 0; j < t.Length; j++)
 25                 {
 26                     points.Add(t[j]);
 27                 }
 28             }
 29
 30             //找出凸包
 31             var hull = CvInvoke.ConvexHull(points.ToArray(), true);
 32
 33             var color = new MCvScalar(34, 177, 76);
 34             //画出轮廓
 35             for (int j = 0; j < hull.Length; j++)
 36             {
 37                 var p1 = new Point((int)(hull[j].X + 0.5), (int)(hull[j].Y + 0.5));
 38                 Point p2;
 39                 if (j == hull.Length - 1)
 40                     p2 = new Point((int)(hull[0].X + 0.5), (int)(hull[0].Y + 0.5));
 41                 else
 42                     p2 = new Point((int)(hull[j + 1].X + 0.5), (int)(hull[j + 1].Y + 0.5));
 43                 //CvInvoke.Circle(d, p1, 3, color);
 44                 CvInvoke.Line(a, p1, p2, color);
 45             }
 46
 47             int pp1 = 0, pp2 = 0, pp3 = 0;
 48             Find(hull, ref pp1, ref pp2, ref pp3, ref a);
 49
 50             Console.WriteLine("Find1 p1={0}, p2={1}", pp1, pp3);
 51
 52             double k = 0, bb = 0d;
 53             CalculateLineFormula(hull[pp1], hull[pp2], ref k, ref bb);
 54
 55             var tmp1 = new Point((int)(hull[pp1].X + 0.5), (int)(hull[pp1].Y + 0.5));
 56
 57             //var tmp2 = new Point((int)(hull[pp2].X + 0.5), (int)(hull[pp2].Y + 0.5));
 58             var tmp3 = new Point((int)(hull[pp3].X + 0.5), (int)(hull[pp3].Y + 0.5));
 59             CvInvoke.Line(a, tmp1, tmp3, color);
 60             imageBox1.Image = a;
 61
 62         }
 63
 64
 65
 66          /// <param name="p2Index"></param>
 67         public void Find2(PointF[] points, ref int p1Index,  ref int p3Index)
 68         {
 69             var max = double.MinValue;
 70
 71             for (int i = 0; i < points.Length; i++)
 72              {
 73                 for (int j = 0; i < points.Length; i++)
 74                 {
 75                     var dis = CalculateDisOfPoints(points[i], points[j]);
 76                     if (!(dis > max)) continue;
 77                     max = dis;
 78                     p1Index = i;
 79                     p3Index = j;
 80
 81                     Console.WriteLine("Find2 max={0}", max);
 82                 }
 83              }
 84         }
 85
 86
 87         private Point ConvetT(PointF p)
 88         {
 89             return new Point((int)p.X, (int)p.Y);
 90         }
 91
 92
 93
 94         /// <summary>
 95         /// 计算两个距离最长的对点
 96         /// </summary>
 97         /// <param name="points"></param>
 98         /// <param name="p1Index"></param>
 99         /// <param name="p2Index"></param>
100         public void Find(PointF[] points, ref int p1Index, ref int p2Index, ref int p3Index, ref Image<Bgr, byte> image)
101         {
102
103             var maxYPos = -1;
104             var minYPos = -1;
105             var maxDis = 0d;
106
107             var len = points.Length;
108             //先寻找最大的Y
109             FindMax(points, ref maxYPos, ref minYPos);
110             p1Index = maxYPos;
111             p2Index = (maxYPos + 1) % len;
112             p3Index = minYPos;
113             //对重点
114             maxDis = CalculateDisOfPoints(points[maxYPos], points[minYPos]);
115             Console.WriteLine("max={0}", maxDis);
116             var cnt = 0;
117
118             var n1 =  (maxYPos )%len;
119             var n2 =(minYPos) % len ;
120
121             //四个向量
122             PointF vec1, vec2, vec3, vec4;
123             vec1 = new PointF(1, 0); //指向右边
124             vec3= new PointF(-1,0); //指向左边
125             var offset1 = 0;
126             var offset2 = 0;
127             //顺时针旋转一周
128             var color = new MCvScalar(34, 177, 76);
129             while(offset1<len && offset2<len)
130             {
131                 var tmpImg = image.Copy();
132                 var p1 = points[ (n1+offset1)%len];
133                 var p2 = points[ (n1+offset1+1)%len];
134                 vec2 = new PointF(p2.X - p1.X, p2.Y - p1.Y);
135
136
137                 var p3 = points[ (n2+offset2)%len];
138                 var p4 = points[ (n2 + offset2+1) % len];
139                 vec4= new PointF(p4.X - p3.X, p4.Y - p3.Y);;
140
141                 //计算向量夹角
142                 var ang12 = CalculateAngle(vec1, vec2);
143                 var ang34 = CalculateAngle(vec3, vec4);
144
145                 var dis = 0d;
146                 if(ang12<ang34)
147                 {
148                     //12夹角比较小, 计算p2与p3的距离
149                     dis = CalculateDisOfPoints(p2, p3);
150                     if (dis  -maxDis>0.000001)
151                     {
152                         maxDis = dis;
153                         p1Index = (n1 + offset1 + 1) % len;
154                         p3Index = (n2 + offset2) % len;
155
156                         //CvInvoke.Line(image, ConvetT(points[p1Index]), ConvetT(points[p3Index]), color);
157                         //imageBox1.Image = image;
158                     }
159
160                     //经过p3点的与vec1反方向的平行线
161                     vec3 = new PointF(-vec1.X, -vec1.Y);
162                     //更新向量
163                     vec1 = vec2;
164
165                     //转动
166                     offset1++;
167
168                     Console.WriteLine("Find1 max={0}", maxDis);
169                 }
170                 else
171                 {
172                     //12夹角比较小, 计算p2与p3的距离
173                     dis = CalculateDisOfPoints(p1, p4);
174                     if (dis - maxDis > 0.000001)
175                     {
176                         maxDis = dis;
177                         p1Index = (n1 + offset1) % len;
178                         p3Index = (n2 + offset2 + 1) % len;
179                     }
180
181                     //转动
182                     offset2++;
183                     //经过p3点的与vec1反方向的平行线
184                     vec1 = new PointF(-vec3.X, -vec3.Y);
185                     vec3 = vec4;
186                     Console.WriteLine("Find1 max={0}", maxDis);
187                 }
188             }
189         }
190
191
192         /// <summary>
193         /// 计算经过两个点p1,p2的直线
194         /// </summary>
195         /// <param name="p1">点1</param>
196         /// <param name="p2">点2</param>
197         /// <param name="k">斜率</param>
198         /// <param name="b"></param>
199         private void CalculateLineFormula(PointF p1, PointF p2, ref double k,ref double b)
200         {
201             var dX = p1.X - p2.X;
202             var dY = p2.Y - p2.Y;
203
204             if(dX==0)
205             {
206                 //X=C
207                 k = 1;
208                 b = 0;
209
210             }
211             else if(dY==0)
212             {
213                 k = 0;
214                 b = 0;
215             }
216             else
217             {
218                 k = (double)dY / dX;
219                 b = p1.Y - p1.X * k;
220             }
221         }
222
223         /// <summary>
224         /// 计算平行线的距离
225         /// </summary>
226         /// <param name="k"></param>
227         /// <param name="b1"></param>
228         /// <param name="b2"></param>
229         /// <returns></returns>
230         private double CalculateLinesDis(double k, double b1, PointF p1, PointF p2)
231         {
232             var toll=0.000001d;
233             if (Math.Abs(k) < toll)  // x=常熟
234                 return Math.Abs(p1.X-p2.X);
235             else    if (Math.Abs(k)-1 < toll)   //y=常数
236                 return Math.Abs(p1.Y-p2.Y);
237             else
238             {
239                 //line 1, ax+by=c
240                 var a = -k;
241                 var b = 1;
242                 var c = b1;
243                 //计算p2到 line1的距离
244                 return Math.Abs(a * p1.X + b * p1.Y + c) / Math.Sqrt(a * a + b * b);
245             }
246
247         }
248
249
250
251         /// <summary>
252         /// 先寻找一对对踵点
253         /// </summary>
254         /// <param name="points"></param>
255         /// <param name="maxPos"></param>
256         /// <param name="minPos"></param>
257         private void FindMax(PointF[] points, ref int maxPos, ref int minPos)
258         {
259             var max = double.MinValue;
260             var min = double.MaxValue;
261
262             for (int i = 0; i < points.Length; i++)
263             {
264                 if(points[i].Y>max)
265                 {
266                     max = points[i].Y;
267                     maxPos = i;
268                 }
269                 if (points[i].Y < min)
270                 {
271                     min = points[i].Y;
272                     minPos = i;
273                 }
274             }
275
276         }
277
278
279
280         private double CalculateDisOfPoints(PointF p1, PointF p2)
281         {
282             return Math.Sqrt( (p1.Y-p2.Y)*(p1.Y-p2.Y)+(p1.X-p2.X)*(p1.X-p2.X));
283         }
284
285
286         /// <summary>
287         /// 计算两个向量的夹角,0-180度
288         /// </summary>
289         /// <param name="vec1">向量1</param>
290         /// <param name="vec2">向量2</param>
291         /// <returns></returns>
292         private double CalculateAngle(PointF  vec1, PointF vec2)
293         {
294             //var ang=Math.Atan(k2-k1)
295
296             var toll=0.0000001;
297
298             if (vec1.X * vec2.X + vec1.Y * vec2.Y < toll)
299                 return 90;
300
301
302             if(Math.Abs(vec1.X)<toll  )
303             {
304
305             }
306
307
308             var sum1 = Math.Sqrt(vec1.X*vec1.X+vec1.Y*vec1.Y);
309             var sum2 = Math.Sqrt(vec2.X * vec2.X + vec2.Y * vec2.Y);
310
311             if (sum1 + sum2 < toll)
312                 return 0;
313
314             var sum3 = vec1.X * vec2.X + vec1.Y * vec2.Y;
315             var ang = Math.Acos(sum3 / (sum1 * sum2))*180/Math.PI;
316             return ang;
317         }

效果如下:

参考资料:

http://www.cnblogs.com/Booble/archive/2011/04/03/2004865.html

转载于:https://www.cnblogs.com/fantasy-zhtr/p/6200724.html

轮廓中对踵点/旋转卡壳相关推荐

  1. 最远对踵点 旋转卡壳

    original link - http://poj.org/problem?id=2187 题意: 求最远点对 推荐 https://blog.csdn.net/wang_heng199/artic ...

  2. 旋转卡壳凸包(不用一下子就学完所有)

    目录 前言 参考博客 前置知识 1.极角排序 2.凸包(默认逆时针) 3.对踵点 旋转卡壳能解决的各类问题 1.计算距离 1.1凸多边形直径 1.2凸多边形宽 1.3凸多边形间最大距离 1.4凸多边形 ...

  3. LA 4728 (旋转卡壳) Squares

    题意: 求平面上的最远点对距离的平方. 分析: 对于这个数据量枚举肯定是要超时的. 首先这两个点一定是在凸包上的,所以可以枚举凸包上的点,因为凸包上的点要比原来的点会少很多,可最坏情况下的时间复杂度也 ...

  4. 模板:旋转卡壳(计算几何)

    所谓旋转卡壳,就是旋转起来的卡壳 (逃) 前言 前置知识:凸包 个人感觉很像 two-pointers 算法. 能够在优秀的线性时间复杂度内完成总多求最值(周长.面积-)的神奇操作. 解析 给出情境: ...

  5. 旋转卡壳算法(转载)

    https://www.cnblogs.com/little-w/p/3579603.html 转自:http://blog.csdn.net/acmaker/article/details/3188 ...

  6. 计算几何之旋转卡壳算法

    一.目录 一些历史: 1978年, M.I. Shamos's Ph.D. 的论文"Computational Geometry"标志着计算机科学的这一领域的诞生. 当时他发表成果 ...

  7. 凸包问题--旋转卡壳

    前情提要: 1978年,M.I.Shamos在论文<Computational Ceometry>中介绍了一种寻找凸多边形直径的线性算法. Shamos的算法就像绕着多边形旋转一对卡壳,因 ...

  8. 计算几何之 旋转卡壳 代码模板与证明

    旋转卡壳 旋转卡壳这个算法很形象,一般用来在O(nlogn)O(nlogn)O(nlogn)的时间复杂度下求最远点对问题,就是求平面中任意两点的最远距离. 一般求最远点对问题得枚举两个点,所以复杂度是 ...

  9. [POJ2187]Beauty Contest(计算几何-旋转卡壳-最远点对)

    题目: 我是超链接 题解: 值得一提的是,这是一个"不定向"算法,为什么呢,因为ta的名字不定哈哈哈,旋转卡壳一共有2*3*2*2=24种不同的读音哦 旋转卡壳可以解决:凸多边形最 ...

最新文章

  1. Eclipse 快捷键(转载)
  2. 为程序员量身定做的目标
  3. python3之MongoDB
  4. Leetcode--239. 滑动窗口最大值
  5. Word 相关的快捷键
  6. .net EventHandler 事件处理
  7. C语言宏的特殊用法和几个坑 (转)
  8. HTML+CSS网页设计视频教程
  9. 怎么设置电脑防火墙ping启用_如何通过windows防火墙启用和禁用ping命令
  10. 面试现场说要轮岗,实际岗位是地推
  11. write()与 read() 函数用法(C语言)
  12. SpringBoot + Sharding JDBC 读写分离、分库分表
  13. iframe 接班人-微前端框架 qiankun 在中后台系统实践
  14. 【虚幻引擎】UE4/UE5 后期处理盒子(PostProcessVolume)
  15. BZOJ2215 : [Poi2011]Conspiracy
  16. 捷信总经理Ondrej:愿为中欧企业间的长远发展与互惠共赢而努力
  17. 如何使用API接口查询物流信息?
  18. 互联网时代下的十大商业模式
  19. 微信昵称表情符号前端显示问题
  20. stm32f103c8t6 TIM2定时器1ms中断

热门文章

  1. 【实测有效】“解决国内访问s3.amazonaws.com下载文件非常缓慢的问题”
  2. jsTree 组件官方文档学习
  3. REMIND Your Neural Network to Prevent Catastrophic Forgetting 翻译
  4. 基于React的图片预览组件
  5. 装箱和拆箱,自动装箱和自动拆箱
  6. Matlab RoboticToolBox(一)Link参数、三自由度/四自由度逆运动学
  7. c语言for循环如何打印菱形
  8. Go汇编入门资料【强!!!】
  9. 表格内容居中css样式,css表格中的内容如何居中?css表格中的文本样式介绍
  10. 软件开发——软技能(一、IDE)