环境:windows10、pycharm2017、、python3.64、opencv3
***先上个效果图吧,图中是加了一些其他算法的,不是单独的识别,还有一些卡尔曼滤波,svm等。我们先出基本的识别思路开始。
def read_morphology(cap): # read cap and morphological operation to get led binary image.
ret, frame = cap.read()
# frame = cv.flip(frame, 1)
# frame = cv.flip(frame, 1)
open = cv.getTrackbarPos('open', 'mor_adjust')
close = cv.getTrackbarPos('close', 'mor_adjust')
erode = cv.getTrackbarPos('erode', 'mor_adjust')
dilate = cv.getTrackbarPos('dilate', 'mor_adjust')
frame = cv.resize(frame, (WIDTH, HIGH), interpolation=cv.INTER_CUBIC)
mask = hsv_change(frame)
# dst_open = open_binary(mask, open, open)
dst_close = close_binary(mask, close, close)
dst_erode = erode_binary(dst_close, erode, erode)
dst_dilate = dilate_binary(dst_erode, dilate, dilate)
cv.circle(frame, (int(WIDTH / 2), int(HIGH / 2)), 2, (255, 0, 255), -1)
cv.imshow("erode", mask)
return dst_dilate, frame
hsv色彩空间转换,为了调参数方便我设置了滑块,方便调参调整hsv的阈值来获得一个较好的阈值效果,但是这种根据阈值来调整的会受光线影响比较严重 ,rm的场地比较黑暗,但是能也会有些影响,可以加一些滤光片或者增加摄像头的曝光等等来进行调整。
def nothing(x):
pass
def creatTrackbar(): # creat trackbar to adjust the color threshold.
# blue
# cv.createTrackbar("hmin", "color_adjust", 0, 255, nothing)
# cv.createTrackbar("hmax", "color_adjust", 250, 255, nothing)
# cv.createTrackbar("smin", "color_adjust", 0, 255, nothing)
# cv.createTrackbar("smax", "color_adjust", 143, 255, nothing)
# cv.createTrackbar("vmin", "color_adjust", 255, 255, nothing)
# cv.createTrackbar("vmax", "color_adjust", 255, 255, nothing)
# red
cv.createTrackbar("hmin", "color_adjust", 0, 255, nothing)
cv.createTrackbar("hmax", "color_adjust", 255, 255, nothing)
cv.createTrackbar("smin", "color_adjust", 3, 255, nothing)
cv.createTrackbar("smax", "color_adjust", 255, 255, nothing)
cv.createTrackbar("vmin", "color_adjust", 245, 255, nothing)
cv.createTrackbar("vmax", "color_adjust", 255, 255, nothing)
cv.createTrackbar("open", "mor_adjust", 1, 30, nothing)
cv.createTrackbar("close", "mor_adjust", 5, 30, nothing)
cv.createTrackbar("erode", "mor_adjust", 2, 30, nothing)
cv.createTrackbar("dilate", "mor_adjust", 5, 30, nothing)
def hsv_change(frame): # hsv channel separation.
hmin = cv.getTrackbarPos('hmin', 'color_adjust')
hmax = cv.getTrackbarPos('hmax', 'color_adjust')
smin = cv.getTrackbarPos('smin', 'color_adjust')
smax = cv.getTrackbarPos('smax', 'color_adjust')
vmin = cv.getTrackbarPos('vmin', 'color_adjust')
vmax = cv.getTrackbarPos('vmax', 'color_adjust')
# gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
# cv.imshow("gray", gray)
hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
lower_hsv = np.array([hmin, smin, vmin])
upper_hsv = np.array([hmax, smax, vmax])
mask = cv.inRange(hsv, lowerb=lower_hsv, upperb=upper_hsv)
return mask
形态学操作,模块化可直接调用使用
def open_binary(binary, x, y):
kernel = cv.getStructuringElement(cv.MORPH_RECT, (x, y))
dst = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel)
return dst
def close_binary(binary, x, y):
kernel = cv.getStructuringElement(cv.MORPH_RECT, (x, y))
dst = cv.morphologyEx(binary, cv.MORPH_CLOSE, kernel)
return dst
def erode_binary(binary, x, y):
kernel = cv.getStructuringElement(cv.MORPH_RECT, (x, y))
dst = cv.erode(binary, kernel)
return dst
def dilate_binary(binary, x, y):
kernel = cv.getStructuringElement(cv.MORPH_RECT, (x, y))
dst = cv.dilate(binary, kernel)
return dst
def find_contours(binary, frame): # find contours and main screening section
_, contours, heriachy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
length = len(contours)
data_list = []
first_data = []
second_data1 = []
second_data2 = []
c = 0
d = 0
if length > 0:
# print("---founding---")
for i, contour in enumerate(contours):
data_dict = dict()
# print("countour", contour)
area = cv.contourArea(contour)
rect = cv.minAreaRect(contour)
rx, ry = rect[0]
rw = rect[1][0]
rh = rect[1][1]
z = rect[2]
coor = cv.boxPoints(rect)
x1 = coor[0][0]
y1 = coor[0][1]
x2 = coor[1][0]
y2 = coor[1][1]
x3 = coor[2][0]
y3 = coor[2][1]
x4 = coor[3][0]
y4 = coor[3][1]
# if i >= 1:
data_dict["area"] = area
data_dict["rx"] = rx
data_dict["ry"] = ry
data_dict["rh"] = rh
data_dict["rw"] = rw
data_dict["z"] = z
data_dict["x1"] = x1
data_dict["y1"] = y1
data_dict["x2"] = x2
data_dict["y2"] = y2
data_dict["x3"] = x3
data_dict["y3"] = y3
data_dict["x4"] = x4
data_dict["y4"] = y4
data_list.append(data_dict)
for i in range(len(data_list)):
data_rh = data_list[i].get("rh", 0)
data_rw = data_list[i].get("rw", 0)
data_area = data_list[i].get("area", 0)
if (float(data_rh / data_rw) >= 0.2) \
and (float(data_rh / data_rw) <= 4) \
and data_area >= 20:
first_data.append(data_list[i])
else:
pass
for i in range(len(first_data)):
c = i + 1
while c < len(first_data):
data_ryi = float(first_data[i].get("ry", 0))
data_ryc = float(first_data[c].get("ry", 0))
data_rhi = float(first_data[i].get("rh", 0))
data_rhc = float(first_data[c].get("rh", 0))
data_rxi = float(first_data[i].get("rx", 0))
data_rxc = float(first_data[c].get("rx", 0))
if (abs(data_ryi - data_ryc) <= 3 * ((data_rhi + data_rhc) / 2)) \
and (abs(data_rhi - data_rhc) <= 0.2 * max(data_rhi, data_rhc)) \
and (abs(data_rxi - data_rxc) <= (6 / 2) * ((data_rhi + data_rhc) / 2)):
second_data1.append(first_data[i])
second_data2.append(first_data[c])
c = c + 1
# for i in range(len(second_data1)):
# data_z1 = second_data1[i].get("z", 0)
# data_z2 = second_data2[i].get("z", 0)
# if abs(data_z1 - data_z2) <= 6:
# third_data1.append(second_data1[i])
# third_data2.append(second_data2[i])
if len(second_data1):
global dataList_c
dataList_c.clear()
for i in range(len(second_data1)):
rectangle_x1 = int(second_data1[i]["x1"])
rectangle_y1 = int(second_data1[i]["y1"])
rectangle_x2 = int(second_data2[i]["x3"])
rectangle_y2 = int(second_data2[i]["y3"])
if abs(rectangle_y1 - rectangle_y2) <= (6 / 2) * (abs(rectangle_x1 - rectangle_x2)):
global point1_1x, point1_1y, point1_2x, point1_2y, point1_3x, point1_3y, point1_4x, point1_4y
global point2_1x, point2_1y, point2_2x, point2_2y, point2_3x, point2_3y, point2_4x, point2_4y
point1_1x = second_data1[i]["x1"]
point1_1y = second_data1[i]["y1"]
point1_2x = second_data1[i]["x2"]
point1_2y = second_data1[i]["y2"]
point1_3x = second_data1[i]["x3"]
point1_3y = second_data1[i]["y3"]
point1_4x = second_data1[i]["x4"]
point1_4y = second_data1[i]["y4"]
point2_1x = second_data2[i]["x1"]
point2_1y = second_data1[i]["y1"]
point2_2x = second_data1[i]["x2"]
point2_2y = second_data1[i]["y2"]
point2_3x = second_data1[i]["x3"]
point2_3y = second_data1[i]["y3"]
point2_4x = second_data1[i]["x4"]
point2_4y = second_data1[i]["y4"]
if point1_1x > point2_1x:
pass
cv.rectangle(frame, (point2_2x, point2_2y), (point1_4x, point1_4y), (255, 255, 0), 2)
else:
point1_1x, point2_1x = point2_1x, point1_1x
point1_2x, point2_2x = point2_2x, point1_2x
point1_3x, point2_3x = point2_3x, point1_3x
point1_4x, point2_4x = point2_4x, point1_4x
point1_1y, point2_1y = point2_1y, point1_1y
point1_2y, point2_2y = point2_2y, point1_2y
point1_3y, point2_3y = point2_3y, point1_3y
point1_4y, point2_4y = point2_4y, point1_4y
cv.rectangle(frame, (point2_1x, point2_1y), (point1_3x, point1_3y), (255, 255, 0), 2)
cv.putText(frame, "target1:", (rectangle_x2, rectangle_y2 - 5), cv.FONT_HERSHEY_SIMPLEX,
0.5, [255, 255, 255])
center = (int((point2_2x + point1_4x) / 2), int((point2_2y + point1_4y) / 2))
cv.circle(frame, center, 2, (0, 0, 255), -1) # 画出重心
dataList_c.append(center)
high = (rectangle_y1, rectangle_y2)
dataRange.append(high)
else:
print("---not find---")
dataList_c.clear()
data_list.clear()
1,图片数据读取:在While语句中从摄像头中读入数据,以帧一帧的形式加以进入后续处理。
2,预处理:对读入进来的图片预处理,包括,转化到HSV色彩空间、根据不同阈值不断调整提取出鲜明的红色/蓝色、对提取出来的包含各种噪声的二值图进行腐蚀膨胀处理,得到完整的可能含有多个的明显的灯条信息并且噪声较小或没有噪声后。即算预处理结束。
3,筛选灯条:对预处理完的灯条进行轮廓查找进入find_contours()函数,遍历cv2.findContours()opencvAPI查找出的轮廓,根据灯条高宽比、面积大小、两列灯条之间的宽度差、高度差把是灯条对的轮廓筛选出来,其中以待筛选的一对灯条的高度平均值或max(待筛选的一对灯条)作为比对标准进行筛选。画出所有灯条对,并确定中心及击打点。
4,测距及数据处理:根据PNP算法、cv2.solvePnP()API等单目测距出目标点距离摄像头的距离,并根据姿势计算获得欧拉角作为电控云台转动的数据。
5,主要框架流程:将各个函数步骤逐步封装,并在主函数的While读图语句中分步调用,并作为主线程,将筛选灯条svm算法、测距及数据处理和串口发送,作为两个分线程,各自运行互不影响提高识别速度。(也可以开多个线程,根据自己算法而定)