OpenCV-09-霍夫变换及轮廓查找(绘制 最小外接圆、旋转外接矩形、不旋转外接矩形)

1. 霍夫直线变换,是在极坐标上,对某一个点进行旋转,绘制曲线,当两条极坐标曲线相交于一点,则这两个点在一条线上,有n个点在极坐标上的曲线相交了m次,当m大于一定的阈值,则认为存在该条直线。

霍夫直线的绘制代码:

rho = 1;
theta = np.pi/180
threshold=0
lines = cv.HoughLines(img,rho, theta, threshold)

2. 绘制棋盘上的直线

OpenCV-09-霍夫变换及轮廓查找(绘制 最小外接圆、旋转外接矩形、不旋转外接矩形)

#  霍夫变换
#  线段以像素为单位的距离精度,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()

    效果如下:

OpenCV-09-霍夫变换及轮廓查找(绘制 最小外接圆、旋转外接矩形、不旋转外接矩形)
彩蛋:明天是清明节啦,可以放松放松,一起加油油!

上一篇:OpenCV-Python开发指南(25)---矩特征


下一篇:opencv 轮廓的外围多边形提取或者删除最小最大轮廓