轮廓检测
案例一,只检测外轮廓
import cv2
import numpy as np
# 读取图像
image = cv2.imread('img.png')
# 将图像转换为灰度
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 通过阈值处理得到二值图像
_, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 寻找轮廓
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 在原图上绘制轮廓
cv2.drawContours(image, contours, -1, (0, 255, 0), 2)
# 显示结果
cv2.imshow('Original Image', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 效果如图
PNB8QA39L}9K9W2_A63_V~N.jpg
image.png案例二,检索所有的轮廓
import cv2
# 读取图像
image = cv2.imread('yuan.png')
# 将图像转换为灰度
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 通过阈值处理得到二值图像
_, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 寻找轮廓(使用cv2.RETR_TREE模式)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 在原图上绘制轮廓及其层次结构
cv2.drawContours(image, contours, -1, (0, 255, 0), 2)
# 显示结果
cv2.imshow('Contours with Hierarchy', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
image.png
image.png案例三,根据轮廓条件来筛选
import cv2
img = cv2.imread('./yuan.png', 1)
orgImg = img.copy() # 创建一个深copy对象
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img = cv2.GaussianBlur(img, (3, 3), 0)
# show(img,'gauss')
_, img = cv2.threshold(img, 200, 255, cv2.THRESH_BINARY)
# show(img, 'thres')
canny = cv2.Canny(img, 50, 150)
# show(img, 'canny')
# cv2.RETR_EXTERNAL 只检测外轮廓
# cv2.RETR_LIST 没有层级关系的轮廓
# cv2.RETR_CCOMP 有层级关系的轮廓
# cv2.RETR_TREE 树结构的轮廓
# cv2.CHAIN_APPROX_NONE 存储所有边界点
# cv2.CHAIN_APPROX_SIMPLE 压缩垂直、水平、对角方向,只保留端点
# contours:轮廓点。列表格式,每一个元素为一个3维数组(其形状为(n,1,2),其中n表示轮廓点个数,2表示像素点坐标),表示一个轮廓
# hierarchy:轮廓间的层次关系,为三维数组,形状为(1,n,4),其中n表示轮廓总个数,4指的是用4个数表示各轮廓间的相互关系
# 第一个数表示同级轮廓的下一个轮廓编号,第二个数表示同级轮廓的上一个轮廓的编号,
# 第三个数表示该轮廓下一级轮廓的编号,第四个数表示该轮廓的上一级轮廓的编号。
contours, hierarchy = cv2.findContours(canny, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 遍历轮廓,还原到原图中,人眼识别在那里
for i in range(len(contours)):
# 1.特征,计算轮廓的面积【*****】
area = cv2.contourArea(contours)
if area > 40000 and area < 49000:
print(f"轮廓的面积{i}:", area)
# rgb图, 所有轮廓, 第几个轮廓
# 为了调试,过滤才使用
perimeter = cv2.arcLength(contours, True)
print(f'当前轮廓的周长:{perimeter}')
if perimeter > 1000: continue
orgImg = cv2.drawContours(orgImg, contours, i, (0, 0, 255), 3)
cv2.imshow("yuan", orgImg)
cv2.waitKey(0)
image.png轮廓近似检测
import cv2
# 轮廓检测
img = cv2.imread('./20230927111939.jpg', 1)
cv2.imshow("", img)
cv2.waitKey(0)
oldImg = img.copy() # 创建1个新对象
# 转换为灰度图
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值 化
ret, thresh = cv2.threshold(imgray, 127, 255, 0)
# c.show(thresh)
# 高斯滤波
gau_shi = cv2.GaussianBlur(thresh, [3, 3], 0)
canny = cv2.Canny(img, 50, 150)
contours, hierarchy = cv2.findContours(canny, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for i in range(len(contours)):
img = cv2.drawContours(img.copy(), contours, i, (0, 0, 255), 3)
cv2.imshow('old-con', img)
cv2.waitKey(0)
cnt = contours[0]
epsilon = 0.1 * cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True)
img3 = cv2.drawContours(oldImg, [approx], -1, (0, 0, 255), 3)
cv2.imshow("", img3)
cv2.waitKey(0)
img4 = cv2.polylines(oldImg.copy(), [approx], True, (0, 255, 0), 5)
cv2.imshow("", img4)
cv2.waitKey(0)
image.png直接获取近似轮廓
# 轮廓检测
img = cv2.imread('./20230927111939.jpg', 1)
oldImg = img.copy() # 创建1个新对象
# 转换为灰度图
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值 化
ret, thresh = cv2.threshold(imgray, 127, 255, 0)
# c.show(thresh)
# 高斯滤波
gau_shi = cv2.GaussianBlur(thresh, [3, 3], 0)
canny = cv2.Canny(img, 50, 150)
contours, hierarchy = cv2.findContours(canny, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for i in range(len(contours)):
img = cv2.drawContours(img.copy(), contours, i, (0, 0, 255), 3)
cv2.imshow('old-con', img)
cv2.waitKey(0)
cnt = contours[0]
# 得到轮廓的外接矩形
x, y, w, h = cv2.boundingRect(cnt)
img = cv2.rectangle(oldImg, (x, y), (x + w, y + h), (255, 0, 0), 2)
cv2.imshow("", img)
cv2.waitKey(0)
image.png获取旋转矩形
import cv2
import numpy as np
# 读取图像
image = cv2.imread('20230927143717.jpg')
# 将图像转换为灰度
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 进行边缘检测
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
# 寻找轮廓
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 遍历每个轮廓
for contour in contours:
# 拟合外接矩形
rect = cv2.minAreaRect(contour)
box = cv2.boxPoints(rect)
box = np.intp(box)
# 在原始图像上绘制矩形
# cv2.drawContours(image, [box], 0, (0, 255, 0), 2)
cv2.polylines(image, [box], isClosed=True, color=(0, 255, 0), thickness=2)
# 显示结果
cv2.imshow('Rotated Rectangle Detection', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
image.pngcv2.polylines和cv2.drawContours的区别
cv2.polylines 和 cv2.drawContours 是 OpenCV 中用于绘制多边形或轮廓的两个不同的函数。
cv2.polylines:
cv2.polylines 用于绘制多条线段,即可以绘制多边形。语法:cv2.polylines(img, pts, isClosed, color[, thickness[, lineType[, shift]]])
img:要绘制线段的图像。pts:包含多边形顶点坐标的数组。isClosed:指定是否封闭多边形。如果为 True,则多边形将首尾相连形成封闭图形;如果为 False,则多边形只是一组线段而不封闭。color:线段的颜色。thickness:线段的宽度。默认值为 1。lineType:线段的类型。默认值为 8-connected(8 连通)。更多选项可以参考 OpenCV 文档。shift:坐标中的小数位数。默认值为 0。
cv2.drawContours:
cv2.drawContours 用于绘制轮廓。语法:cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]])
image:要绘制轮廓的图像。contours:包含轮廓的列表。contourIdx:要绘制的轮廓的索引。如果为负数,则绘制所有轮廓。color:轮廓的颜色。thickness:轮廓线的宽度。如果为负数或cv2.FILLED,则填充轮廓。lineType:轮廓线的类型。hierarchy:轮廓的层次结构信息。maxLevel:绘制轮廓的最大层次。offset:每个轮廓的可选偏移量。
总的来说,cv2.polylines 适用于绘制多条线段,而 cv2.drawContours 适用于绘制轮廓。cv2.drawContours 的灵活性更高,可以用于处理更复杂的轮廓结构。
矩形识别的其他代码-混乱仅参考
import cv2
import numpy as np
def show(img, title=''):
cv2.imshow(title, img)
cv2.waitKey(0)
# 边缘检测都是针对灰度图像
img = cv2.imread("20230927143717.jpg", 0)
oldImg = img.copy() # 创建1个新对象
gau_shi = cv2.GaussianBlur(oldImg, [3, 3], 0)
canny = cv2.Canny(gau_shi, 50, 150)
show(canny, 'canny')
contours, hierarchy = cv2.findContours(canny, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
for i in range(len(contours)): # oldImg.copy(),每次运行的时候,会新建一个地址空间。避免内容叠加
# img = cv2.drawContours(oldImg.copy(), contours, i, (0,0,255), 3)
# c.show(img,i) # x, y, w, h = cv2.boundingRect(contours) # 得到矩型 ,不包含旋转矩型
# img = cv2.rectangle(oldImg, (x, y), (x + w, y + h), (0, 0, 255), 10)
# c.show(img)
rect = cv2.minAreaRect(contours) # 返回回点集cnt的最小外接矩形
box = cv2.boxPoints(rect) # 获取最小外接矩形的4个顶点坐标
box = np.intp(box)
img2 = cv2.polylines(oldImg.copy(), [box], True, (0, 255, 0), 5)
show(img2, 'xuanzhuan')
(x, y), radius = cv2.minEnclosingCircle(contours) # 得到最小外接圆
center = (int(x), int(y))
radius = int(radius)
img = cv2.circle(img, center, radius, (0, 0, 255), 2)
show(img, 'yuan')
"""
(x, y)代表椭圆中心点的位置
(a, b)代表长短轴长度,应注意a、b为长短轴的直径,而非半径
angle 代表了中心旋转的角度
""" ellipse = cv2.fitEllipse(contours) # 得到椭圆
im = cv2.ellipse(oldImg.copy(), ellipse, (0, 255, 0), 2)
show(im, 'tuoyuan')
# 根据一组点拟合出一条直线
rows, cols = img.shape[:2]
[vx, vy, x, y] = cv2.fitLine(contours, cv2.DIST_L2, 0, 0.01, 0.01)
lefty = int((-x * vy / vx) + y)
righty = int(((cols - x) * vy / vx) + y)
img = cv2.line(oldImg.copy(), (cols - 1, righty), (0, lefty), (0, 255, 0), 2)
show(img, 'ff')
获取最小外接圆
import cv2
import numpy as np
# 读取图像
image = cv2.imread('20230927143717.jpg')
# 将图像转换为灰度
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 进行边缘检测
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
# 寻找轮廓
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 遍历每个轮廓
for contour in contours:
# 获取最小外接圆
(x, y), radius = cv2.minEnclosingCircle(contour)
center = (int(x), int(y))
radius = int(radius)
# 在原始图像上绘制最小外接圆
cv2.circle(image, center, radius, (0, 255, 0), 2)
# 显示结果
cv2.imshow('Minimum Enclosing Circle Detection', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
外接圆获取外接椭圆
import cv2
# 读取图像
image = cv2.imread('20230927143717.jpg')
# 将图像转换为灰度
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 进行边缘检测
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
# 寻找轮廓
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 遍历每个轮廓
for contour in contours:
# 拟合外接椭圆
ellipse = cv2.fitEllipse(contour)
# 在原始图像上绘制椭圆
cv2.ellipse(image, ellipse, (0, 255, 0), 2)
# 显示结果
cv2.imshow('Fitted Ellipses', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
获取最小外接椭圆
import cv2
# 读取图像
image = cv2.imread('20230927143717.jpg')
# 将图像转换为灰度
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 进行边缘检测
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
# 寻找轮廓
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 遍历每个轮廓
for contour in contours:
# 拟合外接椭圆
ellipse = cv2.fitEllipse(contour)
# 在原始图像上绘制椭圆
cv2.ellipse(image, ellipse, (0, 255, 0), 2)
# 显示结果
cv2.imshow('Fitted Ellipses', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
image.png求平均颜色或者灰度
import cv2
# 读取图像
image = cv2.imread('20230927143717.jpg')
# 将图像转换为灰度
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 计算灰度平均值
average_value = cv2.mean(gray)[0]
# 打印平均值
print(f"灰度平均值: {average_value}")
获取极点
leftmost = tuple(cnt[cnt[:,:,0].argmin()][0])
rightmost = tuple(cnt[cnt[:,:,0].argmax()][0])
topmost = tuple(cnt[cnt[:,:,1].argmin()][0])
bottommost = tuple(cnt[cnt[:,:,1].argmax()][0])
用于找到轮廓 (cnt) 的最左边点 (leftmost)、最右边点 (rightmost)、最上边点 (topmost) 和最下边点 (bottommost)。 |