60_霍夫圆.py
61_霍夫圆_查找棋子_滑动条.py
62_查找物体的轮廓信息.py
63_查找物体的轮廓信息_绘制外接矩形.py
64_网球案例.py
64_获取轮廓相关信息.py
64_获取轮廓相关信息_优化.py
原理
代码
"""
需求:
1. 读取图像
"""
import logging
import cv2 as cv
# 霍夫圆形检测
def hough_circle(in_gray_img):
# 定义检测图像中圆的方法。目前唯一实现的方法是cv2.HOUGH_GRADIENT
method = cv.HOUGH_GRADIENT
# 累加器分辨率与图像分辨率的反比。例如,如果dp = 1,则累加器具有与输入图像相同的分辨率。如果dp = 2,则累加器的宽度和高度都是一半。
dp = 1
# 检测到的圆的圆心之间最小距离。如果minDist太小,则可能导致检测到多个相邻的圆。如果minDist太大,则可能导致很多圆检测不到。
minDist = 20
# param1 Canny算法阈值上线
# param2 cv2.HOUGH_GRADIENT方法的累加器阈值。阈值越小,检测到的圈子越多。
# minRadius : 最小的半径,如果不确定,则不指定
# maxRadius : 最大的半径,若不确定,则不指定
circles = cv.HoughCircles(in_gray_img, method, dp, minDist=minDist, param1=70, param2=30, minRadius=0, maxRadius=20)
try:
for circle in circles[0, :]:
# 圆心坐标,半径
x, y, r = circle
# 绘制圆心
cv.circle(img, (x, y), 2, (0, 255, 0), 1)
# 绘制圆形
cv.circle(img, (x, y), int(r), (0, 0, 255), 2)
cv.imshow("result", img)
except:
logging.warning("霍夫圆没有找到,个数为0")
# 0. 配置日志
logging.basicConfig(level=logging.INFO)
# 1. 读取图像, 将图片转成灰色图片
# filename = r"../img/weiqi.jpg"
# filename = r"../img/water_coins.jpg"
filename = r"../img/tenis1.jpg"
img = cv.imread(filename, cv.IMREAD_COLOR)
gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 调用函数,寻找霍夫圆
hough_circle(gray_img)
# 显示图像,等待按键
cv.imshow("img", img)
cv.imshow("gray", gray_img)
cv.waitKey(0)
cv.destroyAllWindows()
代码
"""
需求:
1. 读取图像
"""
import logging
import cv2 as cv
# 霍夫圆形检测
def hough_circle(index, in_gray_img, v):
global img
global _dp, _minDist, _param1, _param2, _minRadius, _maxRadius
dst = img.copy()
# 定义检测图像中圆的方法。目前唯一实现的方法是cv2.HOUGH_GRADIENT
method = cv.HOUGH_GRADIENT
if index == 0:
_dp = v # 1
elif index == 1:
_minDist = v # 20
elif index == 2:
_param1 = v # 80
elif index == 3:
_param2 = v # 40
elif index == 4:
_minRadius = v # 10
elif index == 5:
_maxRadius = v # 37
circles = cv.HoughCircles(in_gray_img, method,
dp=_dp, # 1
minDist=_minDist, # 20
param1=_param1, # 80
param2=_param2, # 40
minRadius=_minRadius, # 10
maxRadius=_maxRadius # 37
)
# logging.info("circles.shape={0}\ncircles=\n{1}".format(circles.shape, circles)) # x, y, radius
logging.info("dp::{0}, minDist::{1}, _param1::{2}, _param2::{3}, _minRadius::{4}, _maxRadius::{5}".format(
_dp, _minDist, _param1, _param2, _minRadius, _maxRadius
))
for circle in circles[0, :]:
# 圆心坐标,半径
x, y, r = circle
x = int(x)
y = int(y)
r = int(r)
# 绘制圆心
cv.circle(dst, (x, y), 2, (0, 255, 0), 1)
# 绘制圆形
cv.circle(dst, (x, y), r, (0, 0, 255), 2)
cv.imshow("dst", dst)
# 0. 配置日志
logging.basicConfig(level=logging.INFO)
# 1. 读取图像, 将图片转成灰色图片
filename = r"../img/weiqi.jpg" # 1, 24, 18, 33, 4, 17
# filename = r"../img/coins.jpg" # 1, 18, 60, 20, 0, 10
img = cv.imread(filename, cv.IMREAD_COLOR)
gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
gray_img = cv.GaussianBlur(gray_img, (5, 5), 0)
# 调用函数,寻找霍夫圆
# 显示图像,等待按键
cv.imshow("img", img)
cv.imshow("dst", img)
cv.imshow("gray", gray_img)
# 定义全局变量,用以存储改变值
_dp = 1
_minDist = 20
_param1 = 70
_param2 = 30
_minRadius = 0
_maxRadius = 40
cv.createTrackbar("dp", "dst", 1, 2, lambda v: hough_circle(0, gray_img, v))
cv.createTrackbar("minDist", "dst", 10, 40, lambda v: hough_circle(1, gray_img, v))
cv.createTrackbar("param1", "dst", 60, 80, lambda v: hough_circle(2, gray_img, v))
cv.createTrackbar("param2", "dst", 20, 40, lambda v: hough_circle(3, gray_img, v))
cv.createTrackbar("minR", "dst", 0, 10, lambda v: hough_circle(4, gray_img, v))
cv.createTrackbar("maxR", "dst", 10, 40, lambda v: hough_circle(5, gray_img, v))
cv.waitKey(0)
cv.destroyAllWindows()
原理
# 查找轮廓
处理的图像,轮廓列表,继承关系 = cv.findContours(图像,轮廓检索模式,检索的方法)
# hierarchy[i][3],分别表示第i个轮廓的后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号
# 绘制轮廓
cv.drawContours(图像,轮廓列表,轮廓索引-1则绘制所有,轮廓颜色,轮廓的宽度)
代码
"""
需求:
1. 读取图像
"""
import logging
import cv2 as cv
import numpy as np
# 0. 配置日志
logging.basicConfig(level=logging.INFO)
# 1. 读取图像,转化成灰度图
filename = r"../img/shape.jpg"
src = cv.imread(filename, cv.IMREAD_COLOR)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# 2. 将图像转化成二值图, block_size 表示 block_size x block_size 的正方形区域
binary = cv.adaptiveThreshold(gray, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY_INV, 11, 5)
binary = cv.medianBlur(binary, 3)
# 3. 找出 二值图 中的轮廓
b_c, contours, hieracrchy = cv.findContours(binary, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
logging.info("b_c.shape::{0}\ncontours::{1}\nlen(contours)::{2}\nhieracrchy::{3}".format(
b_c.shape, contours, len(contours), hieracrchy)) # hieracrchy::[[[-1 -1 -1 -1]]] 最外层轮廓
# 4. 绘制轮廓
cv.drawContours(src, contours, -1, (180, 180, 0), 2, cv.LINE_AA)
# 显示图像,等待按键
cv.imshow("src", src)
cv.imshow("gray", gray)
cv.imshow("binary", binary)
cv.imshow("b_c", b_c)
key = cv.waitKey(0)
logging.info("key = {0}".format(key))
代码
"""
需求:
1. 读取图像
"""
import logging
import cv2 as cv
import numpy as np
# 0. 配置日志
logging.basicConfig(level=logging.INFO)
# 1. 读取图像,转化成灰度图
# filename = r"../img/shape.jpg"
# filename = r"../img/rect_inclined.PNG"
filename = r"../img/trapezoid_inclined.PNG"
src = cv.imread(filename, cv.IMREAD_COLOR)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# 2. 将图像转化成二值图, block_size 表示 block_size x block_size 的正方形区域
binary = cv.adaptiveThreshold(gray, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY_INV, 11, 2)
binary = cv.medianBlur(binary, 3)
# 3. 找出 二值图 中的轮廓
"""
contours 中的 每一个 contour 存储的是一个点
"""
b_c, contours, hieracrchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
# logging.info("b_c.shape::{0}\ncontours::{1}\nlen(contours)::{2}\nhieracrchy::{3}".format(
# b_c.shape, contours, len(contours), hieracrchy)) # hieracrchy::[[[-1 -1 -1 -1]]] 最外层轮廓
# 4. 绘制轮廓
cv.drawContours(src, contours, -1, (180, 180, 0), 2, cv.LINE_AA)
# 5. 根据轮廓计算外切圆,对每一个轮廓
for contour in contours: # 有 len(contours)个轮廓,每一个轮廓有
# logging.info("contour::{0}\ncontour.shape::{1}".format(contour, contour.shape)) # contour.shape::(198, 1, 2), 198点
# logging.info("{}, {}".format(len(contour), type(contour))) # INFO:root:136,
# 需求1:求最小外切圆
center, radius = cv.minEnclosingCircle(contour)
x = int(center[0])
y = int(center[1])
r = int(radius)
cv.circle(src, (x, y), r, (0, 0, 255), 2)
# 需求2:最小外切矩形(带旋转角度,不合要求)
"""
INFO:root:((93.92063903808594, 239.05789184570312), (77.08946228027344, 103.39725494384766), -36.11933898925781)
左上点,右下点,角度弧度
"""
# ret_v = cv.minAreaRect(contour)
# # logging.info("{}".format(ret_v))
# pt1 = ret_v[0]
# pt2 = ret_v[1]
# pt1 = (int(pt1[0]), int(pt1[1]))
# pt2 = (int(pt2[0]), int(pt2[1]))
# cv.rectangle(src, pt1, pt2, (100, 200, 250), 2)
# 需求3:最小外切矩形
"""
Calculates the up-right bounding rectangle of a point set or non-zero pixels of gray-scale image.
"""
ret_v2 = cv.boundingRect(contour)
x, y, w, h = ret_v2
cv.rectangle(src, (x, y), (x + w, y + h), (255, 100, 0), 2)
# 需求4:
# 显示图像,等待按键
cv.imshow("src", src)
cv.imshow("gray", gray)
cv.imshow("binary", binary)
cv.imshow("b_c", b_c)
key = cv.waitKey(0)
logging.info("key = {0}".format(key))
代码
"""
需求:
1. 读取图像
"""
import logging
import cv2 as cv
import numpy as np
# 0. 配置日志
logging.basicConfig(level=logging.INFO)
# 1. 读取图像, 转换成灰度图像
filename = r"../img/tenis1.jpg"
src = cv.imread(filename, cv.IMREAD_COLOR)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# 2. 灰度图转换成二值图
ret_v, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_TRIANGLE)
logging.info("{}".format(ret_v))
# 3. 对二值图进行滤波处理
binary = cv.medianBlur(binary, 7)
# 4. 查找轮廓,绘制轮廓
image, contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
# logging.info("{}".format(len(contours))) # 只有一个轮廓,这个轮廓由278个点组成
cv.drawContours(src, contours, -1, (0, 0, 255), 2, cv.LINE_AA)
# 5. 计算外切圆,绘制外切圆
for contour in contours:
# logging.info("{}, {}".format(contour, len(contour)))
# 求最小外切圆
center, radius = cv.minEnclosingCircle(contour)
x, y, r = int(center[0]), int(center[1]), int(radius)
cv.circle(src, (x, y), r, (255, 0, 0), 2)
pass
# 显示图像,等待按键
cv.imshow("src", src)
cv.imshow("gray", gray)
cv.imshow("binary", binary)
key = cv.waitKey(0)
logging.info("key = {}".format(key))
代码
"""
需求:
1. 读取图像
参考:
绘制倾斜矩形轮廓的资料
1. https://my.oschina.net/u/4386741/blog/3664544
2. https://blog.csdn.net/lanyuelvyun/article/details/76614872
"""
import logging
import cv2 as cv
import numpy as np
# 0. 配置日志
logging.basicConfig(level=logging.INFO)
# 1. 读取图像, 转换成灰度图像
# filename = r"../img/tenis1.jpg"
filename = r"../img/trapezoid_inclined.PNG"
src = cv.imread(filename, cv.IMREAD_COLOR)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# 2. 灰度图转换成二值图
ret_v, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_TRIANGLE)
# logging.info("{}".format(ret_v))
# 3. 对二值图进行滤波处理
binary = cv.medianBlur(binary, 7)
# 4. 查找轮廓,绘制轮廓
image, contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
# logging.info("{}".format(len(contours))) # 只有一个轮廓,这个轮廓由278个点组成
logging.info("contours::\n{}".format(contours))
cv.drawContours(src, contours, -1, (0, 0, 255), 2, cv.LINE_AA)
# 5. 计算外切圆,绘制外切圆
for contour in contours:
# logging.info("{}, {}".format(contour, len(contour)))
# 需求1:求最小外切圆
center, radius = cv.minEnclosingCircle(contour)
x, y, r = int(center[0]), int(center[1]), int(radius)
img_circle = cv.circle(src, (x, y), r, (255, 0, 0), 2)
# 需求2:求外接矩形
ret_v = cv.boundingRect(contour)
x, y, w, h = ret_v
img_b_rect = cv.rectangle(src, (x, y), (x + w, y + h), (200, 100, 200), 2, cv.LINE_AA)
# 需求3:求最小面积外接矩形(带旋转角度)(尝试实现)
# center, size, angle = cv.minAreaRect(contour) # 矩形中心, 宽高, angle
rect = cv.minAreaRect(contour)
box = cv.boxPoints(rect)
# logging.info("box::\n{0}".format(box))
box = np.int32(box)
img_min_rect = cv.drawContours(src, [box], -1, (255, 255, 255), 2, cv.LINE_AA)
# 需求4:获取周长
ret_v = cv.arcLength(contour, closed=True)
logging.info("ret_v::\n{0}".format(ret_v))
# 需求5:获取面积
ret_v = cv.contourArea(contour)
logging.info("rect_v::\n{0}".format(ret_v))
# 显示图像,等待按键
cv.imshow("src", src)
cv.imshow("gray", gray)
cv.imshow("binary", binary)
cv.imshow("img_circle", img_circle)
cv.imshow("img_b_rect", img_b_rect)
key = cv.waitKey(0)
logging.info("key = {}".format(key))
代码
"""
需求:
1. 读取图像
参考:
绘制倾斜矩形轮廓的资料
1. https://my.oschina.net/u/4386741/blog/3664544
2. https://blog.csdn.net/lanyuelvyun/article/details/76614872
"""
import logging
import cv2 as cv
import numpy as np
"""------------------------- 函数区 -------------------------"""
def get_min_enclose_circle(img, contour):
center, radius = cv.minEnclosingCircle(contour)
x, y, r = int(center[0]), int(center[1]), int(radius)
cv.circle(img, (x, y), r, (255, 0, 0), 2)
cv.imshow("min_enc_cir", img)
def get_bound_rect(img, contour):
ret_v = cv.boundingRect(contour)
x, y, w, h = ret_v
cv.rectangle(img, (x, y), (x + w, y + h), (200, 0, 0), 2, cv.LINE_AA)
cv.imshow("bound_rect", img)
def get_min_enclose_rect_rotate(img, contour):
rect = cv.minAreaRect(contour)
box = cv.boxPoints(rect)
box = np.int32(box)
cv.drawContours(img, [box], -1, (255, 0, 0), 2, cv.LINE_AA)
cv.imshow("min_area_rect", img)
def get_contour_length(contour):
ret_v = cv.arcLength(contour, closed=True)
logging.info("ret_v::\n{0}".format(ret_v))
def get_contour_area(contour):
ret_v = cv.contourArea(contour)
logging.info("rect_v::\n{0}".format(ret_v))
"""------------------------- 调试区 -------------------------"""
# 0. 配置日志
logging.basicConfig(level=logging.INFO)
# 1. 读取图像, 转换成灰度图像
# filename = r"../img/tenis1.jpg"
filename = r"../img/shape_collection.PNG"
src = cv.imread(filename, cv.IMREAD_COLOR)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# 2. 灰度图转换成二值图
ret_v, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_TRIANGLE)
# 3. 对二值图进行滤波处理
binary = cv.medianBlur(binary, 7)
# 4. 查找轮廓,绘制轮廓
image, contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
img_contours = src.copy()
cv.drawContours(img_contours, contours, -1, (0, 0, 255), 2, cv.LINE_AA)
# 5. 对轮廓集中的每一个轮廓,计算外切圆,绘制外切圆等
min_enc_cir = src.copy()
bound_rect = src.copy()
min_enc_rect_rotate = src.copy()
for i, contour in enumerate(contours):
logging.info("contour::{0}".format(i))
# 需求1:求最小外切圆
get_min_enclose_circle(min_enc_cir, contour)
# 需求2:求外接矩形
get_bound_rect(bound_rect, contour)
# 需求3:求最小面积外接矩形(带旋转角度)(尝试实现)
get_min_enclose_rect_rotate(min_enc_rect_rotate, contour)
# 需求4:获取周长
get_contour_length(contour)
# 需求5:获取面积
get_contour_area(contour)
# 显示图像,等待按键
cv.imshow("src", src)
cv.imshow("gray", gray)
cv.imshow("binary", binary)
cv.imshow("contours", img_contours)
key = cv.waitKey(0)
logging.info("key = {}".format(key))