基于HSV色域分割+Canny的特征圆检测算法实现(单张图片检测+realsense相机实时检测)
文章目录
- 前言
- 一、效果展示
- 二、算法流程
- 三、环境配置
- 四、部分代码解释
- 4.1 前置滑块
- 4.2 图形预处理
- 4.3 椭圆检测
- 五、完整代码
- 5.1 对于一张图片的检测
- 5.2 使用Realsense相机进行实时检测
前言
本科毕设设计的一种传统视觉方案完成特征圆检测方法,仅基于OpenCV实现,可以完成一张图片的检测,也可以搭配相机进行实时的检测,已在Windows 10及Ubuntu 16.04下运行通过。
一、效果展示
单张图片的检测

使用realsense的实时检测,可以获取圆心的三维坐标。


二、算法流程
- 将RGB图片转换到HSV色域,去除背景干扰。
- 图像滤波处理。
- Canny算法边缘检测。
- 对检测到的轮廓边缘进行椭圆拟合,使用圆度值以及长短轴的值进行目标圆的筛选。
三、环境配置
基本只依赖numpy和cv2。
import numpy as np
import cv2
四、部分代码解释
4.1 前置滑块
设计滑块便于后面实时调试HSV、半径等参数。
def nothing(*arg):pass
para = (0, 127, 149, 255, 255, 255, 0, 50)
# lowHue lowSat lowVal highHue highSat highVal minRadius maxRadius
cv2.namedWindow('Trackbar')
cv2.resizeWindow('Trackbar', 400, 400)
cv2.createTrackbar('lowHue', 'Trackbar', para[0], 255, nothing)
cv2.createTrackbar('lowSat', 'Trackbar', para[1], 255, nothing)
cv2.createTrackbar('lowVal', 'Trackbar', para[2], 255, nothing)
cv2.createTrackbar('highHue', 'Trackbar', para[3], 255, nothing)
cv2.createTrackbar('highSat', 'Trackbar', para[4], 255, nothing)
cv2.createTrackbar('highVal', 'Trackbar', para[5], 255, nothing)
cv2.createTrackbar('minRadius', 'Trackbar', para[6], 500, nothing)
cv2.createTrackbar('maxRadius', 'Trackbar', para[7], 500, nothing)
4.2 图形预处理
frame = cv2.imread("./c1.jpg")lowHue = cv2.getTrackbarPos('lowHue', 'Trackbar')lowSat = cv2.getTrackbarPos('lowSat', 'Trackbar')lowVal = cv2.getTrackbarPos('lowVal', 'Trackbar')highHue = cv2.getTrackbarPos('highHue', 'Trackbar')highSat = cv2.getTrackbarPos('highSat', 'Trackbar')highVal = cv2.getTrackbarPos('highVal', 'Trackbar')minRadius = cv2.getTrackbarPos('minRadius', 'Trackbar')maxRadius = cv2.getTrackbarPos('maxRadius', 'Trackbar')print("para is ",[lowHue, lowSat, lowVal, highHue, highSat, highVal, minRadius, maxRadius])# Show the original image.cv2.namedWindow('frame', 0)cv2.imshow('frame', frame)# Blur methods available, comment or uncomment to try different blur methods.frame = cv2.medianBlur(frame, 5)# Convert the frame to HSV colour model.hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)# HSV values to define a colour range.colorLow = np.array([lowHue, lowSat, lowVal])colorHigh = np.array([highHue, highSat, highVal])mask = cv2.inRange(hsv, colorLow, colorHigh)kernal = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernal)mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernal)result = cv2.bitwise_and(frame, frame, mask=mask)# Show final output imagecv2.namedWindow('afterHSVmask', 0)cv2.imshow('afterHSVmask', result)gray = cv2.cvtColor(result, cv2.COLOR_BGR2GRAY)imgray = cv2.Canny(result, 600, 100, 3) # Cannycv2.namedWindow('canny', 0)cv2.imshow('canny', imgray)ret, thresh = cv2.threshold(imgray, 127, 255, cv2.THRESH_BINARY)
4.3 椭圆检测
原理是使用findContours函数寻找所有的轮廓,在所有的轮廓中拟合椭圆,根据圆度和长短轴的限制进行筛选。
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # contours为轮廓集,可以计算轮廓的长度、面积等for cnt in contours:if len(cnt) > 50:ell = cv2.fitEllipse(cnt) # 拟合椭圆 ell = [ center(x, y) , long short (a, b), angle ]a = ell[1][0] # longb = ell[1][1] # shortx = int(ell[0][0])y = int(ell[0][1])if (b / a) < 1.2 and a > minRadius and b > minRadius and a < maxRadius and b < maxRadius:frame = cv2.ellipse(frame, ell, (0, 0, 200), 2)cv2.circle(frame, (x, y), 2, (255, 255, 255), 3)cv2.putText(frame, str((x, y, (a + b) // 2)), (x + 20, y + 10), 0, 1,[225, 255, 255], thickness=1, lineType=cv2.LINE_AA)
五、完整代码
完整代码已上传GitHub,附带一些图片。
https://github.com/Thinkin99/HSV_Canny_Circle_Detection
5.1 对于一张图片的检测
import numpy as np
import cv2def nothing(*arg):passpara = (0, 127, 149, 255, 255, 255, 0, 50)
# lowHue lowSat lowVal highHue highSat highVal minRadius maxRadius
cv2.namedWindow('Trackbar')
cv2.resizeWindow('Trackbar', 400, 400)
cv2.createTrackbar('lowHue', 'Trackbar', para[0], 255, nothing)
cv2.createTrackbar('lowSat', 'Trackbar', para[1], 255, nothing)
cv2.createTrackbar('lowVal', 'Trackbar', para[2], 255, nothing)
cv2.createTrackbar('highHue', 'Trackbar', para[3], 255, nothing)
cv2.createTrackbar('highSat', 'Trackbar', para[4], 255, nothing)
cv2.createTrackbar('highVal', 'Trackbar', para[5], 255, nothing)
cv2.createTrackbar('minRadius', 'Trackbar', para[6], 500, nothing)
cv2.createTrackbar('maxRadius', 'Trackbar', para[7], 500, nothing)while True:frame = cv2.imread("./c1.jpg")lowHue = cv2.getTrackbarPos('lowHue', 'Trackbar')lowSat = cv2.getTrackbarPos('lowSat', 'Trackbar')lowVal = cv2.getTrackbarPos('lowVal', 'Trackbar')highHue = cv2.getTrackbarPos('highHue', 'Trackbar')highSat = cv2.getTrackbarPos('highSat', 'Trackbar')highVal = cv2.getTrackbarPos('highVal', 'Trackbar')minRadius = cv2.getTrackbarPos('minRadius', 'Trackbar')maxRadius = cv2.getTrackbarPos('maxRadius', 'Trackbar')print("para is ",[lowHue, lowSat, lowVal, highHue, highSat, highVal, minRadius, maxRadius])# Show the original image.cv2.namedWindow('frame', 0)cv2.imshow('frame', frame)# Blur methods available, comment or uncomment to try different blur methods.frame = cv2.medianBlur(frame, 5)# Convert the frame to HSV colour model.hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)# HSV values to define a colour range.colorLow = np.array([lowHue, lowSat, lowVal])colorHigh = np.array([highHue, highSat, highVal])mask = cv2.inRange(hsv, colorLow, colorHigh)kernal = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernal)mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernal)result = cv2.bitwise_and(frame, frame, mask=mask)# Show final output imagecv2.namedWindow('afterHSVmask', 0)cv2.imshow('afterHSVmask', result)gray = cv2.cvtColor(result, cv2.COLOR_BGR2GRAY)imgray = cv2.Canny(result, 600, 100, 3) # Cannycv2.namedWindow('canny', 0)cv2.imshow('canny', imgray)ret, thresh = cv2.threshold(imgray, 127, 255, cv2.THRESH_BINARY)contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # contours为轮廓集,可以计算轮廓的长度、面积等for cnt in contours:if len(cnt) > 50:ell = cv2.fitEllipse(cnt) # 拟合椭圆 ell = [ center(x, y) , long short (a, b), angle ]a = ell[1][0] # longb = ell[1][1] # shortx = int(ell[0][0])y = int(ell[0][1])if (b / a) < 1.2 and a > minRadius and b > minRadius and a < maxRadius and b < maxRadius:frame = cv2.ellipse(frame, ell, (0, 0, 200), 2)cv2.circle(frame, (x, y), 2, (255, 255, 255), 3)cv2.putText(frame, str((x, y, (a + b) // 2)), (x + 20, y + 10), 0, 1,[225, 255, 255], thickness=1, lineType=cv2.LINE_AA)cv2.namedWindow("circle_detect", 0)cv2.imshow("circle_detect", frame)k = cv2.waitKey(5) & 0xFFif k == 27:break
cv2.destroyAllWindows()
5.2 使用Realsense相机进行实时检测
因为已经毕业了, 手上没有Realsense,云改了一下代码,没有实际跑过,可能会有bug,相较于单张图片的检测多了深度值的检测。
from __future__ import division
import numpy as np
import pyrealsense2 as rs
# sys.path.remove('/opt/ros/kinetic/lib/python2.7/dist-packages')
import cv2def nothing(*arg):passpara = (0, 127, 149, 255, 255, 255, 0, 50)
# lowHue lowSat lowVal highHue highSat highVal minRadius maxRadius
cv2.namedWindow('Trackbar')
cv2.resizeWindow('Trackbar', 500, 400)
cv2.createTrackbar('lowHue', 'Trackbar', para[0], 255, nothing)
cv2.createTrackbar('lowSat', 'Trackbar', para[1], 255, nothing)
cv2.createTrackbar('lowVal', 'Trackbar', para[2], 255, nothing)
cv2.createTrackbar('highHue', 'Trackbar', para[3], 255, nothing)
cv2.createTrackbar('highSat', 'Trackbar', para[4], 255, nothing)
cv2.createTrackbar('highVal', 'Trackbar', para[5], 255, nothing)
cv2.createTrackbar('minRadius', 'Trackbar', para[6], 500, nothing)
cv2.createTrackbar('maxRadius', 'Trackbar', para[7], 500, nothing)def get_aligned_images():frames = pipeline.wait_for_frames() # 等待获取图像帧aligned_frames = align.process(frames) # 获取对齐帧aligned_depth_frame = aligned_frames.get_depth_frame() # 获取对齐帧中的depth帧color_frame = aligned_frames.get_color_frame() # 获取对齐帧中的color帧############### 相机参数的获取 #######################intr = color_frame.profile.as_video_stream_profile().intrinsics # 获取相机内参depth_intrin = aligned_depth_frame.profile.as_video_stream_profile().intrinsics # 获取深度参数(像素坐标系转相机坐标系会用到)depth_image = np.asanyarray(aligned_depth_frame.get_data()) # 深度图(默认16位)depth_image_8bit = cv2.convertScaleAbs(depth_image, alpha=0.03) # 深度图(8位)depth_image_3d = np.dstack((depth_image_8bit, depth_image_8bit, depth_image_8bit)) # 3通道深度图color_image = np.asanyarray(color_frame.get_data()) # RGB图# 返回相机内参、深度参数、彩色图、深度图、齐帧中的depth帧return intr, depth_intrin, color_image, depth_image, aligned_depth_frame
pipeline = rs.pipeline() # 定义流程pipeline
config = rs.config() # 定义配置config
# config.enable_stream(rs.stream.depth, 1280, 720, rs.format.z16, 15)
# config.enable_stream(rs.stream.color, 1280, 720, rs.format.bgr8, 15)
config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)
config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)
profile = pipeline.start(config) # 流程开始
align_to = rs.stream.color # 与color流对齐
align = rs.align(align_to)while True:# Get HSV values from the GUI sliders.intr, depth_intrin, color_image, depth_image, aligned_depth_frame = get_aligned_images() # 获取对齐的图像与相机内参if not depth_image.any() or not color_image.any():continuelowHue = cv2.getTrackbarPos('lowHue', 'Trackbar')lowSat = cv2.getTrackbarPos('lowSat', 'Trackbar')lowVal = cv2.getTrackbarPos('lowVal', 'Trackbar')highHue = cv2.getTrackbarPos('highHue', 'Trackbar')highSat = cv2.getTrackbarPos('highSat', 'Trackbar')highVal = cv2.getTrackbarPos('highVal', 'Trackbar')minRadius = cv2.getTrackbarPos('minRadius', 'Trackbar')maxRadius = cv2.getTrackbarPos('maxRadius', 'Trackbar')print("para is ", [lowHue, lowSat, lowVal, highHue, highSat, highVal, minRadius, maxRadius])frame=color_image# Show the original image.cv2.namedWindow('frame',0)cv2.imshow('frame', frame)# Blur methods available, comment or uncomment to try different blur methods.frame = cv2.medianBlur(frame, 9)# Convert the frame to HSV colour model.hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)# HSV values to define a colour range.colorLow = np.array([lowHue,lowSat,lowVal])colorHigh = np.array([highHue,highSat,highVal])mask = cv2.inRange(hsv, colorLow, colorHigh)kernal = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7))mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernal)mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernal)result = cv2.bitwise_and(frame, frame, mask = mask)# Show final output imagecv2.namedWindow('afterHSVmask',0)cv2.imshow('afterHSVmask', result)gray = cv2.cvtColor(result, cv2.COLOR_BGR2GRAY)imgray = cv2.Canny(result, 600, 100, 3) # Cannycv2.namedWindow('canny',0)cv2.imshow('canny',imgray)ret, thresh = cv2.threshold(imgray, 127, 255, cv2.THRESH_BINARY)contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # contours为轮廓集,可以计算轮廓的长度、面积等list_xy=[]for cnt in contours:if len(cnt) > 50:ell = cv2.fitEllipse(cnt) # 拟合椭圆 ellipse = [ center(x, y) , long short (a, b), angle ]a = ell[1][0]b = ell[1][1]x = int(ell[0][0])y = int(ell[0][1])if (b / a) < 1.2 and a > minRadius and b > minRadius and a < maxRadius and b < maxRadius:frame = cv2.ellipse(frame, ell, (0, 0, 200), 2)cv2.circle(frame, (x, y), 2, (255, 255, 255), 3)cv2.putText(frame, str((x, y,(a+b)//2)), (x + 20, y + 10), 0, 1,[225, 255, 255], thickness=1, lineType=cv2.LINE_AA)dis = aligned_depth_frame.get_distance(x, y)if dis == 0:dis = aligned_depth_frame.get_distance(100, 100)#如果检测不到距离,就取(100,100)像素点的距离.camera_xyz = rs.rs2_deproject_pixel_to_point(depth_intrin, (x, y), dis) # 计算相机坐标系的xyzcamera_xyz = np.round(np.array(camera_xyz), 3) # 转成3位小数camera_xyz = camera_xyz.tolist()cv2.putText(frame, str(camera_xyz), (x - 50, y + 50), 0, 1,[225, 255, 255], thickness=1, lineType=cv2.LINE_AA) # 标出坐标cv2.namedWindow("circle_detect",0)cv2.imshow("circle_detect", frame)k = cv2.waitKey(5) & 0xFFif k == 27:breakcv2.destroyAllWindows()
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
