轮廓追踪与C#实现
原文:轮廓追踪与C#实现
轮廓追踪是图像处理中常见的方法,主要目的是追踪二值图像中目标物体的外轮廓,所得结果为单像素闭合轮廓。
流 程:
1. 确定种子点,即追踪的起始像素(如最左上方在轮廓上的像素点);
2. 以相应的追踪规则搜索外部轮廓点。
追踪规则:以种子点为起点,按某以确定方向(如顺时针)寻找与当前轮廓点相邻(8邻域)的轮廓点(第一个相邻),再以 此点为当前轮廓点按照前述方法搜索,直到最后搜索到 的点与种子点相同为止。
注 意:搜索过程中,下一次搜索的起始方向,是上一次搜索到当前像素方向的逆时针45度方向(如果搜索方向是顺时针)。如当前像素在上个轮廓像素的右邻域,那么当前像素可以从其右上角方向搜索,因为这时其上邻域必不是轮廓像素。这样做可以减少算法的计算量。
追踪过程如图1所示:其中红色点表示种子点,黑色点表示轮廓点,蓝色点表示目标物体内部点,搜索方向是顺时针。
我的代码中dircection是搜索方向,定义如下:
int[,] direction = new int[8, 2] { { -1, 0 }, { -1, +1 }, { 0, +1 }, { +1, +1 }, { +1, 0 }, { +1, -1 }, { 0, -1 }, { -1, -1 } };
在代码中的abrect是一个矩形对象,指的是追踪目标所在矩形,这是我原来代码中要用的东西,和这个算法没有关系。
图1.追踪过程图示
C#实现:
unsafe protected void TraceContour(byte* imagedata, int wid, int hei)
{
int stride = (wid + 3) / 4 * 4;
int offset = stride - wid; List<Point> ContourPoints = new List<Point>(); bool bfindstartpoint = false;
int ss = 0;
byte* p = null;
for (int i = 0; i < hei; i++)
{
imagedata[i * stride] = 0;
imagedata[i * stride + wid - 1] = 0;
}
for (int i = 0; i < wid; i++)
{
imagedata[i] = 0;
imagedata[(hei - 1) * stride + i] = 0;
}
//寻找种子点
for (int i = 1; i < hei - 1; i++)
{
p = imagedata + i * stride;
for (int j = 1; j < wid - 1; j++)
{
if (p[j] == 255 && (p[j + 1] + p[j - 1] + p[j - stride] + p[j + stride] + p[j + stride - 1] + p[stride + j + 1] + p[j - stride - 1] + p[j - stride + 1] != 0))
{
bfindstartpoint = true;
ss = i * stride + j;
break;
}
}
if (bfindstartpoint)
{
break;
}
} //寻找种子点失败
if (!bfindstartpoint)
return ; //搜索方向
/*
* 7 0 1
* 6 + 2
* 5 4 3
*/
int begindirect = 0;//从0开始顺时针搜索
int kk = ss;
int k = 0;
int bb = 0;
bool bfindpoint = false;
Point pt = new Point(); while (bfindstartpoint)
{
bfindpoint = false;
k = begindirect;
while (!bfindpoint)
{
bb = kk;
kk += (stride * direction[k, 0] + direction[k, 1]);
int ih = kk / stride;
int iw = kk % stride;
//如果只有一点会死循环
//如果超出边界
if (ih == hei || iw == wid || kk < ss || (kk >= stride * hei))
{
k++;
kk = bb;
if (k == 8)
k = 0;
}
else if (imagedata[kk] == 255)
{
//还原到原坐标系
pt.X = iw + abrect.X;
pt.Y = ih + abrect.Y;
ContourPoints.Add(pt);
if (kk == ss)
bfindstartpoint = false;
begindirect = (k + 7) % 8;//逆时针旋转45度
bfindpoint = true;
}
else
{
kk = bb;
k++;
if (k == 8)
k = 0;
}
}
}
}
轮廓追踪与C#实现的更多相关文章
- 简单的验证码识别(opecv)
opencv版本: 3.0.0 处理验证码: 纯数字验证码 (颜色不同,有噪音,和带有较多的划痕) 测试时间 : 一天+一晚 效果: 比较挫,可能是由于测试的图片是在太小了的缘故. 原理: 验证码 ...
- 基于OpenCV的车辆检测与追踪的实现
最近老师布置了一个作业,是做一个基于视频的车辆检测与追踪,用了大概两周的时间做了一个简单的,效果不是很理想,但抑制不住想把自己的一些认识写下来,这里就把一些网络上的博客整理一下分享给大家,希望帮助到大 ...
- Kinect 开发 —— 骨骼追踪进阶(上)
Kinect传感器核心只是发射红外线,并探测红外光反射,从而可以计算出视场范围内每一个像素的深度值.从深度数据中最先提取出来的是物体主体和形状,以及每一个像素点的游戏者索引信息.然后用这些形状信息来匹 ...
- 基于Cat的分布式调用追踪
Cat是美团点评出的一款APM工具,同类的产品也有不少,知名的开源产品如zipkin和pinpoint:国内收费的产品如oneapm.考虑到Cat在互联网公司的应用比较广,因此被纳入选型队列,我也有幸 ...
- Office 365 如何使用powershell查询邮件追踪
如何使用Powershell 对office365的邮件进行查询追踪 1. 首先链接到Exchange Online 管理上面 $UserCredential = Get-Credential $Se ...
- java性能调优及问题追踪--Btrace的使用
在生产环境中经常遇到格式各样的问题,如OOM或者莫名其妙的进程死掉.一般情况下是通过修改程序,添加打印日志:然后重新发布程序来完成.然而,这不仅麻烦,而且带来很多不可控的因素.有没有一种方式,在不修改 ...
- 追踪记录每笔业务操作数据改变的利器——SQLCDC
对于大部分企业应用来用,有一个基本的功能必不可少,那就是Audit Trail或者Audit Log,中文翻译为追踪检查.审核检查或者审核记录.我们采用Audit Trail记录每一笔业务操作的基本信 ...
- 2016-1-30 Servlet中Session管理(Sesssion追踪)
Session管理(Sesssion追踪)是Web应用程序开发中非常重要的一个主题.这是因为HTTP是无状态的,在默认情况下,Web服务器不知道一个HTTP请求是来自初次用户,还是来自之前已经访问过的 ...
- Metaio获取当前追踪的对象的方法
重写 onTrackingEvent获取TrackingValues集合,然后通过TrackingValues的state属性的isTrackingState()方法判断是否为追踪状态,或者直接使用s ...
随机推荐
- WPF Opacity 最小值多少会被击穿
粗略测试 这样也行.再小不懂咯(跟Double精度有关???) <WrapPanel.Background> <SolidColorBrush x:Name="opacit ...
- [GeekBand ] 利用 pass by reference -to -const 编写高效规范的 c++代码
本文参考资料 : GeekBand 侯捷老师,学习笔记 Effective C ++ 侯捷译 条款20 开发环境采用:VS2013版本 首先:分析值传递的缺点 (一) class Person{ p ...
- js css 实现简单的计算器
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Android菜鸟的成长笔记(22)——Android进程间传递复杂数据(AIDL)
在上一篇中介绍了Andorid中的进程间的通信方式AIDL,本篇文章将介绍传递复杂数据的AIDL Service 下面通过一个示例说明: 本例子中用到了两个自定义类型:Person与Pet, 其中Pe ...
- Android 对.properties文件的读取
/** * * @param filepath .properties文件的位置 */ public void checkFileExists(String filepath){ File file ...
- 读取Jar包外面的配置文件
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/shenxiandashu/article/details/79193705 比较常用的方法是将pro ...
- C#之Linq、where()、FindAll()的区别
原地址 C#之Linq.where().FindAll()的区别 对于实现了IEnumerable接口的类.类型.集合可以使用Linq.Linq的扩展方法where().FindAll()来查询符合谓 ...
- 如何向数据库添加时同时返回ID
我们在做项目开发时很多时候都需要数据库的增删改查,而添加数据后又想得到该项数据在数据库中的主键值,这里有一个非常方便的方法可以在插入数据的同时获得主键值. public void save(Perso ...
- eclipes 常用的快捷键 , 修改字体
内容辅助键 Alt+/ 自动补齐main方法 main 然后 Alt+/ 自动补齐输出语句 syso 然后 Alt+/ 格式化Ctrl+Shift+f 代码区域右键 -- Source – Fo ...
- 嵌套函数中的this
function countDown(){ var self = this; var doWork = function(){ console.log(this);//window console.l ...