基于HSV色域分割+Canny的特征圆检测算法实现(单张图片检测+realsense相机实时检测)

文章目录

  • 前言
  • 一、效果展示
  • 二、算法流程
  • 三、环境配置
  • 四、部分代码解释
    • 4.1 前置滑块
    • 4.2 图形预处理
    • 4.3 椭圆检测
  • 五、完整代码
    • 5.1 对于一张图片的检测
    • 5.2 使用Realsense相机进行实时检测


前言

本科毕设设计的一种传统视觉方案完成特征圆检测方法,仅基于OpenCV实现,可以完成一张图片的检测,也可以搭配相机进行实时的检测,已在Windows 10及Ubuntu 16.04下运行通过。

一、效果展示

单张图片的检测
单张图片的检测
使用realsense的实时检测,可以获取圆心的三维坐标。
在这里插入图片描述
在这里插入图片描述

二、算法流程

  1. 将RGB图片转换到HSV色域,去除背景干扰。
  2. 图像滤波处理。
  3. Canny算法边缘检测。
  4. 对检测到的轮廓边缘进行椭圆拟合,使用圆度值以及长短轴的值进行目标圆的筛选。

三、环境配置

基本只依赖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)#如果检测不到距离,就取(100100)像素点的距离.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()


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部