这几天接触了小车移动物块的项目,其中的视觉算法基于opencv,方法虽然简单效果却很nice,今天对团队的算法做个记录,
方法原理:帧差检测,将带有检测目标的深度图与无目标的背景图做差,得到感兴趣目标的位置。具体步骤如下,
1、图片读取
import cv2
import numpy as np
ref_path = 'C:\Users/15989\Desktop\imgs/1.png'
cur_path = 'C:\Users/15989\Desktop\imgs/201.png'
cur_img = cv2.imread(cur_path, -1)
ref_img = cv2.imread(ref_path, -1)
由于图片是16位的深度图,为了方便查看就对图片进行了归一化,操作如下:
def norm(img):
img = (img - img.min()) / (img.max() - img.min())
img *= 255
return img
读取图片如下 (背景图/目标图):
diff_frame = cv2.absdiff(cur_img, ref_img)
3、选取感兴趣区域
diff_frame_roi = diff_frame[200:, 200:540]
4、将图片转成二值图
frame_bin = cv2.inRange(diff_frame_roi, 20, 100)
5、闭运算 (先膨胀,后腐蚀),消除小型的黑洞
kernel = np.ones((3, 3), dtype=np.uint8)
closing = cv2.morphologyEx(frame_bin, cv2.MORPH_CLOSE, kernel)
6、寻找目标轮廓
contours, _ = cv2.findContours(closing, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
7、找到包含轮廓的最小外接圆并求出对应半径,对轮廓半径进行过滤,计算符合要求的轮廓的最小外接矩形,对外接矩形的宽高及它们的比例进行过滤,选取合适大小的目标 (调参主要集中在这一环节)
x_obj, y_obj = 0, 0
w, h = 0, 0
xl, yl = [], []
wl, hl = [], []
for cont in contours:
(x, y), radius = cv2.minEnclosingCircle(cont)
if radius > 13 and radius < 28:
rect = cv2.minAreaRect(cont)
x_obj, y_obj = rect[0]
w, h = rect[1]
if w/h > 1.5 or w/h < 0.5 or w*h < 500:
continue
else:
xl.append(x_obj)
yl.append(y_obj)
wl.append(w)
hl.append(h)
8、 得到目标最终位置,由于第3步中对图片进行了裁剪,因此需要将上一步得到的坐标进行转换,转换成原图坐标并在图片中框出目标所在位置
x_final = [xi + 200 for xi in xl]
y_final = [yi + 200 for yi in yl]
for x_f, y_f, w_f, h_f in zip(x_final, y_final, wl, hl):
cv2.rectangle(cur_img, (int(x_f - w_f / 2), int(y_f - h_f / 2)), (int(x_f + w_f / 2), int(y_f + h_f / 2)), (0, 0, 0), thickness=2)