目录
效果展示
基础理论(HSV)
为什么用HSV空间而不是RGB空间?
HSV
1、Hue(色相)
2、Value(明度)
3、Saturation(饱和度)
一、初始化
滑动条初始化
1、创建回调函数
2、窗口设置(名称)
3、滑动条设置
代码
二、运动函数
三、舵机控制
四、在HSV空间下获取二值图
1、获取滑动条的值
2、转HSV(三通道:H、S、V)
3、转二值图(单通道阈值处理)
4、结合HSV三个通道,得到最终二值图
代码
五、图像处理(总)
1、打开摄像头
2、获取HSV色彩空间得到的二值图
3、高斯滤波
4、开运算去噪
5、闭运算
6、霍夫圆检测
原理
API
6-1、霍夫圆检测
6-2、获取圆心和半径坐标
6-3、画圆
代码
六、运动控制
总代码
效果展示
基础理论(HSV)
为什么用HSV空间而不是RGB空间?
因为RGB通道并不能很好地反映出物体具体的颜色信息。
而HSV空间能够非常直观的表达色彩的明暗、色调、以及鲜艳程度,方便进行颜色之间的对比。
(RGB受光线影响很大,所以采取HSV)
这里用HSV的目的:得到合适的二值图。
HSV
Hue(H):色调、色相(具体的颜色)
Saturation(S):饱和度、色彩纯净度
Value(V):明度
Hue范围是[0,179],饱和范围是[0,255],值范围是[0,255]
(写代码的时候,犯了蠢错误:把3个都设成了179,发现死活调不对)
1、Hue(色相)
Hue:色相(具体的颜色)
2、Value(明度)
明度:色彩的明亮程度,单通道亮度(并不等同于整体发光量)。
(明度越高越白,越低越黑,一般提高明度会同时提高R、G、B三通道的数值)
3、Saturation(饱和度)
Saturation:饱和度、色彩纯度(越低越灰,越高越纯) 。
(一般调高饱和度会降低RGB中相对较低的数值,凸显主要颜色的纯度。 )
B站视频讲解:
短动画慢语速1分钟讲清影视调色中色彩形成原理基础——RGB与HSV
一、初始化
滑动条初始化
这次的初始化,除了电机、舵机、窗口等等的初始化,还有滑动条的初始设置。
在创建滑动条之前:
1、需要设置窗口名称,不然窗口都没有,自然也就无法设置滑动条了。
2、创建回调函数。
1、创建回调函数
1
2def nothing(*arg): pass
2、窗口设置(名称)
1
2
3
4
5def Trackbar_Init(): # 1 create windows cv2.namedWindow('h_binary') cv2.namedWindow('s_binary') cv2.namedWindow('v_binary')
3、滑动条设置
1
2
3
4
5
6
7
8# 2 Create Trackbar cv2.createTrackbar('hmin', 'h_binary', 6, 179, nothing) cv2.createTrackbar('hmax', 'h_binary', 26, 179, nothing) cv2.createTrackbar('smin', 's_binary', 110, 255, nothing) cv2.createTrackbar('smax', 's_binary', 255, 255, nothing) cv2.createTrackbar('vmin', 'v_binary', 140, 255, nothing) cv2.createTrackbar('vmax', 'v_binary', 255, 255, nothing) # 创建滑动条 滑动条值名称 窗口名称 滑动条值 滑动条阈值 回调函数
代码
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
50def Motor_Init(): global L_Motor, R_Motor L_Motor= GPIO.PWM(l_motor,100) R_Motor = GPIO.PWM(r_motor,100) L_Motor.start(0) R_Motor.start(0) def Direction_Init(): GPIO.setup(left_back,GPIO.OUT) GPIO.setup(left_front,GPIO.OUT) GPIO.setup(l_motor,GPIO.OUT) GPIO.setup(right_front,GPIO.OUT) GPIO.setup(right_back,GPIO.OUT) GPIO.setup(r_motor,GPIO.OUT) def Servo_Init(): global pwm_servo pwm_servo=Adafruit_PCA9685.PCA9685() def Trackbar_Init(): # 1 create windows cv2.namedWindow('h_binary') cv2.namedWindow('s_binary') cv2.namedWindow('v_binary') # 2 Create Trackbar cv2.createTrackbar('hmin', 'h_binary', 6, 179, nothing) cv2.createTrackbar('hmax', 'h_binary', 26, 179, nothing) cv2.createTrackbar('smin', 's_binary', 110, 255, nothing) cv2.createTrackbar('smax', 's_binary', 255, 255, nothing) cv2.createTrackbar('vmin', 'v_binary', 140, 255, nothing) cv2.createTrackbar('vmax', 'v_binary', 255, 255, nothing) # 创建滑动条 滑动条值名称 窗口名称 滑动条值 滑动条阈值 回调函数 def Init(): GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) Direction_Init() Servo_Init() Motor_Init() Trackbar_Init() # 回调函数 def nothing(*arg): pass
二、运动函数
常规操作:向前、向后、向左、向右、停止。
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
48def Front(speed): L_Motor.ChangeDutyCycle(speed) GPIO.output(left_front,1) #left_front GPIO.output(left_back,0) #left_back R_Motor.ChangeDutyCycle(speed) GPIO.output(right_front,1) #right_front GPIO.output(right_back,0) #right_back def Back(speed): L_Motor.ChangeDutyCycle(speed) GPIO.output(left_front,0) #left_front GPIO.output(left_back,1) #left_back R_Motor.ChangeDutyCycle(speed) GPIO.output(right_front,0) #right_front GPIO.output(right_back,1) #right_back def Left(speed): L_Motor.ChangeDutyCycle(speed) GPIO.output(left_front,0) #left_front GPIO.output(left_back,1) #left_back R_Motor.ChangeDutyCycle(speed) GPIO.output(right_front,1) #right_front GPIO.output(right_back,0) #right_back def Right(speed): L_Motor.ChangeDutyCycle(speed) GPIO.output(left_front,1) #left_front GPIO.output(left_back,0) #left_back R_Motor.ChangeDutyCycle(speed) GPIO.output(right_front,0) #right_front GPIO.output(right_back,1) #right_back def Stop(): L_Motor.ChangeDutyCycle(0) GPIO.output(left_front,0) #left_front GPIO.output(left_back,0) #left_back R_Motor.ChangeDutyCycle(0) GPIO.output(right_front,0) #right_front GPIO.output(right_back,0) #right_back
三、舵机控制
1
2
3
4def set_servo_angle(channel,angle): angle=4096*((angle*11)+500)/20000 pwm_servo.set_pwm_freq(50) #frequency==50Hz (servo) pwm_servo.set_pwm(channel,0,int(angle))
1
2
3
4set_servo_angle(4, 110) #top servo lengthwise #0:back 180:front set_servo_angle(5, 90) #bottom servo crosswise #0:left 180:right
四、在HSV空间下获取二值图
1、获取滑动条的值
1
2
3
4
5
6
7# 1 get trackbar's value hmin = cv2.getTrackbarPos('hmin', 'h_binary') hmax = cv2.getTrackbarPos('hmax', 'h_binary') smin = cv2.getTrackbarPos('smin', 's_binary') smax = cv2.getTrackbarPos('smax', 's_binary') vmin = cv2.getTrackbarPos('vmin', 'v_binary') vmax = cv2.getTrackbarPos('vmax', 'v_binary')
2、转HSV(三通道:H、S、V)
1
2
3
4# 2 to HSV hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) cv2.imshow('hsv', hsv) h, s, v = cv2.split(hsv)
3、转二值图(单通道阈值处理)
分别对H、S、V三个道阈值处理:
1
2
3
4
5
6
7
8
9
10# 3 set threshold (binary image) # if value in (min, max):white; otherwise:black h_binary = cv2.inRange(np.array(h), np.array(hmin), np.array(hmax)) s_binary = cv2.inRange(np.array(s), np.array(smin), np.array(smax)) v_binary = cv2.inRange(np.array(v), np.array(vmin), np.array(vmax)) # 5 Show cv2.imshow('h_binary', h_binary) cv2.imshow('s_binary', s_binary) cv2.imshow('v_binary', v_binary)
4、结合HSV三个通道,得到最终二值图
对H、S、V三个通道与操作。(H&&S&&V)
1
2# 4 get binary binary = cv2.bitwise_and(h_binary, cv2.bitwise_and(s_binary, v_binary))
代码
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# 在HSV色彩空间下得到二值图 def Get_HSV(image): # 1 get trackbar's value hmin = cv2.getTrackbarPos('hmin', 'h_binary') hmax = cv2.getTrackbarPos('hmax', 'h_binary') smin = cv2.getTrackbarPos('smin', 's_binary') smax = cv2.getTrackbarPos('smax', 's_binary') vmin = cv2.getTrackbarPos('vmin', 'v_binary') vmax = cv2.getTrackbarPos('vmax', 'v_binary') # 2 to HSV hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) cv2.imshow('hsv', hsv) h, s, v = cv2.split(hsv) # 3 set threshold (binary image) # if value in (min, max):white; otherwise:black h_binary = cv2.inRange(np.array(h), np.array(hmin), np.array(hmax)) s_binary = cv2.inRange(np.array(s), np.array(smin), np.array(smax)) v_binary = cv2.inRange(np.array(v), np.array(vmin), np.array(vmax)) # 4 get binary(对H、S、V三个通道分别与操作) binary = cv2.bitwise_and(h_binary, cv2.bitwise_and(s_binary, v_binary)) # 5 Show cv2.imshow('h_binary', h_binary) cv2.imshow('s_binary', s_binary) cv2.imshow('v_binary', v_binary) cv2.imshow('binary', binary) return binary
五、图像处理(总)
1、打开摄像头
1
2
3
4# 1 Capture the frames ret, frame = camera.read() image = frame cv2.imshow('frame', frame)
2、获取HSV色彩空间得到的二值图
(Get_HSV(frame)其实就是步骤四的HSV处理)
1
2# 2 get HSV binary = Get_HSV(frame)
3、高斯滤波
1
2# 3 Gausi blur blur = cv2.GaussianBlur(binary,(9,9),0)
4、开运算去噪
1
2
3
4# 4 Open kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9)) Open = cv2.morphologyEx(blur, cv2.MORPH_OPEN, kernel) cv2.imshow('Open',Open)
5、闭运算
1
2
3# 5 Close Close = cv2.morphologyEx(Open, cv2.MORPH_CLOSE, kernel) cv2.imshow('Close',Close)
6、霍夫圆检测
原理
霍夫变换圆检测是基于图像梯度实现:
圆心检测的原理︰圆心是圆周法线的交汇处,设置一个阈值,在某点的相交的直线的条数大于这个阈值就认为该交汇点为圆心。
圆半径确定原理:圆心到圆周上的距离〔半径)是相同的,设置一个阈值,只要相同距离的数量大于该阈值,就认为该距离是该圆心的半径。
API
复制代码1
2
3
4
5
6
7
8
9def HoughCircles(image: Any, method: Any, dp: Any, minDist: Any, circles: Any = None, param1: Any = None, param2: Any = None, minRadius: Any = None, maxRadius: Any = None) -> None
参数:
- 第二个参数,int类型的method,即使用的检测方法,目前OpenCV中就霍夫梯度法一种可以使用,它的标识符为CV_HOUGH_GRADIENT,在此参数处填这个标识符即可。
- 第三个参数,double类型的dp,用来检测圆心的累加器图像的分辨率于输入图像之比的倒数,且此参数允许创建一个比输入图像分辨率低的累加器。上述文字不好理解的话,来看例子吧。例如,如果dp= 1时,累加器和输入图像具有相同的分辨率。如果dp=2,累加器便有输入图像一半那么大的宽度和高度。
- 第四个参数,double类型的minDist,为霍夫变换检测到的圆的圆心之间的最小距离,即让我们的算法能明显区分的两个不同圆之间的最小距离。这个参数如果太小的话,多个相邻的圆可能被错误地检测成了一个重合的圆。反之,这个参数设置太大的话,某些圆就不能被检测出来了。
- 第五个参数,InputArray类型的circles,经过调用HoughCircles函数后此参数存储了检测到的圆的输出矢量,每个矢量由包含了3个元素的浮点矢量(x, y, radius)表示。
- 第六个参数,double类型的param1,有默认值100。它是第三个参数method设置的检测方法的对应的参数。对当前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示传递给canny边缘检测算子的高阈值,而低阈值为高阈值的一半。
- 第七个参数,double类型的param2,也有默认值100。它是第三个参数method设置的检测方法的对应的参数。对当前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示在检测阶段圆心的累加器阈值。它越小的话,就可以检测到更多根本不存在的圆,而它越大的话,能通过检测的圆就更加接近完美的圆形了。
- 第八个参数,int类型的minRadius,有默认值0,表示圆半径的最小值。
- 第九个参数,int类型的maxRadius,也有默认值0,表示圆半径的最大值。
6-1、霍夫圆检测
1
2
3# 6 Hough Circle detect circles = cv2.HoughCircles(Close,cv2.HOUGH_GRADIENT,2,120,param1=120,param2=20,minRadius=20,maxRadius=0) # param2:决定圆能否被检测到(越少越容易检测到圆,但相应的也更容易出错)
6-2、获取圆心和半径坐标
1
2
3# 1 获取圆的圆心和半径 x, y, r = int(circles[0][0][0]),int(circles[0][0][1]),int(circles[0][0][2]) print(x, y, r)
6-3、画圆
1
2
3# 2 画圆 cv2.circle(image, (x, y), r, (255,0,255),5) cv2.imshow('image', image)
代码
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# 图像处理 def Image_Processing(): global h, s, v # 1 Capture the frames ret, frame = camera.read() image = frame cv2.imshow('frame', frame) # 2 get HSV binary = Get_HSV(frame) # 3 Gausi blur blur = cv2.GaussianBlur(binary,(9,9),0) # 4 Open kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9)) Open = cv2.morphologyEx(blur, cv2.MORPH_OPEN, kernel) cv2.imshow('Open',Open) # 5 Close Close = cv2.morphologyEx(Open, cv2.MORPH_CLOSE, kernel) cv2.imshow('Close',Close) # 6 Hough Circle detect circles = cv2.HoughCircles(Close,cv2.HOUGH_GRADIENT,2,120,param1=120,param2=20,minRadius=20,maxRadius=0) # param2:决定圆能否被检测到(越少越容易检测到圆,但相应的也更容易出错) # judge if circles is exist if circles is not None: # 1 获取圆的圆心和半径 x, y, r = int(circles[0][0][0]),int(circles[0][0][1]),int(circles[0][0][2]) print(x, y, r) # 2 画圆 cv2.circle(image, (x, y), r, (255,0,255),5) cv2.imshow('image', image) else: (x,y),r = (0,0), 0 return (x,y), r
六、运动控制
根据检测到的圆,获取到的坐标、半径,进行运动控制。
这里可以做到跟踪小球,前进和后退相配合,“敌进我退,敌退我进”。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22# 运动控制(这里可以做到跟踪小球,前景和后退相配合,“敌进我退,敌退我进”) def Move((x,y), r): low_xlimit = width/4 high_xlimit = 0.75 * width #low_ylimit = 3/4 * height ylimit = 0.75 * height print(high_xlimit, ylimit) # 没检测到,停止不动 if x==0: Stop() # 检测到在图片0.75以上的区域(距离正常) elif x>low_xlimit and x<high_xlimit and y<ylimit: Front(60) # 检测到在图片0.75以下的区域(距离过近,后退) elif x>low_xlimit and x<high_xlimit and y>=ylimit: Back(60) # 在左0.25区域,向左跟踪 elif x<low_xlimit: Left(60) # 在右0.25区域,向右跟踪 elif x>high_xlimit: Right(60)
总代码
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#Ball Tracking(HSV) import RPi.GPIO as GPIO import time import Adafruit_PCA9685 import numpy as np import cv2 #set capture window width, height = 320, 240 camera = cv2.VideoCapture(0) camera.set(3,width) camera.set(4,height) l_motor = 18 left_front = 22 left_back = 27 r_motor = 23 right_front = 25 right_back = 24 def Motor_Init(): global L_Motor, R_Motor L_Motor= GPIO.PWM(l_motor,100) R_Motor = GPIO.PWM(r_motor,100) L_Motor.start(0) R_Motor.start(0) def Direction_Init(): GPIO.setup(left_back,GPIO.OUT) GPIO.setup(left_front,GPIO.OUT) GPIO.setup(l_motor,GPIO.OUT) GPIO.setup(right_front,GPIO.OUT) GPIO.setup(right_back,GPIO.OUT) GPIO.setup(r_motor,GPIO.OUT) def Servo_Init(): global pwm_servo pwm_servo=Adafruit_PCA9685.PCA9685() def Trackbar_Init(): # 1 create windows cv2.namedWindow('h_binary') cv2.namedWindow('s_binary') cv2.namedWindow('v_binary') # 2 Create Trackbar cv2.createTrackbar('hmin', 'h_binary', 6, 179, nothing) cv2.createTrackbar('hmax', 'h_binary', 26, 179, nothing) cv2.createTrackbar('smin', 's_binary', 110, 255, nothing) cv2.createTrackbar('smax', 's_binary', 255, 255, nothing) cv2.createTrackbar('vmin', 'v_binary', 140, 255, nothing) cv2.createTrackbar('vmax', 'v_binary', 255, 255, nothing) # 创建滑动条 滑动条值名称 窗口名称 滑动条值 滑动条阈值 回调函数 def Init(): GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) Direction_Init() Servo_Init() Motor_Init() Trackbar_Init() def Front(speed): L_Motor.ChangeDutyCycle(speed) GPIO.output(left_front,1) #left_front GPIO.output(left_back,0) #left_back R_Motor.ChangeDutyCycle(speed) GPIO.output(right_front,1) #right_front GPIO.output(right_back,0) #right_back def Back(speed): L_Motor.ChangeDutyCycle(speed) GPIO.output(left_front,0) #left_front GPIO.output(left_back,1) #left_back R_Motor.ChangeDutyCycle(speed) GPIO.output(right_front,0) #right_front GPIO.output(right_back,1) #right_back def Left(speed): L_Motor.ChangeDutyCycle(speed) GPIO.output(left_front,0) #left_front GPIO.output(left_back,1) #left_back R_Motor.ChangeDutyCycle(speed) GPIO.output(right_front,1) #right_front GPIO.output(right_back,0) #right_back def Right(speed): L_Motor.ChangeDutyCycle(speed) GPIO.output(left_front,1) #left_front GPIO.output(left_back,0) #left_back R_Motor.ChangeDutyCycle(speed) GPIO.output(right_front,0) #right_front GPIO.output(right_back,1) #right_back def Stop(): L_Motor.ChangeDutyCycle(0) GPIO.output(left_front,0) #left_front GPIO.output(left_back,0) #left_back R_Motor.ChangeDutyCycle(0) GPIO.output(right_front,0) #right_front GPIO.output(right_back,0) #right_back def set_servo_angle(channel,angle): angle=4096*((angle*11)+500)/20000 pwm_servo.set_pwm_freq(50) #frequency==50Hz (servo) pwm_servo.set_pwm(channel,0,int(angle)) # 回调函数 def nothing(*arg): pass # 在HSV色彩空间下得到二值图 def Get_HSV(image): # 1 get trackbar's value hmin = cv2.getTrackbarPos('hmin', 'h_binary') hmax = cv2.getTrackbarPos('hmax', 'h_binary') smin = cv2.getTrackbarPos('smin', 's_binary') smax = cv2.getTrackbarPos('smax', 's_binary') vmin = cv2.getTrackbarPos('vmin', 'v_binary') vmax = cv2.getTrackbarPos('vmax', 'v_binary') # 2 to HSV hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) cv2.imshow('hsv', hsv) h, s, v = cv2.split(hsv) # 3 set threshold (binary image) # if value in (min, max):white; otherwise:black h_binary = cv2.inRange(np.array(h), np.array(hmin), np.array(hmax)) s_binary = cv2.inRange(np.array(s), np.array(smin), np.array(smax)) v_binary = cv2.inRange(np.array(v), np.array(vmin), np.array(vmax)) # 4 get binary(对H、S、V三个通道分别与操作) binary = cv2.bitwise_and(h_binary, cv2.bitwise_and(s_binary, v_binary)) # 5 Show cv2.imshow('h_binary', h_binary) cv2.imshow('s_binary', s_binary) cv2.imshow('v_binary', v_binary) cv2.imshow('binary', binary) return binary # 图像处理 def Image_Processing(): global h, s, v # 1 Capture the frames ret, frame = camera.read() image = frame cv2.imshow('frame', frame) # 2 get HSV binary = Get_HSV(frame) # 3 Gausi blur blur = cv2.GaussianBlur(binary,(9,9),0) # 4 Open kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9)) Open = cv2.morphologyEx(blur, cv2.MORPH_OPEN, kernel) cv2.imshow('Open',Open) # 5 Close Close = cv2.morphologyEx(Open, cv2.MORPH_CLOSE, kernel) cv2.imshow('Close',Close) # 6 Hough Circle detect circles = cv2.HoughCircles(Close,cv2.HOUGH_GRADIENT,2,120,param1=120,param2=20,minRadius=20,maxRadius=0) # param2:决定圆能否被检测到(越少越容易检测到圆,但相应的也更容易出错) # judge if circles is exist if circles is not None: # 1 获取圆的圆心和半径 x, y, r = int(circles[0][0][0]),int(circles[0][0][1]),int(circles[0][0][2]) print(x, y, r) # 2 画圆 cv2.circle(image, (x, y), r, (255,0,255),5) cv2.imshow('image', image) else: (x,y),r = (0,0), 0 return (x,y), r # 运动控制(这里可以做到跟踪小球,前景和后退相配合,“敌进我退,敌退我进”) def Move((x,y), r): low_xlimit = width/4 high_xlimit = 0.75 * width #low_ylimit = 3/4 * height ylimit = 0.75 * height print(high_xlimit, ylimit) # 没检测到,停止不动 if x==0: Stop() # 检测到在图片0.75以上的区域(距离正常) elif x>low_xlimit and x<high_xlimit and y<ylimit: Front(60) # 检测到在图片0.75以下的区域(距离过近,后退) elif x>low_xlimit and x<high_xlimit and y>=ylimit: Back(60) # 在左0.25区域,向左跟踪 elif x<low_xlimit: Left(60) # 在右0.25区域,向右跟踪 elif x>high_xlimit: Right(60) if __name__ == '__main__': Init() set_servo_angle(4, 110) #top servo lengthwise #0:back 180:front set_servo_angle(5, 90) #bottom servo crosswise #0:left 180:right while 1: # 1 Image Process (x,y), r = Image_Processing() # 2 Move Move((x,y), r) # must include this codes(otherwise you can't open camera successfully) if cv2.waitKey(1) & 0xFF == ord('q'): Stop() GPIO.cleanup() break
这里的HSV是根据我自己当前的情况调节的,更改场景以后可能需要重新调节H、S、V三通道的阈值(max && min)
基础的视觉检测+运动,没有太多的运动控制算法(PID等等都没有涉及到)。有好的想法和建议欢迎交流讨论,Thanks♪(・ω・)ノ
最后
以上就是愉快火最近收集整理的关于树莓派视觉小车 -- 小球追踪(颜色追踪)(OpenCV色彩空间HSV)效果展示 基础理论(HSV)一、初始化二、运动函数三、舵机控制四、在HSV空间下获取二值图五、图像处理(总)六、运动控制总代码的全部内容,更多相关树莓派视觉小车内容请搜索靠谱客的其他文章。
发表评论 取消回复