图像轮廓跟踪
最近闲来无事,做了一个关于图像轮廓提取的事情,觉得提有意思的,所以想拿来与大家分享。全部代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 private void OutLine_Click(object sender, EventArgs e)
2 {
3 if (bitMap != null)
4 {
5 ImageFeature imgFeature = new ImageFeature(bitMap);
6 imgFeature.Draw();
7 Invalidate();
8 }
9 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class ImageFeature
2 {
3 public Bitmap bitMap; //图像
4 private int w, h; //图像宽、高
5 public int[,] binary; //图像二值化数组
6 private int[] baseStartPoint = new int[2]; //图像基本起点坐标
7 private int[] standardStartPoint = new int[2]; //图像标准起点坐标
8
9 private int[,] boundArray; //边界点集合
10 private int count = 0; //边界点个数
11 private int[] codes; //链码数组
12
13 public ImageFeature(Bitmap b)
14 {
15 bitMap = b;
16 w = b.Width;
17 h = b.Height;
18 binary = new int[w, h];
19 }
20
21 /// <summary>
22 /// 图像二值化函数
23 /// </summary>
24 public void ToBianry()
25 {
26 for (int j = 0; j < h; j++)
27 for (int i = 0; i < w; i++)
28 if (bitMap.GetPixel(i, j).B > 128) binary[i, j] = 0;
29 else binary[i, j] = 1;
30 }
31
32 /// <summary>
33 /// 图像基本起点的查找
34 /// 从下而上、从左到右
35 /// </summary>
36 private void FindBaseStartPoint()
37 {
38 for(int i=0;i<w;i++)
39 for(int j=h-1;j>=0;j--)
40 if (binary[i, j] == 1)
41 {
42 baseStartPoint[0] = i;
43 baseStartPoint[1] = j;
44 j = -1;
45 i = w;
46 }
47 }
48
49 /// <summary>
50 /// 图像轮廓跟踪,以逆时针八个方向为准
51 /// →、↗、↑、↖、←、↙、↓,↘
52 /// </summary>
53 private void OutLine()
54 {
55 int[,] director = { {1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1},{0,1},{1,1}}; //八个方向向量
56 bool bFindBasePoint = false; //是否已经找到了原启始点
57 int k=0; //方向向量循环变量
58 bool bFindNextPoint = false; //是否已经找到下一个点
59 int X, Y; //点坐标中间变量
60 boundArray=new int[w*h/8,2]; //对边界点集的设定
61 int[] codeArray=new int[w*h/8];
62 boundArray[0,0]=baseStartPoint[0];
63 boundArray[0,1]=baseStartPoint[1];
64 while (!bFindBasePoint)
65 {
66 bFindNextPoint = false;
67 while(!bFindNextPoint)
68 {
69 X = boundArray[count, 0] + director[k, 0];
70 Y = boundArray[count, 1] + director[k, 1];
71 if (X < 0) X = 0;
72 if (X> w) X = w;
73 if (Y < 0) Y = 0;
74 if (Y > h) Y = h;
75 if (binary[X, Y] == 1)
76 {
77 bFindNextPoint = true;
78 codeArray[count] = k;
79 count++;
80 //记录边界点坐标
81 boundArray[count, 0] = X;
82 boundArray[count, 1] = Y;
83 if (X == baseStartPoint[0] && Y == baseStartPoint[1]) bFindBasePoint = true;
84 k -= 2;
85 if (k < 0) k += 8;
86 }
87 else
88 {
89 k++;
90 if (k == 8) k = 0;
91 }
92 }
93 }
94
95 //规范化两码
96 int max=0,num=0,pointSite=0,tem_i;
97 for (int i = 0; i < count; i++)
98 {
99 if (codeArray[i] == 0)
100 {
101 tem_i = i;
102 num = 1;
103 while (codeArray[i + 1] == 0)
104 {
105 num++;
106 i++;
107 }
108 if (num > max)
109 {
110 max = num;
111 pointSite = tem_i;
112 }
113 }
114 }
115 codes=new int[count]; //链码数组
116 for(int i=0;i<count-pointSite;i++) codes[i]=codeArray[i+pointSite];
117 for(int i=0;i<pointSite;i++) codes[count-pointSite+i]=codeArray[i];
118 standardStartPoint[0] = boundArray[pointSite, 0];
119 standardStartPoint[1]=boundArray[pointSite,1];
120 }
121
122 /// <summary>
123 /// 描绘轮廓坐标
124 /// </summary>
125 private void DrawOutLine()
126 {
127 for (int j = 0; j < h; j++)
128 for (int i = 0; i < w; i++) bitMap.SetPixel(i, j, Color.FromArgb(255, 255, 255));
129 for (int i = 0; i < count; i++) bitMap.SetPixel(boundArray[i, 0], boundArray[i, 1], Color.FromArgb(0, 0, 0));
130 }
131
132 /// <summary>
133 /// 画轮廓
134 /// </summary>
135 public void Draw()
136 {
137 ToBianry();
138 FindBaseStartPoint();
139 OutLine();
140 DrawOutLine();
141 }
142 }
图像处理的过程:
我们要打开的图片是:
经过轮廓提取操作以后我们可以得到的结果图片是:
这是通过WinForm来实现的。具体的细节,我在这就不赘述了。我希望能够给大家带来帮助同时也希望大家能够多多的支持和提宝贵建议。