【计算机视觉OpenCV基础】实验二 基元检测

news/2024/7/21 5:26:25 标签: opencv, python, 图像处理

实验二 基元检测

计算机视觉OpenCV基础实验合辑(实验1234+扩展)
资源下载地址: https://download.csdn.net/download/weixin_53403301
合辑:(加在下载地址后面)
/87113581
讲义(包括理论、图例、PPT、实验、代码、手册):(加在下载地址后面)
/87113633

matplotlib中载入中文字体

python">plt.rcParams['font.sans-serif'] = ['SimHei'] # 载入字体

实验目的:
1、 熟练掌握OpenCV使用方法;
2、 编程实现基元检测算法,加深对基元检测技术的理解,初步掌握基元检测运用方法。
实验内容:
1、边缘检测
(1)边缘检测的原理
基于搜索:利用一阶导数的最大值获取边界

基于零穿越:利用二阶导数为0获取边界

(2)Sobel算子
基于搜索的方法获取边界

cv.sobel()

cv.convertScaleAbs()

cv.addweights()

(3)Laplacian算子
基于零穿越获取边界

(4)Canny算法
噪声去除:高斯滤波

计算图像梯度:sobel算子,计算梯度大小和方向

非极大值抑制:利用梯度方向像素来判断当前像素是否为边界点

滞后阈值:设置两个阈值,确定最终的边界

python"># -*- coding: utf-8 -*-
"""
Created on Wed Apr 21 14:44:28 2021
​
@author: ZHOU
"""import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 载入字体
# 1 读取图像
img = cv.imread('./image/horse.jpg',0)
# 2 计算Sobel卷积结果
x = cv.Sobel(img, cv.CV_16S, 1, 0)
y = cv.Sobel(img, cv.CV_16S, 0, 1)
# 3 将数据进行转换
Scale_absX = cv.convertScaleAbs(x)  # convert 转换  scale 缩放
Scale_absY = cv.convertScaleAbs(y)
# 4 结果合成
result = cv.addWeighted(Scale_absX, 0.5, Scale_absY, 0.5, 0)
# 5 图像显示
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(121),plt.imshow(img,cmap=plt.cm.gray),plt.title('原图')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(result,cmap = plt.cm.gray),plt.title('Sobel滤波后结果')
plt.xticks([]), plt.yticks([])
plt.show()
​
​
x = cv.Sobel(img, cv.CV_16S, 1, 0, ksize = -1) # 利用Scharr进行边缘检测。
y = cv.Sobel(img, cv.CV_16S, 0, 1, ksize = -1)
# 3 将数据进行转换
Scale_absX = cv.convertScaleAbs(x)  # convert 转换  scale 缩放
Scale_absY = cv.convertScaleAbs(y)
# 4 结果合成
result = cv.addWeighted(Scale_absX, 0.5, Scale_absY, 0.5, 0)
# 5 图像显示
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(121),plt.imshow(img,cmap=plt.cm.gray),plt.title('原图')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(result,cmap = plt.cm.gray),plt.title('Scharr滤波后结果')
plt.xticks([]), plt.yticks([])
plt.show()# 1 读取图像
img = cv.imread('./image/horse.jpg',0)
# 2 laplacian转换
result = cv.Laplacian(img,cv.CV_16S)
Scale_abs = cv.convertScaleAbs(result)
# 3 图像展示
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(121),plt.imshow(img,cmap=plt.cm.gray),plt.title('原图')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(Scale_abs,cmap = plt.cm.gray),plt.title('Laplacian检测后结果')
plt.xticks([]), plt.yticks([])
plt.show()# 1 图像读取
img = cv.imread('./image/horse.jpg',0)
# 2 Canny边缘检测
lowThreshold = 0
max_lowThreshold = 100
canny = cv.Canny(img, lowThreshold, max_lowThreshold) 
# 3 图像展示
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(121),plt.imshow(img,cmap=plt.cm.gray),plt.title('原图')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(canny,cmap = plt.cm.gray),plt.title('Canny检测后结果')
plt.xticks([]), plt.yticks([])
plt.show()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2、模板匹配
原理:在给定的图片中查找和模板最相似的区域

API:利用cv.matchTemplate()进行模板匹配,然后使用cv.minMaxLoc()搜索最匹配的位置。

python"># -*- coding: utf-8 -*-
"""
Created on Wed Apr 21 15:04:31 2021
​
@author: ZHOU
"""import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 载入字体
# 1 图像和模板读取
img = cv.imread('./image/wulin.jpeg')
template = cv.imread('./image/bai.jpeg')
h,w,l = template.shape
# 2 模板匹配
# 2.1 模板匹配
res = cv.matchTemplate(img, template, cv.TM_CCORR)
# 2.2 返回图像中最匹配的位置,确定左上角的坐标,并将匹配位置绘制在图像上
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res)
# 使用平方差时最小值为最佳匹配位置
# top_left = min_loc
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
cv.rectangle(img, top_left, bottom_right, (0,255,0), 2)
# 3 图像显示
plt.imshow(img[:,:,::-1])
plt.title('匹配结果'), plt.xticks([]), plt.yticks([])
plt.show()

在这里插入图片描述

3、霍夫变换
(1)霍夫线检测
原理:将要检测的内容转换到霍夫空间中,利用累加器统计最优解,将检测结果表示处理

API:cv2.HoughLines()

注意:该方法输入是的二值化图像,在进行检测前要将图像进行二值化处理

python"># -*- coding: utf-8 -*-
"""
Created on Wed Apr 21 15:06:51 2021
​
@author: ZHOU
"""import numpy as np
import random
import cv2 as cv
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 载入字体
# 1.加载图片,转为二值图
img = cv.imread('./image/rili.jpg')
​
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
edges = cv.Canny(gray, 50, 150)# 2.霍夫直线变换
lines = cv.HoughLines(edges, 0.8, np.pi / 180, 150)
# 3.将检测的线绘制在图像上(注意是极坐标噢)
for line in lines:
    rho, theta = line[0]
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a * rho
    y0 = b * rho
    x1 = int(x0 + 1000 * (-b))
    y1 = int(y0 + 1000 * (a))
    x2 = int(x0 - 1000 * (-b))
    y2 = int(y0 - 1000 * (a))
    cv.line(img, (x1, y1), (x2, y2), (0, 255, 0))
# 4. 图像显示
plt.figure(figsize=(10,8),dpi=100)
plt.imshow(img[:,:,::-1]),plt.title('霍夫变换线检测')
plt.xticks([]), plt.yticks([])
plt.show()

在这里插入图片描述

(2)霍夫圆检测
方法:霍夫梯度法

API:cv.HoughCircles()

python"># -*- coding: utf-8 -*-
"""
Created on Wed Apr 21 15:06:51 2021
​
@author: ZHOU
"""import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# 1 读取图像,并转换为灰度图
planets = cv.imread("./image/star.jpeg")
gay_img = cv.cvtColor(planets, cv.COLOR_BGRA2GRAY)
# 2 进行中值模糊,去噪点
img = cv.medianBlur(gay_img, 7)  
# 3 霍夫圆检测
circles = cv.HoughCircles(img, cv.HOUGH_GRADIENT, 1, 200, param1=100, param2=30, minRadius=0, maxRadius=100)
# 4 将检测结果绘制在图像上
for i in circles[0, :]:  # 遍历矩阵每一行的数据
    # 绘制圆形
    cv.circle(planets, (i[0], i[1]), i[2], (0, 255, 0), 2)
    # 绘制圆心
    cv.circle(planets, (i[0], i[1]), 2, (0, 0, 255), 3)
# 5 图像显示
plt.figure(figsize=(10,8),dpi=100)
plt.imshow(planets[:,:,::-1]),plt.title('霍夫变换圆检测')
plt.xticks([]), plt.yticks([])
plt.show()

在这里插入图片描述

4、角点检测
(1)Harris算法
思想:通过图像的局部的小窗口观察图像,角点的特征是窗口沿任意方向移动都会导致图像灰度的明显变化。

API: cv.cornerHarris()

(2)Shi-Tomasi算法
对Harris算法的改进,能够更好地检测角点

API: cv2.goodFeatureToTrack()

python"># -*- coding: utf-8 -*-
"""
Created on Wed Apr 21 15:24:03 2021
​
@author: ZHOU
"""import cv2 as cv
import numpy as np 
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 载入字体
# 1 读取图像,并转换成灰度图像
img = cv.imread('./image/chessboard.jpg')
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 2 角点检测
# 2.1 输入图像必须是 float32
gray = np.float32(gray)# 2.2 最后一个参数在 0.04 到 0.05 之间
dst = cv.cornerHarris(gray,2,3,0.04)
# 3 设置阈值,将角点绘制出来,阈值根据图像进行选择
img[dst>0.001*dst.max()] = [0,0,255]
# 4 图像显示
plt.figure(figsize=(10,8),dpi=100)
plt.imshow(img[:,:,::-1]),plt.title('Harris角点检测')
plt.xticks([]), plt.yticks([])
plt.show()# 1 读取图像
img = cv.imread('./image/tv.jpg') 
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
# 2 角点检测
corners = cv.goodFeaturesToTrack(gray,1000,0.01,10)  
# 3 绘制角点
for i in corners:
    x,y = i.ravel()
    cv.circle(img,(x,y),2,(0,0,255),-1)
# 4 图像展示
plt.figure(figsize=(10,8),dpi=100)
plt.imshow(img[:,:,::-1]),plt.title('shi-tomasi角点检测')
plt.xticks([]), plt.yticks([])
plt.show()

在这里插入图片描述
在这里插入图片描述

5、轮廓检测
(1)轮廓搜索:
cv2.findContours(img,mode,method)

mode:轮廓检索模式

• RETR_EXTERNAL :只检索最外面的轮廓;

• RETR_LIST:检索所有的轮廓,并将其保存到一条链表当中;

• RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;

• RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次;

method:轮廓逼近方法

• CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。

• CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。

(2)轮廓绘制
cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2)

(3)轮廓特征计算:面积、周长、边界矩形、外接圆、饱和度(轮廓面积与边界矩形面积之比)。
cv2.contourArea(cnt) #面积

cv2.arcLength(cnt,True) #周长,True表示闭合的

x,y,w,h = cv2.boundingRect(cnt) #获得边界矩形

img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2) #绘制边界矩形

area = cv2.contourArea(cnt) #轮廓面积

x, y, w, h = cv2.boundingRect(cnt) #获得轮廓的边界矩形

rect_area = w * h#边界矩形面积

extent = float(area) / rect_area#面积比

print (‘轮廓面积与边界矩形比’,extent)

(x,y),radius = cv2.minEnclosingCircle(cnt)#外接圆

(4)轮廓近似(多边形逼近)
epsilon = 0.15*cv2.arcLength(cnt,True) #以周长的0.15作为误差标准

approx = cv2.approxPolyDP(cnt,epsilon,True) #对轮廓cnt以误差标准epsilon进行近似

python"># -*- coding: utf-8 -*-
"""
Created on Wed Apr 21 15:24:03 2021
​
@author: ZHOU
"""import cv2
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 载入字体
# 1 读取图像,并转换成灰度图像
img = cv2.imread('./image1/contours.png')
plt.imshow(img[:,:,::-1])
plt.title('原图'), plt.xticks([]), plt.yticks([])
plt.show()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold (gray, 127, 255, cv2.THRESH_BINARY)
binary=thresh
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)# 绘制轮廓 传入图像 -1
draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2)
plt.imshow(res[:,:,::-1])
plt.title('绘制轮廓 -1'), plt.xticks([]), plt.yticks([])
plt.show()
# 绘制轮廓 传入图像 0
draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, 0, (0, 0, 255), 2)
plt.imshow(res[:,:,::-1])
plt.title('绘制轮廓 0'), plt.xticks([]), plt.yticks([])
plt.show()
# 计算面积
cnt = contours[0]
print('面积',cv2.contourArea(cnt))
print('周长',cv2.arcLength(cnt,True))# 边界矩形
cnt = contours[0]
x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)
plt.imshow(img[:,:,::-1])
plt.title('边界矩形'), plt.xticks([]), plt.yticks([])
plt.show()
area = cv2.contourArea(cnt)
rect_area = w*h
extent = float(area) / rect_area
print('轮廓面积与边界矩形之比',extent)
# 外接圆
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
img = cv2.circle(img, center, radius, (0,255,0), 2)
plt.imshow(img[:,:,::-1])
plt.title('外接圆'), plt.xticks([]), plt.yticks([])
plt.show()# 1 读取图像2,并转换成灰度图像
img = cv2.imread('./image1/contours2.png')
plt.imshow(img[:,:,::-1])
plt.title('原图'), plt.xticks([]), plt.yticks([])
plt.show()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold (gray, 127, 255, cv2.THRESH_BINARY)
binary=thresh
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
​
cnt = contours[0]
draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2)
plt.imshow(res[:,:,::-1])
plt.title('绘制轮廓'), plt.xticks([]), plt.yticks([])
plt.show()
epsilon = 0.15*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)
print('0.15倍周长',epsilon)
print('对轮廓cnt以误差标准epsilon进行近似',approx)
draw_img = img.copy()
res = cv2.drawContours(draw_img, [approx], -1, (0, 0, 255), 2)
plt.imshow(res[:,:,::-1])
plt.title('轮廓近似'), plt.xticks([]), plt.yticks([])
plt.show()# 边界矩形
x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)
plt.imshow(img[:,:,::-1])
plt.title('边界矩形'), plt.xticks([]), plt.yticks([])
plt.show()
area = cv2.contourArea(cnt)
rect_area = w*h
extent = float(area) / rect_area
print('轮廓面积与边界矩形之比',extent)
# 外接圆
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
img = cv2.circle(img, center, radius, (0,255,0), 2)
plt.imshow(img[:,:,::-1])
plt.title('外接圆'), plt.xticks([]), plt.yticks([])
plt.show()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
面积 8500.5
周长 437.9482651948929

在这里插入图片描述
轮廓面积与边界矩形之比 0.5154317244724715
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

0.15倍周长 189.8943818628788
对轮廓cnt以误差标准epsilon进行近似 [[[291 30]]

[[ 40 263]]

[[335 257]]]
在这里插入图片描述
在这里插入图片描述
轮廓面积与边界矩形之比 0.7800798598378357
在这里插入图片描述

6、形态学图像处理
• 腐蚀和膨胀:

腐蚀:求局部最大值,缩小或细化,能将小于结构体的细节从图像中滤除。

膨胀:求局部最小值,增长或粗化

• 开闭运算:

开:先腐蚀后膨胀。平滑物体轮廓、断开较窄的连接、消除细的突出物。

闭:先膨胀后腐蚀。平滑轮廓、弥合较窄的间断和细长的沟壑,消除小的孔洞,填补轮廓线中的断裂。

• 礼帽和黑帽:

礼帽:原图像与开运算之差。

开运算放大了裂缝或者局部低亮度的区域,所以,从原图中减去开运算后的图,得到的结果突出了比原图轮廓周围的区域更明亮的区域,

这个操作与选择的核的大小有关。TopHat运算一般用来分离比邻近点亮一些的斑块,可以使用这个运算提取背景。

黑帽:闭运算与原图像之差

黑帽运算的结果突出了比原图轮廓周围区域更暗的区域,所以黑帽运算用来分离比邻近点暗一些的斑块。

python"># -*- coding: utf-8 -*-
"""
Created on Wed Apr 21 16:48:59 2021
​
@author: ZHOU
"""import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 载入字体
# 1 读取图像
img = cv.imread("./image/letter.png")
# 2 创建核结构
kernel = np.ones((5, 5), np.uint8)# 3 图像腐蚀和膨胀
erosion = cv.erode(img, kernel) # 腐蚀
dilate = cv.dilate(img,kernel) # 膨胀# 4 图像展示
fig,axes=plt.subplots(nrows=1,ncols=3,figsize=(10,8),dpi=100)
axes[0].imshow(img)
axes[0].set_title("原图")
axes[1].imshow(erosion)
axes[1].set_title("腐蚀后结果")
axes[2].imshow(dilate)
axes[2].set_title("膨胀后结果")
plt.show()
​
img1 = cv.imread("./image/letteropen.png")
img2 = cv.imread("./image/letterclose.png")
# 2 创建核结构
kernel = np.ones((10, 10), np.uint8)
# 3 图像的开闭运算
cvOpen = cv.morphologyEx(img1,cv.MORPH_OPEN,kernel) # 开运算
cvClose = cv.morphologyEx(img2,cv.MORPH_CLOSE,kernel)# 闭运算
# 4 图像展示
fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(10,8))
axes[0,0].imshow(img1)
axes[0,0].set_title("原图")
axes[0,1].imshow(cvOpen)
axes[0,1].set_title("开运算结果")
axes[1,0].imshow(img2)
axes[1,0].set_title("原图")
axes[1,1].imshow(cvClose)
axes[1,1].set_title("闭运算结果")
plt.show()# 2 创建核结构
kernel = np.ones((10, 10), np.uint8)
# 3 图像的礼帽和黑帽运算
cvOpen = cv.morphologyEx(img1,cv.MORPH_TOPHAT,kernel) # 礼帽运算
cvClose = cv.morphologyEx(img2,cv.MORPH_BLACKHAT,kernel)# 黑帽运算
# 4 图像显示
fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(10,8))
axes[0,0].imshow(img1)
axes[0,0].set_title("原图")
axes[0,1].imshow(cvOpen)
axes[0,1].set_title("礼帽运算结果")
axes[1,0].imshow(img2)
axes[1,0].set_title("原图")
axes[1,1].imshow(cvClose)
axes[1,1].set_title("黑帽运算结果")
plt.show()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实验收获:
编程实现基元检测算法,加深对基元检测技术的理解,初步掌握基元检测运用方法。 学会了利用OpenCV进行边缘检测、角点检测、霍夫变换、形态学处理、基元检测以及模板匹配。



http://www.niftyadmin.cn/n/10666.html

相关文章

使用OpenCV计算两幅图像的协方差

要计算协方差首先要知道协方差的数学原理。 定义 Cov(X,Y) E{ [X-E(X)][Y-E(Y)] }为随机量X与Y的协方差。 其中E(X)为随机变量X的期望(均值),E(Y)为随机变量Y的期望(均值)。 我们通常用下面的这个公式计算协方差。 Cov(X,Y)E(XY)-E(X)E(Y) 另外,大家…

xlsx库实现纯前端导入导出Excel

前言 最近做了前端导入、导出 Excel 的需求,用到了js-xlsx这个库,该库文档提供的用例很少,并不是很友好。本文总结一下我是如何实现需求的。 需求 提供一个 Excel 文件,将里面的内容转成 JSON 导入数据提供一个 JSON 文件&…

Java继承——抽象类与接口的比较以及内部类、匿名类、异常类......

文章目录壹、抽象类与接口的比较贰、内部类叁、匿名类(匿名内部类)肆、异常类(Exception)壹、抽象类与接口的比较 1、抽象类与接口都可以有抽象方法; 2、接口中只可以有常量,不可以有变量;而抽…

智慧气象解决方案-最新全套文件

智慧气象解决方案-最新全套文件一、建设背景二、建设架构传统气象所面临的挑战:1、气象数据大幅快速增长,导致计算能力不足2、人工智能应用不足,短临预报精度较低3、气象数据分散,数据融合困难4、气象服务方式单一,体验…

UE5笔记【七】Nanite虚化几何-虚化几何简介;创建Nanite对象。

简书上有一篇文章:《【UE5】Nanite解析》 Epic外放的两大特性Nanite跟Lumen,构成了UE版本升级的基石,关于这两大技术,已经有了众多的分享,不过这些分享在结构和内容上难以构成整个方案的全貌,因此尝试先通…

iOS键盘通知弹框使用小结

项目开发中文本框输入的时候经常会用到键盘弹框遮挡的问题。解决办法就是根据底部键盘弹出的高度动态的改变对应view的位置。这里以多行文本框输入为例,效果图如下。 //第一步,注册监听键盘通知 [[NSNotificationCenter defaultCenter] addObserver:self…

使用python画柱状图(matplotlib.pyplot)-- 你想要的设置这张图基本都包括

本人写论文时画的图,总结一下方法: 安心看下去,你应该就可以画出一个好看的柱状图,基本上需要的设置都有哦!!! 目录 1 首先引入画图所需要的包Matplotlib 2 Matplotlib Pyplot 3 画柱状图 …

LQ0221 逆波兰表达式【程序填空】

题目来源:蓝桥杯2013初赛 C A组F题 题目描述 本题为代码补全填空题,请将题目中给出的源代码补全,并复制到右侧代码框中,选择对应的编译语言(C/Java)后进行提交。若题目中给出的源代码语言不唯一&#xff0…