这片也有点长,加个目录
1. 图像形状检测
1.1 霍夫直线检测
1.2 霍夫圆检测
2. 轮廓检测
2.1 图像轮廓绘制
2.2 矩形
2.3 旋转矩形
2.4 圆
2.5 凸包
2.6 轮廓绘制调试
霍夫直线检测
使用matplotlib展示图像
'''
HoughLinesP是HoughLines的优化版本
'''
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('./resource/image_A.png')
original_img=img.copy()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 120)
lines = cv2.HoughLinesP(edges, rho=1,
theta=np.pi/180.0,
threshold=20,
minLineLength=40,
maxLineGap=5)
for line in lines:
x1, y1, x2, y2 = line[0]
cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 8), dpi=100)
axes[0][0].imshow(original_img[:,:,[2,1,0]])
axes[0][0].set_title("original")
axes[0][1].imshow(edges, cmap=plt.cm.gray)
axes[0][1].set_title("Canny")
axes[1][0].imshow(img[:, :, ::-1])
axes[1][0].set_title("Result(threshold:300)")
plt.show()
霍夫圆检测
使用matplotlib展示图像
import cv2
import matplotlib.pyplot as plt
import numpy as np
# 读取图像
original_image=cv2.imread ('./resource/4.png',cv2.IMREAD_COLOR)
original_image_copy=original_image.copy()
original_gray_image=cv2.imread ('./resource/4.png',cv2.IMREAD_GRAYSCALE)
# 进行中值滤波
dst_img = cv2.medianBlur(original_gray_image, 7)
'''
参数:
image:输入图像(灰度图)
method:使用霍夫变换圆检测的算法,参数为cv2.HOUGH_GRADIENT
dp:霍夫空间的分辨率,dp=1时表示霍夫空间与输入图像空间的大小一致,dp=2时霍夫空间是输入图像空间的一半,以此类推
minDist:为圆心之间的最小距离,如果检测到的两个圆心之间距离小于该值,则认为它们是同一个圆心
param1:边缘检测时使用Canny算子的高阈值,低阈值是高阈值的一半
param2∶检测圆心和确定半径时所共有的阈值
minRadius和maxRadius:为所检测到的圆半径的最小值和最大值
'''
# 霍夫圆检测
circle = cv2.HoughCircles(dst_img, cv2.HOUGH_GRADIENT, 1, 70,param1=55, param2=55, minRadius=50, maxRadius=200)
# 将检测结果绘制在图像上
for i in circle[0, :]: # 遍历矩阵的每一行的数据
# 绘制圆形
cv2.circle(original_image_copy, (int(i[0]), int(i[1])), int(i[2]), (255, 0, 0), 10)
# 绘制圆心
cv2.circle(original_image_copy, (int(i[0]), int(i[1])), 2, (255, 0, 0), 3)
# 显示图像
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(10, 8), dpi=100)
axes[0].imshow(original_image[:, :, ::-1])
axes[0].set_title("original")
axes[1].imshow(original_image_copy[:, :, ::-1])
axes[1].set_title("result")
plt.show()
轮廓检测
使用matplotlib展示图像
import numpy as np
import cv2
import matplotlib.pyplot as plt
# 读取图像
img=cv2.imread ('./resource/5.png',cv2.IMREAD_COLOR)
# original_gray_image=cv2.imread ('./resource/image_G.png',cv2.IMREAD_GRAYSCALE)
binaryImg=cv2.Canny(img,50,150)
#寻找轮廓
#也可以这么写:
#binary,contours, hierarchy = cv2.findContours(binaryImg,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#这样,可以直接用contours表示
h = cv2.findContours(binaryImg,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
#提取轮廓
contours = h[0]
#打印返回值,这是一个元组
print(type(h))
#打印轮廓类型,这是个列表
print(type(h[1]))
#查看轮廓数量
print (len(contours))
#创建白色幕布
temp = np.ones(binaryImg.shape,np.uint8)*255
#画出轮廓:temp是白色幕布,contours是轮廓,-1表示全画,然后是颜色,厚度
cv2.drawContours(temp,contours,-1,(0,255,0),3)
# 显示图形
plt.figure(figsize=(10,5))
plt.subplot(121)
# opencv是bgr,所以显示的时候需要逆转通道
plt.imshow(img[:,:,[2,1,0]])
plt.subplot(122)
# matplotlib不能直接显示opencv单通道的灰度图,需要把单通道的灰度图转换成三通道的灰度图
imgOfThree = np.concatenate((np.expand_dims(temp, axis=2), np.expand_dims(temp, axis=2), np.expand_dims(temp, axis=2)), axis=-1)
# 用matplotlib显示图片
plt.imshow(imgOfThree)
plt.show()
用矩形绘制图像轮廓
使用matplotlib展示图像
# -*- coding: utf-8 -*-
import numpy as np
import cv2
import sys
#主函数
img = cv2.imread('./resource/5.png',cv2.IMREAD_COLOR)
#第二步:边缘检测 或者 阈值处理 生成一张二值图
img = cv2.GaussianBlur(img,(3,3),0.5)#高斯平滑处理
binaryImg = cv2.Canny(img,50,200)
#第三步:边缘的轮廓,返回的 contours 是一个 list 列表
h = cv2.findContours(binaryImg,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
#提取轮廓
contours = h[0]
#打印返回值,这是一个元组
print(type(h))
#打印轮廓类型,这是个列表
print(type(h[1]))
#查看轮廓数量
n=len(contours)
print(n)
for i in range(len(contours)):
x, y, w, h = cv2.boundingRect(contours[i])
if 120000>int(w)*int(h)>10000:
cv2.rectangle(img, (x, y), (x+w, y+h), (0,0,255), 3)
cv2.imshow("binaryImg",img)
cv2.waitKey(0)
cv2.destroyAllWindows()
用旋转矩形绘制轮廓
使用matplotlib展示图像
import numpy as np
import cv2
#主函数
img = cv2.imread('./resource/5.png',cv2.IMREAD_COLOR)
#第二步:边缘检测 或者 阈值处理 生成一张二值图
img = cv2.GaussianBlur(img,(3,3),0.5)#高斯平滑处理
binaryImg = cv2.Canny(img,50,200)
#第三步:边缘的轮廓,返回的 contours 是一个 list 列表
h = cv2.findContours(binaryImg,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
#提取轮廓
contours = h[0]
#打印返回值,这是一个元组
print(type(h))
#打印轮廓类型,这是个列表
print(type(h[1]))
#查看轮廓数量
n=len(contours)
for i in range(len(contours)):
# 返回最小外接矩形的中心(x,y),(宽度,高度),旋转角度
rect = cv2.minAreaRect(contours[i])
if 100000>int(rect[1][0])*int(rect[1][1])>50000:
box = cv2.boxPoints(rect) # 返回矩形四个角点坐标
box = np.int0(box) # 获得矩形角点坐标(整数)
cv2.drawContours(img, [box], -1, (0,0, 255,), 2)
cv2.imshow("binaryImg",img)
cv2.waitKey(0)
cv2.destroyAllWindows()
用圆绘制轮廓
使用matplotlib展示图像
import numpy as np
import cv2
img = cv2.imread('./resource/4.png',cv2.IMREAD_COLOR)
#第二步:边缘检测 或者 阈值处理 生成一张二值图
img = cv2.GaussianBlur(img,(3,3),0.5)#高斯平滑处理
binaryImg = cv2.Canny(img,50,200)
#第三步:边缘的轮廓,返回的 contours 是一个 list 列表
h = cv2.findContours(binaryImg,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
#提取轮廓
contours = h[0]
#打印返回值,这是一个元组
print(type(h))
#打印轮廓类型,这是个列表
print(type(h[1]))
#查看轮廓数量
n=len(contours)
for i in range(len(contours)):
# ----- 最小外包圆 -------
# 返回,center: 最小包围圆形的中心。radius: 最小包围圆形的半径
circle = cv2.minEnclosingCircle(contours[i])
if 20000<int(circle[1])**2*3.14<70000:
#画圆
cv2.circle(img,(int(circle[0][0]),int(circle[0][1])),int(circle[1]),255,2)
cv2.imshow("binaryImg",img)
cv2.waitKey(0)
cv2.destroyAllWindows()
使用凸包绘制轮廓
使用matplotlib展示图像
import cv2
import numpy as np
img = cv2.pyrDown(cv2.imread(r'./resource/7.jpg'))
# 阈值分割
ret, thresh = cv2.threshold(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY),127, 255, cv2.THRESH_BINARY)
# 寻找轮廓
contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
black = np.zeros_like(img)
for cnt in contours:
# 获取轮廓周长信息
epsilon = 0.01 * cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)
# 获取凸包的轮廓处理信息
hull = cv2.convexHull(cnt)
cv2.drawContours(black, [cnt], -1, (0, 255, 0), 2) # 原始轮廓
cv2.drawContours(black, [approx], -1, (255, 255, 0), 2) # 近似多边形
cv2.drawContours(black, [hull], -1, (0, 0, 255), 2) # 凸包
cv2.imshow("hull", black)
cv2.waitKey()
cv2.destroyAllWindows()
'''
另一种方法
# -*- coding: utf-8 -*-
import numpy as np
import cv2
import sys
#主函数
img = cv2.imread(r"D:\zxtGProject\105_OpenCV\OpenCV100\original\resource\image_O.jpg",cv2.IMREAD_COLOR)
#第二步:边缘检测 或者 阈值处理 生成一张二值图
img = cv2.GaussianBlur(img,(3,3),0.5)#高斯平滑处理
binaryImg = cv2.Canny(img,50,200)
#第三步:边缘的轮廓,返回的 contours 是一个 list 列表
h = cv2.findContours(binaryImg,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
#提取轮廓
contours = h[0]
#查看轮廓数量
n=len(contours)
# 寻找物体的凸包并绘制凸包的轮廓
for cnt in contours:
hull = cv2.convexHull(cnt)
length = len(hull)
# 如果凸包点集中的点个数大于5
if length > 10:
# # 绘制图像凸包的轮廓
for i in range(length):
cv2.line(img, tuple(hull[i][0]), tuple(hull[(i+1)%length][0]), (0,0,255), 2)
# 绘制凸包图形
# img_hull = cv2.drawContours(img, [hull], 0, (255, 255, 255), 3)
cv2.imshow("binaryImg",img)
cv2.waitKey(0)
cv2.destroyAllWindows()
'''
轮廓绘制调试
使用matplotlib展示图像
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('./resource/7.jpg',cv2.IMREAD_GRAYSCALE)
img_original=img.copy()
img_use_circle=img.copy()
#第一步:阈值化,生成二值图
#图像平滑
dst_threshold = cv2.GaussianBlur(img,(3,3),0.5)
# Otsu 阈值分割
OtsuThresh = 0
OtsuThresh,dst_otsu = cv2.threshold(dst_threshold,OtsuThresh,255,cv2.THRESH_OTSU)
# 形态学开运算( 消除细小白点 )
#创建结构元
s = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
dst_open = cv2.morphologyEx(dst_otsu,cv2.MORPH_OPEN,s,iterations=2)
#第二步:寻找二值图的轮廓,返回值是一个元组,hc[1] 代表轮廓
hc= cv2.findContours(dst_open,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
contours = hc[0]
#第三步:画出找到的轮廓并用多边形拟合轮廓
#轮廓的数量
n = len(contours)
#将轮廓画在该黑板上
contoursImg = np.zeros(img.shape,np.uint8)
for i in range(n):
#画出轮廓
cv2.drawContours(contoursImg,contours,i,255,2)
#画出轮廓的最小外包圆
circle = cv2.minEnclosingCircle(contours[i])
cv2.circle(img_use_circle,(int(circle[0][0]),int(circle[0][1])),int(circle[1]),0,5)
#多边形逼近(注意与凸包区别)
approxCurve = cv2.approxPolyDP(contours[i],0.3,True)
#多边形顶点个数
k = approxCurve.shape[0]
#顶点连接,绘制多边形
for i in range(k-1):
cv2.line(img,(approxCurve[i,0,0],approxCurve[i,0,1]),(approxCurve[i+1,0,0],approxCurve[i+1,0,1]),0,5)
#首尾相接
cv2.line(img,(approxCurve[k-1,0,0],approxCurve[k-1,0,1]),(approxCurve[0,0,0],approxCurve[0,0,1]),0,5)
# 显示图像
fig, axes = plt.subplots(nrows=2, ncols=4, figsize=(10, 8), dpi=100)
axes[0][0].imshow(img_original, cmap=plt.cm.gray)
axes[0][0].set_title("original")
axes[0][1].imshow(dst_threshold, cmap=plt.cm.gray)
axes[0][1].set_title("GaussianBlur")
axes[0][2].imshow(dst_otsu, cmap=plt.cm.gray)
axes[0][2].set_title("otsu")
axes[0][3].imshow(dst_open, cmap=plt.cm.gray)
axes[0][3].set_title("open")
axes[1][0].imshow(contoursImg, cmap=plt.cm.gray)
axes[1][0].set_title("contoursImg")
axes[1][1].imshow(img_use_circle, cmap=plt.cm.gray)
axes[1][1].set_title("img_use_circle")
axes[1][2].imshow(img, cmap=plt.cm.gray)
axes[1][2].set_title("approxPoly")
plt.show()