-
Notifications
You must be signed in to change notification settings - Fork 3
/
getBallPosition.m
171 lines (159 loc) · 5.09 KB
/
getBallPosition.m
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
%% 获取所有球的位置,并识别出白球、瞄准环、瞄准的球
%% 图像处理
% 提取 hue (色度图)
tempImage = rgb2hsv(Table.outerImage.rgb);
Table.outerImage.h = tempImage(:, :, 1);
% Table.outerImage.s = tempImage(:, :, 2);
% Table.outerImage.v = tempImage(:, :, 3);
% hue(色度),球桌背景色 h 值为归一化值,将归一化映射到 0-360 度
screenTemp_h = Table.outerImage.h * 360;
% 二值化,阈值 160 左右
screenTemp_bw_withHole = (screenTemp_h < 100 | 200 < screenTemp_h);
% 填充
screenTemp_bw = imfill(screenTemp_bw_withHole, 'holes');
% 调试
% figure, imshow(screenTemp_bw);
%% 去除六个洞的干扰
% 生成蒙版,黑边,白心
tempEdgeWidth = round(Table.sizeMassArea.x - Table.sizeInside.x);
mask = ones(size(screenTemp_bw));
% 左边
mask(:, 1:tempEdgeWidth) = 0;
% 右边
mask(:, end-tempEdgeWidth:end) = 0;
% 上边
mask(1:tempEdgeWidth, :) = 0;
% 下边
mask(end-tempEdgeWidth:end, :) = 0;
% 应用蒙版
screenTemp_bw = mask & screenTemp_bw;
% 调试模式
% figure, imshow(screenTemp_bw);
%% 圆形检测
% 灰度化
screenTemp_bw = screenTemp_bw*255;
% 检测圆形
tempRadius = Ball.sizeRadius;
threshold_min = tempRadius - tempRadius * 0.45;
threshold_max = tempRadius + tempRadius * 0.5;
threshold_min = round(threshold_min);
threshold_max = round(threshold_max);
[centers, radius] = imfindcircles(screenTemp_bw, [threshold_min threshold_max], ...
'ObjectPolarity', 'bright', ...
'Method', 'PhaseCode', ...
'Sensitivity', 0.9, ...
'EdgeThreshold',0.09);
% 绘制圆形
% 调试
% tempImage = Table.outerImage.rgb;
% L = size(radius);
% for i = 1:L(1)
% cx = centers(i,1);
% cy = centers(i,2);
% cr = radius(i);
% %img = insertShape(img, 'circle', [cx cy cr], 'LineWidth',2,'Color','b');
% tempImage = insertShape(tempImage, 'circle', [cx cy cr], 'LineWidth',2,'Color','blue');
% end
% figure, imshow(tempImage);
%% 分辨白球、瞄准环、普通球、瞄准的球
% 瞄准环:特征,中心为空
sampleWidth = 2;
Ball.center.aimRing = [0, 0];
Ball.center.aimRing_index = 0;
Ball.center.aimRing_radius = 0;
for i = 1:length(radius)
sampleX = centers(i,1);
sampleY = centers(i,2);
% 采样
x = round(sampleX - sampleWidth/2);
y = round(sampleY - sampleWidth/2);
sampleM = getImageArea(screenTemp_bw_withHole, x, y, sampleWidth, sampleWidth);
% 对比
if sum(sum(sampleM)) < 4
Ball.center.aimRing = [sampleX, sampleY];
Ball.center.aimRing_index = i;
Ball.center.aimRing_radius = radius(i);
break
end
end
% 白球:特征,与瞄准环之间有连线,同时测算一下距离,区分目标球
sampleWidth = 4;
Ball.center.whiteBall = [0, 0];
Ball.center.whiteBall_index = 0;
Ball.center.whiteBall_radius = 0;
for i = 1:length(radius)
% 跳过瞄准环
if Ball.center.aimRing_index == i
continue
end
% 计算线段的中心坐标
sampleX = (centers(i,1) + Ball.center.aimRing(1)) / 2;
sampleY = (centers(i,2) + Ball.center.aimRing(2)) / 2;
% 测算下与所有球的距离,跳过临近的球
dx = centers(i,1) - Ball.center.aimRing(1);
dy = centers(i,2) - Ball.center.aimRing(2);
distance = sqrt(dx^2 + dy^2);
K = distance/Ball.sizeDiameter; % 归一化
if 0.7 < K && K < 1.5
continue;
end
% 采样
x = round(sampleX - sampleWidth/2);
y = round(sampleY - sampleWidth/2);
sampleM = getImageArea(screenTemp_bw_withHole, x, y, sampleWidth, sampleWidth);
% 对比
if sum(sum(sampleM)) > 4
Ball.center.whiteBall = [centers(i,1), centers(i,2)];
Ball.center.whiteBall_index = i;
Ball.center.whiteBall_radius = radius(i);
break
end
end
% 瞄准的球:特征,与瞄准环间距接近球的直径
Ball.center.targetBall = [0, 0];
Ball.center.targetBall_index = 0;
Ball.center.targetBall_radius = 0;
for i = 1:length(radius)
% 跳过瞄准环
if Ball.center.aimRing_index == i
continue
end
% 跳过白球
if Ball.center.whiteBall_index == i
continue
end
% 计算中心距离
sampleX = centers(i,1);
sampleY = centers(i,2);
dx = sampleX - Ball.center.aimRing(1);
dy = sampleY - Ball.center.aimRing(2);
distance = sqrt(dx^2 + dy^2);
K = distance/Ball.sizeDiameter; % 归一化
% 对比
if 0.8 < K && K < 1.2
Ball.center.targetBall = [centers(i,1), centers(i,2)];
Ball.center.targetBall_index = i;
Ball.center.targetBall_radius = radius(i);
break
end
end
% 普通球,排除以上的部分球为普通球
Ball.center.normalBall = [];
Ball.center.normalBall_radius = [];
for i = 1:length(radius)
% 跳过瞄准环
if Ball.center.aimRing_index == i
continue
end
% 跳过白球
if Ball.center.whiteBall_index == i
continue
end
% 跳过目标球
if Ball.center.targetBall_index == i
continue
end
% 添加进 普通球
Ball.center.normalBall = [Ball.center.normalBall; [centers(i,1), centers(i,2)]];
Ball.center.normalBall_radius = [Ball.center.normalBall_radius, radius(i)];
end