1. 霍夫直线变换,是在极坐标上,对某一个点进行旋转,绘制曲线,当两条极坐标曲线相交于一点,则这两个点在一条线上,有n个点在极坐标上的曲线相交了m次,当m大于一定的阈值,则认为存在该条直线。
霍夫直线的绘制代码:
rho = 1;
theta = np.pi/180
threshold=0
lines = cv.HoughLines(img,rho, theta, threshold)
2. 绘制棋盘上的直线
# 霍夫变换
# 线段以像素为单位的距离精度,double类型的,推荐用1.0
rho = 1
# 线段以弧度为单位的角度精度,推荐用numpy.pi/180
theta = np.pi/180
# 累加平面的阈值参数,int类型,超过设定阈值才被检测出线段,值越大,
# 基本上意味着检出的线段越长,检出的线段个数越少。
threshold=10
# 线段以像素为单位的最小长度
min_line_length=25
# 同一方向上两条线段判定为一条线段的最大允许间隔(断裂),
# 超过了设定值,则把两条线段当成一条线段,值越大,允许线段上的断裂越大,越有可能检出潜在的直线段
max_line_gap = 3
#要求图像是8位单通道,需要先二值化
lines = cv.HoughLinesP(thresh_img,rho,theta,threshold,
minLineLength=min_line_length,maxLineGap=max_line_gap)
3. 霍夫圆
"""
@param 8-bit 单通道图片
@param method 检测方法, 当前只有cv2.HOUGH_GRADIENT
@param dp 累加器分辨率(步长)和图像分辨率的反比例, 例如:
如果 dp=1 累加器和输入图像分辨率相同.
如果 dp=2 累加器宽高各为输入图像宽高的一半相同.
@param minDist 检测到圆的圆心之间的最小距离。
如果参数太小,除了真实的一个之外,可能错误地检测到多个相邻的圆圈。
如果参数太大,可能会遗漏一些圆
@param param1 参数1。它是两个传递给Canny边缘检测器的较高阈值(较低的阈值是此值的一半)
@param param2 参数2, 它是检测阶段圆心的累加器阈值。
它越小,会检测到更多的假圆圈。较大累加器值对应的圆圈将首先返回。
@param minRadius 最小圆半径.
@param maxRadius 最大圆半径.
如果<=0, 会使用图片最大像素值
如果< 0, 直接返回圆心, 不计算半径
"""
# ../images/coins.jpg
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT,
dp = 1,
minDist = 50,
param1=160,
param2=50,
minRadius=0,
maxRadius=100)
# 绘制圆
for x,y,radius in circles[0]:
cv.circle(src,(x,y),radius,(200,200,0))
4. 查找和绘制轮廓
#第二项node为模式,第三项method为方法
#模式
#RETR_EXTERNAL 只检测最外层轮廓
#RETR_LIST 提取所有轮廓,并放置在list中,检测的轮廓不建立等级关系
#RETR_CCOMP 提取所有轮廓,并将轮廓组织成双层结构(two-level hierarchy),
# 顶层为连通域的外围边界,次层位内层边界
#RETR_TREE 提取所有轮廓并重新建立网状轮廓结构
#方法
#CHAIN_APPROX_NONE 获取每个轮廓的每个像素,相邻的两个点的像素位置差不超过1
#CHAIN_APPROX_SIMPLE 压缩水平方向,垂直方向,对角线方向的元素,
# 只保留该方向的重点坐标,如果一个矩形轮廓只需4个点来保存轮廓信息
#CHAIN_APPROX_TC89_L1 Teh-Chinl链逼近算法
#CHAIN_APPROX_TC89_KCOS Teh-Chinl链逼近算法
#返回值 处理的图像,轮廓列表,继承关系
_,contours,hierarchy = cv.findContours(img,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE)
# 绘制轮廓
# cv.drawContours(图像,轮廓列表,轮廓索引-1则绘制所有,轮廓颜色,轮廓的宽度)
cv.drawContours(img,contours,-1,(255,125,125),2)
计算最小外接圆、最小外接矩形、周长、面积
# 外接圆
((x,y),radius) = cv.minEnclosingCircle(contour)
# 带旋转角度外接矩形 函数返回两个点坐标(共4个值)和一个旋转角度
rect1 = cv.minAreaRect(contour)
pt1 = rect1[0] #第一个点坐标
pt2 = rect1[1] #第二个点坐标
cv.rectangle(src,pt1,pt2,(255,255,0),1)
# 不带旋转角度外接矩形
rect2 = cv.boundingRect(contour)
# 周长
length = cv.arcLength(contour,True) #第二个参数单标轮廓是否闭合,单位是像素
# 面积
area = cv.contourArea(contour)
5. 实例:寻找球的外接圆
import cv2 as cv
import numpy as np
def read_rgb_img(img_name):
rgb_img = cv.imread(img_name,cv.IMREAD_COLOR)
cv.imshow("rgb img",rgb_img)
return rgb_img
def convert_rgb2gray(img):
gray_img = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
# 采用高斯滤波去掉噪点
gray_img = cv.GaussianBlur(gray_img,(5,5),0)
cv.imshow("gray img", gray_img)
return gray_img
def convert_gray2binary(img):
binary_img = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY_INV,5,2)
cv.imshow("binary img", binary_img)
return binary_img
def filter_tenis(img,lower_color,upper_color):
hsv_img = cv.cvtColor(img,cv.COLOR_BGR2HSV)
# 查找颜色
mask_img = cv.inRange(hsv_img, lower_color, upper_color)
cv.imshow("mask img",mask_img)
return mask_img
def getContours(img):
_,contours,hierarchy = cv.findContours(img,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
print(contours,hierarchy)
return contours
def process_tenis_contours(rgb_img,contours):
black_img = np.zeros([rgb_img.shape[0],rgb_img.shape[1],3],np.uint8)
for c in contours:
# 计算面积
area = cv.contourArea(c)
# 该函数计算曲线长度或闭合轮廓周长。
perimeter = cv.arcLength(c,True)
# 获取最小的外切圆
((x,y),radius) = cv.minEnclosingCircle(c)
# 绘制轮廓
cv.drawContours(rgb_img,[c],-1,(150,250,150),2)
cv.drawContours(black_img,[c],-1,(150,250,150),2)
# 获取轮廓中心点
# cx,cy = get_contour_center(c)
# print(cx,cy)
x = int(x)
y = int(y)
cv.circle(rgb_img,(x,y),int(radius),(0,0,255),2)
cv.circle(black_img,(x,y),int(radius),(0,0,255),2)
print("Area:{},primeter:{}".format(area,perimeter))
print("number of contours:{}".format(len(contours)))
cv.imshow("rgb img contours",rgb_img)
cv.imshow("black img contours",black_img)
if __name__ == '__main__':
img_name = "assets/tenis1.jpg"
# 定义范围
lower_color = (30, 120, 130)
upper_color = (60, 255, 255)
rgb_img = read_rgb_img(img_name)
binary_imgage = filter_tenis(rgb_img,lower_color,upper_color)
contours = getContours(binary_imgage)
process_tenis_contours(rgb_img,contours)
cv.waitKey(0)
cv.destroyAllWindows()
效果如下:
彩蛋:明天是清明节啦,可以放松放松,一起加油油!