OpenCV基础_009_ 图像形状拟合和绘制

这片也有点长,加个目录

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()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

机器人迈克猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值