连通域算法(灰度图像处理)

用FPGA做图像处理的基础知识

  • 在一些工业领域用的图像传感器有哪些?
  • FPGA完成某些机器视觉任务的处理流程
  • 为什么用FPGA进行数据处理能达到最高的实时性

课程b站《从零开始系统学FPGA》

image-20220420095445602

一二比较重要:建立时间、保持时间、插入流水线寄存器提高电路频率等这些概念都是面试必问的;用实时流水线的方式处理各种数据是FPGA运用的精髓;Verilog写代码必备能力

工业上除了会用到手机和相机中常见的面阵传感器之外,还会用到线阵传感器。线阵传感器的分辨率是几k乘1,也就是它只扫描一行图像,主要用于扫描仪里和一些需要扫描传送带上的物料的工业应用场合。

image-20220420100158124

物料传送->机器视觉->执行机构:物料检测分选系统

代码部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
//网上原代码  
1 class AreaMark
2 {
3 public:
4 AreaMark(const Mat src,int offset);
5 int getMarkedArea(vector<vector<int>> &area);
6 void getMarkedImage(Mat &dst);
7
8 private:
9 Mat src;
10 int offset;
11 int numberOfArea=0;
12 vector<int> labelMap;
13 vector<int> labelRank;
14 vector<int> stArea;
15 vector<int> enArea;
16 vector<int> rowArea;
17 vector<int> labelOfArea;
18 vector<pair<int, int>> equalLabels;
19
20 void markArea();
21 void searchArea();
22 void setInit(int n);
23 int findRoot(int label);
24 void unite(int labelA, int labelB);
25 void replaceEqualMark();
26 };
27
28 // 构造函数
29 // imageInput:输入待标记二值图像 offsetInput:0为四连通,1为八连通
30 AreaMark::AreaMark(Mat imageInput,int offsetInput)
31 {
32 src = imageInput;
33 offset = offsetInput;
34 }
35
36 // 获取颜色标记图片
37 void AreaMark::getMarkedImage(Mat &dst)
38 {
39 Mat img(src.rows, src.cols, CV_8UC3, CV_RGB(0, 0, 0));
40 cvtColor(img, dst, CV_RGB2HSV);
41
42 int maxLabel = *max_element(labelOfArea.begin(), labelOfArea.end());
43 vector<uchar> hue;
44 for (int i = 1; i<= maxLabel; i++)
45 {
46 // 使用HSV模型生成可区分颜色
47 hue.push_back(uchar(180.0 * (i - 1) / (maxLabel + 1)));
48 }
49
50 for (int i = 0; i < numberOfArea; i++)
51 {
52 for (int j = stArea[i]; j <= enArea[i]; j++)
53 {
54 dst.at<Vec3b>(rowArea[i], j)[0] = hue[labelOfArea[i]];
55 dst.at<Vec3b>(rowArea[i], j)[1] = 255;
56 dst.at<Vec3b>(rowArea[i], j)[2] = 255;
57 }
58 }
59
60 cvtColor(dst, dst, CV_HSV2BGR);
61 }
62
63 // 获取标记过的各行子区域
64 int AreaMark::getMarkedArea(vector<vector<int>> &area)
65 {
66 searchArea();
67 markArea();
68 replaceEqualMark();
69 area.push_back(rowArea);
70 area.push_back(stArea);
71 area.push_back(enArea);
72 area.push_back(labelOfArea);
73 return numberOfArea;
74 }
75
76 void AreaMark::searchArea()
77 {
78 for (int row = 0; row < src.rows; row++)
79 {
80 // 行指针
81 const uchar *rowData = src.ptr<uchar>(row);
82
83 // 判断行首是否是子区域的开始点
84 if (rowData[0] == 255)
85 {
86 numberOfArea++;
87 stArea.push_back(0);
88 }
89
90 for (int col = 1; col < src.cols; col++)
91 {
92 // 子区域开始位置的判断:前像素为背景,当前像素是前景
93 if (rowData[col - 1] == 0 && rowData[col] == 255)
94 {
95 // 在开始位置更新区域总数、开始位置vector
96 numberOfArea++;
97 stArea.push_back(col);
98 // 子区域结束位置的判断:前像素是前景,当前像素是背景
99 }else if (rowData[col - 1] == 255 && rowData[col] == 0)
100 {
101 // 更新结束位置vector、行号vector
102 enArea.push_back(col - 1);
103 rowArea.push_back(row);
104 }
105 }
106 // 结束位置在行末
107 if (rowData[src.cols - 1] == 255)
108 {
109 enArea.push_back(src.cols - 1);
110 rowArea.push_back(row);
111 }
112 }
113 }
114
115
116
117 void AreaMark::markArea()
118 {
119 int label = 1;
120 // 当前所在行
121 int curRow = 0;
122 // 当前行的第一个子区域位置索引
123 int firstAreaCur = 0;
124 // 前一行的第一个子区域位置索引
125 int firstAreaPrev = 0;
126 // 前一行的最后一个子区域位置索引
127 int lastAreaPrev = 0;
128
129 // 初始化标签都为0
130 labelOfArea.assign(numberOfArea, 0);
131
132 // 遍历所有子区域并标记
133 for (int i = 0; i < numberOfArea; i++)
134 {
135 // 行切换时更新状态变量
136 if (curRow != rowArea[i])
137 {
138 curRow = rowArea[i];
139 firstAreaPrev = firstAreaCur;
140 lastAreaPrev = i - 1;
141 firstAreaCur = i;
142 }
143
144 // 相邻行不存在子区域
145 if (curRow != rowArea[firstAreaPrev] + 1)
146 {
147 labelOfArea[i] = label++;
148 continue;
149 }
150 // 对前一行进行迭代
151 for (int j = firstAreaPrev; j <= lastAreaPrev; j++)
152 {
153 // 判断是否相连
154 if (stArea[i] <= enArea[j] + offset && enArea[i] >= stArea[j] - offset)
155 {
156 if (labelOfArea[i] == 0)
157 // 之前没有标记过
158 labelOfArea[i] = labelOfArea[j];
159 else if (labelOfArea[i] != labelOfArea[j])
160 // 之前已经被标记,保存等价对
161 equalLabels.push_back(make_pair(labelOfArea[i], labelOfArea[j]));
162 }else if (enArea[i] < stArea[j] - offset)
163 {
164 // 为当前行下一个子区域缩小上一行的迭代范围
165 firstAreaPrev = max(firstAreaPrev, j - 1);
166 break;
167 }
168 }
169 // 与上一行不存在相连
170 if (labelOfArea[i] == 0)
171 {
172 labelOfArea[i] = label++;
173 }
174 }
175 }
176
177
178 // 并查集初始化
179 void AreaMark::setInit(int n)
180 {
181 for (int i = 0; i <= n; i++)
182 {
183 labelMap.push_back(i);
184 labelRank.push_back(0);
185 }
186 }
187
188 // 查根
189 int AreaMark::findRoot(int label)
190 {
191 if (labelMap[label] == label)
192 {
193 return label;
194 }
195 else
196 {
197 //路径压缩优化
198 return labelMap[label] = findRoot(labelMap[label]);
199 }
200 }
201
202 // 合并
203 void AreaMark::unite(int labelA, int labelB)
204 {
205 labelA = findRoot(labelA);
206 labelB = findRoot(labelB);
207
208 if (labelA == labelB)
209 {
210 return;
211 }
212 // 秩优化,秩大的树合并秩小的树
213 if (labelRank[labelA] < labelRank[labelB])
214 {
215 labelMap[labelA] = labelB;
216 }
217 else
218 {
219 labelMap[labelB] = labelA;
220 if (labelRank[labelA] == labelRank[labelB])
221 {
222 labelRank[labelA]++;
223 }
224 }
225
226 }
227
228 // 等价对处理,标签重映射
229 void AreaMark::replaceEqualMark()
230 {
231 int maxLabel = *max_element(labelOfArea.begin(), labelOfArea.end());
232
233 setInit(maxLabel);
234
235 // 合并等价对,标签初映射
236 vector<pair<int, int>>::iterator labPair;
237 for (labPair = equalLabels.begin(); labPair != equalLabels.end(); labPair++)
238 {
239 unite(labPair->first, labPair->second);
240 }
241
242 // 标签重映射,填补缺失标签
243 int newLabel=0;
244 vector<int> labelReMap(maxLabel + 1, 0);
245 vector<int>::iterator old;
246 for (old = labelMap.begin(); old != labelMap.end(); old++)
247 {
248 if (labelReMap[findRoot(*old)] == 0)
249 {
250 labelReMap[findRoot(*old)] = newLabel++;
251 }
252 }
253 // 根据重映射结果修改标签
254 vector<int>::iterator label;
255 for (label = labelOfArea.begin(); label != labelOfArea.end(); label++)
256 {
257 *label = labelReMap[findRoot(*label)];
258 }
259
260 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//自己写的:数组的四邻域
#include<iostream>
using namespace std;

#define white 1
#define black 0
#define row 16
#define col 16
#define maxnum 1000
#define offset 0

//0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
int bin_img[row][col] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1,// 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0,// 1
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1,// 2
1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0,// 3
1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0,// 4
0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0,// 5
0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 6
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 7
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 8
0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,// 9
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,// 10
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 11
0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,// 12
0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,// 13
0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,// 14
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0};// 15

int area_start[maxnum];
int area_end[maxnum];
int area_row[maxnum];
int num_area;
void searchArea(void){
int i,j;
int ns=0,ne=0,nr=0;
num_area = 0;

for(i=0;i<row;i++){
if(bin_img[i][0]==white){
num_area++;
area_start[ns++]=0;
}
for(j=1;j<col;j++){
if(bin_img[i][j-1]==black&&bin_img[i][j]==white){
num_area++;
area_start[ns++]=j;
}else if(bin_img[i][j]==black&&bin_img[i][j-1]==white){
area_end[ne++]=j-1;
area_row[nr++]=i;
}
}
if(bin_img[i][col-1]==white){
area_end[ne++]=col-1;
area_row[nr++]=i;
}
}
}

int area_label[maxnum];
int equalLabels[maxnum][2];
void markArea(void){
int i,j;
int nel=0;
int label=1;
int row_current=0;
int index_currentFirstArea=0;
int index_preFirstArea=0;
int index_preLastArea=0;

for(i=0;i<num_area;i++){
area_label[i]=0;
}

for(i=0;i<num_area;i++){
//轮到下一行时,变量更新
if(row_current!=area_row[i]){
row_current = area_row[i];
index_preFirstArea = index_currentFirstArea;
index_preLastArea = i-1;
index_currentFirstArea = i;
}

if(row_current!=area_row[index_preFirstArea]+1){
//相邻行不存在子区域
area_label[i]=label++;
}else{
//当前行与上一行进行比较
for(j=index_preFirstArea;j<=index_preLastArea;j++){
if(area_start[i]<=area_end[j]+offset&&area_end[i]>=area_start[j]-offset){
//相连的情况
if(area_label[i]==0){
//没有标记情况
area_label[i]=area_label[j];
}else if(area_label[i]!=area_label[j]){
//已经标记过,保存等价对
equalLabels[nel][0]=area_label[i];
equalLabels[nel++][1]=area_label[j];
}
}else if(area_end[i]<area_start[j]-offset){
//不相连的情况
if(index_preFirstArea<j-1)
index_preFirstArea=j-1;
j=index_preLastArea;
}
}
}
//这一行循环完与上一行不存在联系
if(area_label[i]==0){
area_label[i] = ++label;
}
}
}

// 等价对处理,标签重映射
int labelMap[maxnum];
int labelRank[maxnum];
void replaceEqualMark(void){
int i,j;

for(i=0;i<num_area;i++){
labelMap[i]=i;
labelRank[i]=0;
}
}

int main(){
int i,j;
int s,e,r,l;
searchArea();
markArea();
// for(int i=0;i<num_area;i++){
// cout<<area_start[i]<<" "<<area_end[i]<<" "<<area_row[i]<<endl;
//// cout<<area_label[i]<<" "<<equalLabels[i][0]<<" "<<equalLabels[i][1]<<endl;
// }
for(i=0;i<num_area;i++){
r=area_row[i];
s=area_start[i];
e=area_end[i];
l=area_label[i];
for(j=s;j<=e;j++){
bin_img[r][j]=l;
}
}
for(i=0;i<row;i++){
for(j=0;j<col;j++){
cout<<bin_img[i][j]<<" ";
}
cout<<endl;
}

return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
//自己写的:改了一半的用链式指针的连通域
#include<stdio.h>
#include <stdlib.h>

#define white 1
#define black 0
#define row 16
#define col 16
#define offset 0

//0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
int bin_img[row][col] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1,// 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0,// 1
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1,// 2
1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0,// 3
1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0,// 4
0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0,// 5
0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 6
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 7
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 8
0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,// 9
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,// 10
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 11
0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,// 12
0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,// 13
0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,// 14
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0};// 15


struct Node{
int data;
struct Node *next;
};
struct Node *area_start,*area_end,*area_row,*area_label;
int num_area;

void Insert(struct Node *head,int data){
struct Node *temp;

temp=(struct Node*)malloc(sizeof(struct Node));
temp->data = data;

temp->next = head->next;
head->next = temp;
}
void Display(struct Node *head){
struct Node*p;
p = head->next;
while(p!=NULL)
{
printf("%d ",p->data);
p=p->next;
}
}

void Delete(struct Node *head){
struct Node *p,*q;
p = head->next;
while(p!=NULL){
q=p->next;
free(p);
p=q;
}
head->next=NULL;
}

void searchArea(void){
int i,j;
num_area=0;

area_start=(struct Node*)malloc(sizeof(struct Node));
area_start->next=NULL;
area_end=(struct Node*)malloc(sizeof(struct Node));
area_end->next=NULL;
area_row=(struct Node*)malloc(sizeof(struct Node));
area_row->next=NULL;

for(i=0;i<row;i++){
if(bin_img[i][0]==white){
num_area++;
Insert(area_start,0);
}
for(j=1;j<col;j++){
if(bin_img[i][j-1]==black&&bin_img[i][j]==white){
num_area++;
Insert(area_start,j);
}else if(bin_img[i][j]==black&&bin_img[i][j-1]==white){
Insert(area_end,j-1);
Insert(area_row,i);
}
}
if(bin_img[i][col-1]==white){
Insert(area_end,col-1);
Insert(area_row,i);
}
}
}

void markArea(void){
int i,j;
int nel=0;
int label=1;
int row_current=area_row->next->data;

struct Node *index_currentFirstArea=area_row->next;
struct Node *index_preFirstArea=area_row->next;
struct Node *index_preLastArea=area_row->next;

area_label=(struct Node*)malloc(sizeof(struct Node));
area_label->next=NULL;
struct Node *pr,*pr_pre,*pl,*ps,*pe;
pr=area_row->next;
pr_pre=area_row;
ps=area_start->next;
pe=area_end->next;

for(i=0;i<num_area;i++){
Insert(area_label,0);
}

pl=area_label->next;
for(i=0;i<num_area;i++){
//轮到下一行时,变量更新
if(row_current!=pr->data){
row_current = pr->data;
index_preFirstArea = index_currentFirstArea;
index_preLastArea = pr_pre;
index_currentFirstArea = pr;
}

if(row_current!=index_preFirstArea->data-1){
//相邻行不存在子区域
pl->data= ++label;
}else{
//当前行与上一行进行比较
struct Node *t1,*t2;
t1=index_preLastArea;
t2=index_preFirstArea;
while(){
if(ps->data<=)
}
for(j=index_preFirstArea;j<=index_preLastArea;j++){
if(area_start[i]<=area_end[j]+offset&&area_end[i]>=area_start[j]-offset){
//相连的情况
if(area_label[i]==0){
//没有标记情况
area_label[i]=area_label[j];
}else if(area_label[i]!=area_label[j]){
//已经标记过,保存等价对
equalLabels[nel][0]=area_label[i];
equalLabels[nel++][1]=area_label[j];
}
}else if(area_end[i]<area_start[j]-offset){
//不相连的情况
if(index_preFirstArea<j-1)
index_preFirstArea=j-1;
j=index_preLastArea;
}
}
}
//这一行循环完与上一行不存在联系
if(area_label[i]==0){
area_label[i] = ++label;
}
pr = pr->next;
pr_pre = pr_pre->next;
ps=ps->next;
}
}


int main()
{
searchArea();
// printf("%d",ps->next);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//自己写的:竞速的四邻域
//0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
int bin_img[row][col] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1,// 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0,// 1
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1,// 2
1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0,// 3
1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0,// 4
0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0,// 5
0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 6
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 7
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 8
0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,// 9
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,// 10
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 11
0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0,// 12
0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,// 13
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,// 14
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0};// 15
int i,j;
int point_count=0;
int point_x,point_y;
int left=0,right=0,top=0,bottom=0;
int n=0;
int point[col+20][2];

for(i=0;i<row;i++){
for(j=0;j<col;j++){
if(bin_img[i][j]==white){
point_count++;
}else{
if(point_count>=2){
point_x = j-point_count/2;
point_y = i;

while((point_x-left)>-1&&bin_img[point_y][point_x-left]==white){
left++;
}
while(bin_img[point_y][point_x+right]==white&&(point_x+right)<col){
right++;
}
while(bin_img[point_y-top][point_x]==white&&(point_y-top)>-1){
top++;
}
while(bin_img[point_y+bottom][point_x]==white&&(point_y+bottom)<row){
bottom++;
}
if((left-right)<3&&(right-left)<3&&(top-bottom)<3&&(bottom-top)<3){
if(!(top==bottom&&top==1&&bottom==1)||!(right==left&&right==1&&left==1)){
point[n][0]=point_x;
point[n++][1]=point_y;
// cout<<"point_count="<<point_count<<endl;
cout<<left<<" "<<right<<" "<<top<<" "<<bottom<<endl;
cout<<"point_x="<<point[n-1][1]<<" point_y="<<point[n-1][0]<<endl;
}
}
left=0,right=0,top=0,bottom=0;
}
point_count=0;
}
}
}

小车使用的最终改版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#define col  MT9V03X_W //宽 120
#define row MT9V03X_H //高 80

#define maxnum 1000
#define offset 0

uint8 bin_img[row][col]; //二值化图
uint8 domains[row][col]; //连通域图

uint8 area_start[maxnum];
uint8 area_end[maxnum];
uint8 area_row[maxnum];
uint8 num_area;
uint8 area_label[maxnum];
uint8 point[col+20][2];
int equalLabels[maxnum][2];

//连通域
void Connect_domains(void){
uint16 i,j;
uint8 s,e,r,l;
searchArea();
markArea();

for(i=0;i<num_area;i++){
r=area_row[i];
s=area_start[i];
e=area_end[i];
l=area_label[i];
for(j=s;j<=e;j++){
domains[r][j]=l;
// ips200_drawpoint(j,r,RED);
// ips200_drawpoint(j+1,r,RED);
}
}
}

void searchArea(void){
uint8 i,j;
uint16 ns=0,ne=0,nr=0;
num_area = 0;

for(i=0;i<row;i++){
if(bin_img[i][0]==white){
num_area++;
area_start[ns++]=0;
}
for(j=1;j<col;j++){
if(bin_img[i][j-1]==black&&bin_img[i][j]==white){
num_area++;
area_start[ns++]=j;
}else if(bin_img[i][j]==black&&bin_img[i][j-1]==white){
area_end[ne++]=j-1;
area_row[nr++]=i;
}
}
if(bin_img[i][col-1]==white){
area_end[ne++]=col-1;
area_row[nr++]=i;
}
}
}

void markArea(void){
uint8 i,j;
// int nel=0;
uint8 label=1;
uint8 row_current=0;
uint8 index_currentFirstArea=0;
uint8 index_preFirstArea=0;
uint8 index_preLastArea=0;

for(i=0;i<num_area;i++){
area_label[i]=0;
}

for(i=0;i<num_area;i++){
//轮到下一行时,变量更新
if(row_current!=area_row[i]){
row_current = area_row[i];
index_preFirstArea = index_currentFirstArea;
index_preLastArea = i-1;
index_currentFirstArea = i;
}

if(row_current!=area_row[index_preFirstArea]+1){
//相邻行不存在子区域
area_label[i]=label++;
}else{
//当前行与上一行进行比较
for(j=index_preFirstArea;j<=index_preLastArea;j++){
if(area_start[i]<=area_end[j]+offset&&area_end[i]>=area_start[j]-offset){
//相连的情况
if(area_label[i]==0){
//没有标记情况
area_label[i]=area_label[j];
}
// else if(area_label[i]!=area_label[j]){
// //已经标记过,保存等价对
// equalLabels[nel][0]=area_label[i];
// equalLabels[nel++][1]=area_label[j];
// }
}else if(area_end[i]<area_start[j]-offset){
//不相连的情况
if(index_preFirstArea<j-1)
index_preFirstArea=j-1;
j=index_preLastArea;
}
}
}
//这一行循环完与上一行不存在联系
if(area_label[i]==0){
area_label[i] = ++label;
}
}
}