OPENCV视频学习笔记
一、读取图片
新建好我们的工程文件,在img文件下存放我们的图片,然后在其平级目录下进行程序编写,首先需要掌握读取一张图片的api
import cv2 as cv
src=cv.imread("img/JOJO.jpg")
#print(src)
cv.imshow("dawm",src)
#直接显示会一闪而过,使用KEY可以让其长时间在一个窗口
key = cv.waitKey() # 等待用户输入按键
print(key)
效果如下:
我们可以看到图片在弹窗内出来,按下键盘任意键可以退出
二、操作像素
我们可以利用numpy工具建立一个矩阵,利用np.zeros这样的函数创建一个相等于图像大小的矩阵
import numpy as np
dst = np.zeros((270,480,3),np.uint8)
dst.shape
#在图像中间画一条红色的线
for i in range(480):
dst[135,i] = (255,0,0)
plt.imshow(dst)
效果如下:
我们可以看到图片中间多了一条先
三、图像剪切
接着我们上面的图片,我们根据矩阵,可以截取出矩阵的一部分,这样就很简单了
src = cv.imread("img/JOJO.jpg")
dst = src[0:100,0:50]
plt.imshow(dst)
效果如下:
四、在jupyter下显示图片并进行镜像处理
因为jupyter里面用的是python本身的画图,所以需要替换成RGB原色
# 封装显示函数
def WangX_show(img):
# 将图像转成RGB格式
img = cv.cvtColor(img,cv.COLOR_BGR2RGB)
# 调用plt显示
plt.imshow(img)
而需要显示镜像,就需要建立一个高两倍的画布,然后上半从上到下,下面再从下到上填充
src = cv.imread("img/JOJO.jpg")
src.shape
#1. 创建一个原图两倍高度的矩阵
dst = np.zeros((270*2,480,3),np.uint8)
WangX_show(dst)
helight,width = src.shape[0:2]
print(helight,width)
# 2.向矩阵填充数据
for row in range(helight):
for col in range(width):
#先填充上半
dst[row,col] = src[row,col]
#填充下半
dst[helight*2-1-row,col] = src[row,col]
#显示结果
plt.figure(figsize=(10,10))
WangX_show(dst)
效果如下:
五、图片缩放
图片的缩放,我们常见的有两种类型:1.等比例缩放,2. 任意比例缩放
如果需要按照比例缩放,我们就需要通过shape得到图片的基本信息
imgInfo = img.shape
imgInfo[0] : 表示高度
imgInfo[1] : 表示宽度
imgInfo[2] : 表示每个像素点由几个颜色值构成
常见的图像缩放的算法有:
1.最近领域插值 2.双线性插值 3.像素关系重采样 4.立方插值
默认使用双线性插值,并利用opencv给出的resize方法进行缩放
import cv2 as cv
# 读取一张图片
img = cv.imread("img/JOJO.jpg", cv.IMREAD_COLOR)
# 获取图片信息
imgInfo = img.shape
print(imgInfo)
# 获取图片的高度
height = imgInfo[0]
# 获取图片的宽度
width = imgInfo[1]
# 获取图片的颜色模式,表示每个像素点由3个值组成
mode = imgInfo[2]
# 定义缩放比例
newHeight = int(height*0.5)
newWidth = int(width*0.5)
# 使用api缩放
newImg = cv.resize(img, (newWidth, newHeight))
# 将图片展示出来
cv.imshow("result",newImg)
cv.waitKey(0)
cv.destroyAllWindows()
效果如下:
六、图片操作原理
在前面我们描述过一张图片,如果相对这个图片描述其实就是利用矩阵进行描述,当然操作也是利用矩阵进行操作。
我们将一个矩阵的列和行看成坐标系中的x和y,我们就可以轻易按照前面所学的内容来操作了
import cv2 as cv
import numpy as np
img = cv.imread("img/JOJO.jpg", cv.IMREAD_COLOR)
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
# 创建一个和原图同样大小的矩阵
dstImg = np.zeros((height,width,3),np.uint8)
for row in range(height):
for col in range(width):
# 补成齐次坐标
sourceMatrix = np.array([col,row,1])
matrixB = np.array([[1,0,50],
[0,1,100]])
# 矩阵相乘
dstMatrix = matrixB.dot(sourceMatrix.T)
# 从原图中获取数据
dstCol = int(dstMatrix[0])
dstRow = int(dstMatrix[1])
# 防止角标越界
if dstCol < width and dstRow < height:
dstImg[dstRow,dstCol] = img[row,col]
# 显示图片出来
cv.imshow("dstImg",dstImg)
cv.waitKey(0)
效果同上图是一样的
七、图片移位
我们之前采样计算操作图片,实际上opencv也给我们提供了响应的计算操作,我们需要的就是给出变换矩阵,而函数也很简单
(原始图像,变换矩阵,(高度宽度))
import cv2 as cv
import numpy as np
img = cv.imread("img/JOJO.jpg",cv.IMREAD_COLOR)
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
# 定义位移矩阵
matrixShift = np.float32([
[1,0,50],
[0,1,100]
])
# 调用api
dstImg = cv.warpAffine(img,matrixShift,(width,height))
cv.imshow("dst",dstImg)
cv.waitKey(0)
效果如下:
八、图片旋转
图片旋转默认的位左上角为旋转中心
import cv2 as cv
img = cv.imread("img/JOJO.jpg", cv.IMREAD_COLOR)
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
# 定义仿射矩阵: 参数1:中心点, 参数2:旋转角度,参数3:缩放系数
matrixAffine = cv.getRotationMatrix2D((width * 0.5, height * 0.5), 45, 0.5)
# 进行仿射变换
dstImg = cv.warpAffine(img, matrixAffine, (width, height))
cv.imshow("dstImg",dstImg)
cv.waitKey(0)
效果如下:
九、图像融合
按照一定的比例将两张图片融合在仪器形成图三,这也需要opencv中的一个库cv.addWeighted(图像1,权重1,图像2,权重2,叠加之后的像素偏移值),两张图片叠加后高度应该相同。
我们首先需要明白两张图片的大小,然后按照前面所说的,按照任意比例放缩,将两张图片变成相同大小(高度要相同),这里我们将monster放大成JOJO的大小,然后进行融合显示
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
# 显示1大小
img_1 = cv.imread("img/JOJO.jpg",cv.IMREAD_COLOR)
imgInfo_JOJO = img_1.shape
print(imgInfo_JOJO)
#显示2大小
img_2 = cv.imread("img/monster.jpg",cv.IMREAD_COLOR)
imgInfo_MONSTER = img_2.shape
print(imgInfo_MONSTER)
height_JOJO = imgInfo_JOJO[0]
width_JOJO = imgInfo_JOJO[1]
mode_JOJO = imgInfo_JOJO[2]
height_M = imgInfo_MONSTER[0]
width_M = imgInfo_MONSTER[1]
mode_M= imgInfo_MONSTER[2]
newHeight_M = int(height_M+2)
newWidth_M = int(width_M-2+180)
newImg = cv.resize(img_2, (newWidth_M, newHeight_M))
newImg_shape_Monster=newImg.shape
# 将图片展示出来
#cv.imshow("result",newImg)
print(newImg_shape_Monster)
RongHe = cv.addWeighted(img_1,0.5,newImg,0.5,0)
cv.imshow("result",RongHe)
cv.waitKey(0)
#cv.destroyAllWindows()
效果如下:
十、灰度处理
一张彩色图片通常是由BGR三个通道叠加而成,为了便于图像特征识别,我们通常会将一张彩色图片转成灰度图片来进行分析,当我们转成灰色图片之后,图片中边缘,轮廓特征仍然是能够清晰看到的,况且在这种情况下我们仅需要对单一通道进行分析,会简化很多操作
import cv2 as cv
# 方式一 : 直接以灰度图像的形式读取
# img = cv.imread("img/itheima.jpg", cv.IMREAD_GRAYSCALE)
# cv.imshow("dstImg",img)
# cv.waitKey(0)
# 方式二: 以彩图的方式读取
img = cv.imread("img/JOJO.jpg",cv.IMREAD_COLOR)
# 将原图的所有颜色转成灰色
dstImg = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
cv.imshow("dstImg",dstImg)
cv.waitKey(0)
效果如下:
十一、颜色反转
例如在一张灰度图片中,某个像素点的灰度值为100, 然后我们进行颜色反转之后,灰度值变为255-100 = 155
import cv2 as cv
import numpy as np
# 将图片数据读取进来
img = cv.imread("img/JOJO.jpg",cv.IMREAD_GRAYSCALE)
cv.imshow("img",img)
# 获取原图信息
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
# 创建一个和原图同样大小的矩阵
dstImg = np.zeros((height,width,1),np.uint8)
for row in range(height):
for col in range(width):
# 获取原图中的灰度值
gray = img[row,col]
# 反转
newColor = 255 - gray
# 填充
dstImg[row,col]=newColor
cv.imshow("dstimg",dstImg)
cv.waitKey(0)
效果如下:
如果换成彩图,效果其实也是一样的,相当于RGB三个灰度图叠加而来,让每个通道的颜色进行反转即可
import cv2 as cv
import numpy as np
# 将图片数据读取进来
img = cv.imread("img/JOJO.jpg",cv.IMREAD_COLOR)
cv.imshow("img",img)
# 获取原图信息
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
# 创建一个和原图同样大小的矩阵
dstImg = np.zeros((height,width,3),np.uint8)
for row in range(height):
for col in range(width):
# 获取原图中的灰度值
(b,g,r) = img[row,col]
# 反转
new_b = 255-b
new_g = 255-g
new_r = 255-r
# 填充
dstImg[row,col]=(new_b,new_g,new_r)
cv.imshow("dstimg",dstImg)
cv.waitKey(0)
效果如下:
十二、马赛克效果
马赛克指现行广为使用的一种图像(视频)处理手段,此手段将影像特定区域的色阶细节劣化并造成色块打乱的效果,因为这种模糊看上去有一个个的小格子组成,便形象的称这种画面为马赛克。其目的通常是使之无法辨认。简单来说,假设我们把要打马赛克的区域认为是一个4X4的区域,我们把这块区域的内容和开始的点数相同,从而盖掉原来的内容,颜色也会和之前相近而不模糊,这个所设置的区域,就是每个码的大小
例如我们要给DIO的脸部打码
import cv2 as cv
import numpy as np
# 将图片数据读取进来
img = cv.imread("img/JOJO.jpg",cv.IMREAD_COLOR)
cv.imshow("img",img)
# 获取原图信息
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
#遍历区域
for row in range(10,200): #行-高
for col in range(140,380): #列 宽
# 每10×10的区域将像素点颜色改成一致
if row%10==0 and col%10==0:
# 获取当前颜色值
(b,g,r) = img[row,col]
# 将10×10区域内的颜色值改成一致
for i in range(10):
for j in range(10):
img[row+i,col+j]= (b,g,r)
# 显示效果图
cv.imshow('dstimg',img)
cv.waitKey(0)
效果如下:
十三、图形绘制
在这之前,我们学过的所有操作,其实都是在原图的基础上进行修改! 现在假设我们想在原图上绘制一些标记或者轮廓,那么我们就需要来学习一下opencv给我们提供的相应API,在这些API中,常见的有绘制直线,绘制圆,绘制矩形
import cv2 as cv
import numpy as np
import random
# 创建一个空白的矩阵
dstImg = np.zeros((400,600,3),np.uint8)
# 绘制线段 参数2:起始点 参数3:结束点 参数4:颜色 参数5:线条宽度
cv.line(dstImg,(50,10),(400,10),(255,255,0),10)
# 扛锯齿
cv.line(dstImg,(50,50),(400,50),(255,0,0),10,cv.LINE_AA)
# 绘制一个三角形
cv.line(dstImg,(50,350),(150,200),(255,0,0),10)
cv.line(dstImg,(150,200),(300,350),(0,255,0),10)
cv.line(dstImg,(300,350),(50,350),(0,0,255),10)
# 绘制一个矩形 参数2: 左上角 参数3:右下角 参数4:颜色 参数5:线条宽度,若为负数,则填充整个矩形
cv.rectangle(dstImg,(250,90),(470,180),(0,255,0),-1)
# 绘制圆形 参数2:圆心 参数3:半径 参数4:颜色 参数5:线条宽度
cv.circle(dstImg,(450,280),90,(0,0,255),5)
# 显示图片
cv.imshow("dstimg",dstImg)
cv.waitKey(0)
效果如下:
十四、图片美化
1. 亮度改变
每个通道的颜色值增大或减小
import cv2 as cv
def checkColor(value):
value = value if value < 256 else 255
value = value if value > 0 else 0
return value
# 将图片数据读取进来
img = cv.imread("img/monster.jpg",cv.IMREAD_COLOR)
cv.imshow('img',img)
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
# 定义颜色改变的值
count=35
# 遍历每一个像素点
for row in range(height):
for col in range(width):
# 获取每个像素点的颜色值
(b,g,r) = img[row,col]
# 增大当前颜色值
newb = b + count
newg = g + count
newr = r + count
# 校验每个像素值不能越界
newb = checkColor(newb)
newg = checkColor(newg)
newr = checkColor(newr)
img[row,col] = (newb,newg,newr)
# 显示改变之后的图像
cv.imshow('newimg',img)
cv.waitKey(0)
效果如下
2.直方图均衡化
直方图均衡化是将原图象的直方图通过变换函数修正为均匀的直方图,然后按均衡直方图修正原图象。图象均衡化处理后,图象的直方图是平直的,即各灰度级具有相同的出现频数,那么由于灰度级具有均匀的概率分布,图象看起来就更清晰了
效果就是让整个图片看起来更平滑,对于彩图,也和之前一样计算RGB三种的直方然后进行叠加
import cv2 as cv
img = cv.imread("img/monster.jpg",cv.IMREAD_COLOR)
b,g,r = cv.split(img)
b_dst = cv.equalizeHist(b)
g_dst = cv.equalizeHist(g)
r_dst = cv.equalizeHist(r)
ret = cv.merge([b_dst,g_dst,r_dst])
# 显示均衡化之后的图片
cv.imshow("src",img)
cv.imshow("equalize_img",ret)
cv.waitKey(0)
cv.destroyAllWindows()
效果:
十五、颜色过滤
在一张图片中,如果某个物体的颜色为纯色,那么我们就可以使用颜色过滤inRange的方式很方便的来提取这个物体.其实也就是智能车里常用的轨道循迹,只识别到黑色的道路边界和白色的道路,但是传统BGR颜色空间,如果想要表达一定范围的绿色会很麻烦,所以可以转成HSV颜色空间
什么是HSV颜色模型?
HSV(Hue, Saturation, Value)是根据颜色的直观特性由A. R. Smith在1978年创建的一种颜色空间, 也称六角锥体模型(Hexcone Model)。这个模型中颜色的参数分别是:色调(H),饱和度(S),明度(V)
色调H
用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°,品红为300°;
饱和度S
饱和度S表示颜色接近光谱色的程度。一种颜色,可以看成是某种光谱色与白色混合的结果。其中光谱色所占的比例愈大,颜色接近光谱色的程度就愈高,颜色的饱和度也就愈高。饱和度高,颜色则深而艳。光谱色的白光成分为0,饱和度达到最高。通常取值范围为0%~100%,值越大,颜色越饱和。
明度V
明度表示颜色明亮的程度,对于光源色,明度值与发光体的光亮度有关;对于物体色,此值和物体的透射比或反射比有关。通常取值范围为0%(黑)到100%(白)。
当 S=1 V=1时,H所代表的任何颜色被称为纯色
当 S=0 饱和度为0时,颜色最浅,最浅被描述为灰色,所谓的灰色也有自己的亮度,黑色就是黑一点的灰,白色就是亮一点的灰,这就由V决定,与H无关了
当 V=0时,就是黑色了
在OPENCV里面,H S V的颜色范围是[0,180],[0,255],[0,255]
我们就可以得到:
import cv2 as cv
# 读取图片
rgb_img = cv.imread("img/JOJO.jpg", cv.IMREAD_COLOR)
cv.imshow("rgb_img",rgb_img)
# 将BGR颜色空间转成HSV空间
hsv_img = cv.cvtColor(rgb_img, cv.COLOR_BGR2HSV)
# 定义范围颜色范围
lower_color = (30,120,130)
upper_color = (60,255,255)
# 查找颜色
mask_img = cv.inRange(hsv_img, lower_color, upper_color)
# 在颜色范围内的内容是白色, 其它为黑色
cv.imshow("mask_img",mask_img)
cv.waitKey(0)
cv.destroyAllWindows()
原始的颜色需要我们以别的方式得到,这个我还在调试,效果图之后给出
十六、颜色二值化
图像二值化( Image Binarization)就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的黑白效果的过程
在数字图像处理中,二值图像占有非常重要的地位,图像的二值化使图像中数据量大为减少,从而能凸显出目标的轮廓。
所使用的阈值,结果图片 = cv.threshold(img,阈值,最大值,类型)
THRESH_BINARY | 高于阈值改为255,低于阈值改为0 |
THRESH_BINARY_INV | 高于阈值改为0,低于阈值改为255 |
THRESH_TRUNC | 截断,高于阈值改为阈值,最大值失效 |
THRESH_TOZERO | 高于阈值不改变,低于阈值改为0 |
THRESH_TOZERO_INV | 高于阈值该为0,低于阈值不改变 |
import cv2 as cv
# 读取图像
img = cv.imread("img/JOJO.jpg",cv.IMREAD_GRAYSCALE)
# 显示图片
cv.imshow("gray",img)
# 获取图片信息
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
# 定义阈值
thresh = 60
for row in range(height):
for col in range(width):
# 获取当前灰度值
grayValue = img[row,col]
if grayValue>thresh:
img[row,col]=255
else:
img[row,col]=0
# 直接调用api处理 返回值1:使用的阈值, 返回值2:处理之后的图像
# ret,thresh_img = cv.threshold(img, thresh, 255, cv.THRESH_BINARY)
# 显示修改之后的图片
cv.imshow("thresh",img);
cv.waitKey(0)
cv.destroyAllWindows()
效果如下:
自适应阈值
我们使用一个全局值作为阈值。但是在所有情况下这可能都不太好,例如,如果图像在不同区域具有不同的照明条件。在这种情况下,自适应阈值阈值可以帮助。这里,算法基于其周围的小区域确定像素的阈值。因此,我们为同一图像的不同区域获得不同的阈值,这为具有不同照明的图像提供了更好的结果。
除上述参数外,方法cv.adaptiveThreshold还有三个输入参数:
- cv.ADAPTIVE_THRESH_MEAN_C:该阈值是该附近区域减去恒定的平均Ç。
- cv.ADAPTIVE_THRESH_GAUSSIAN_C:阈值是邻域值减去常数C的高斯加权和。
该BLOCKSIZE确定附近区域的大小和Ç是从平均值或附近的像素的加权和中减去一个常数
import cv2 as cv
# 读取图像
img = cv.imread("img/JOJO.jpg",cv.IMREAD_GRAYSCALE)
# 显示图片
cv.imshow("gray",img)
# 获取图片信息
imgInfo = img.shape
# 直接调用api处理 参数1:图像数据 参数2:最大值 参数3:计算阈值的方法, 参数4:阈值类型 参数5:处理块大小 参数6:算法需要的常量C
thresh_img = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,11,5)
# 显示修改之后的图片
cv.imshow("thresh",thresh_img);
cv.waitKey(0)
cv.destroyAllWindows()
效果如下:
大津算法
用于进行图像分割中阈值选取的最佳算法
import cv2 as cv
# 读取图像
img = cv.imread("img/JOJO.jpg",cv.IMREAD_GRAYSCALE)
cv.imshow("src",img)
ret,thresh_img = cv.threshold(img, 225, 255, cv.THRESH_BINARY_INV)
cv.imshow("normal", thresh_img);
gaussian_img = cv.GaussianBlur(img,(5,5),0)
cv.imshow("g",gaussian_img)
ret,thresh_img = cv.threshold(gaussian_img, 0, 255, cv.THRESH_BINARY|cv.THRESH_OTSU)
cv.imshow("otsu", thresh_img);
print("阈值:",ret)
cv.waitKey(0)
cv.destroyAllWindows()
十七、读取摄像头
import cv2 as cv
capture = cv.VideoCapture(0) #选择摄像头端口,电脑默认第一个为0
print(capture.isOpened)
ok,fram = capture.read()
while ok:
cv.imshow("frame",fram)
cv.waitKey(50)
ok,fram = capture.read()
效果如下:
图像中获取的图片数据为fram,所以和上面的处理相同,我们将read的值换成fram就可以进行我们之前的操作,当然帧率会有所下降,毕竟我们是在一边读取一边进行操作
十八、图像卷积
图像滤波是尽量保留图像细节特征的条件下对目标图像的噪声进行抑制,是图像预处理中不可缺少的操作,其处理效果的好坏将直接影响到后续图像处理和分析的有效性和可靠性。
线性滤波是图像处理最基本的方法,它允许我们对图像进行处理,产生很多不同的效果。首先,我们需要一个二维的滤波器矩阵(卷积核)和一个要处理的二维图像。然后,对于图像的每一个像素点,计算它的邻域像素和滤波器矩阵的对应元素的乘积,然后加起来,作为该像素位置的值。这样就完成了滤波过程。
十九、霍夫变换
用来检测直线的
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
# 1. 将图片以灰度的方式读取进来
img = cv.imread("assets/weiqi.jpg", cv.IMREAD_COLOR)
cv.imshow("src",img)
gray_img = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
# cv.imshow("gray",gray_img)
#
flag,thresh_img = cv.threshold(gray_img,100,255,cv.THRESH_BINARY_INV)
cv.imshow("thresh_img",thresh_img)
# 3. 霍夫变换
# 线段以像素为单位的距离精度,double类型的,推荐用1.0
rho = 1
# 线段以弧度为单位的角度精度,推荐用numpy.pi/180
theta = np.pi/180
# 累加平面的阈值参数,int类型,超过设定阈值才被检测出线段,值越大,基本上意味着检出的线段越长,检出的线段个数越少。
threshold=10
# 线段以像素为单位的最小长度
min_line_length=25
# 同一方向上两条线段判定为一条线段的最大允许间隔(断裂),超过了设定值,则把两条线段当成一条线段,值越大,允许线段上的断裂越大,越有可能检出潜在的直线段
max_line_gap = 3
lines = cv.HoughLinesP(thresh_img,rho,theta,threshold,minLineLength=min_line_length,maxLineGap=max_line_gap)
dst_img = img.copy()
for line in lines:
x1,y1,x2,y2 = line[0]
cv.line(dst_img,(x1,y1),(x2,y2),(0,0,255),2)
cv.imshow("dst img",dst_img)
cv.waitKey(0)
cv.destroyAllWindows()
效果如下:
霍夫圆
圆心,r是半径。圆环需要三个参数来设定,所以圆环的累加器必须是三维的。Opencv采用霍夫梯度法这个巧妙的方法来获取边界的梯度信息从而提升计算的效率
import cv2 as cv
import numpy as np
# 读取图像
img = cv.imread("img/weiqi.jpg", cv.IMREAD_COLOR)
# 将图片转成灰度图片
gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 霍夫圆形检测
def hough_circle(gray_img):
method = cv.HOUGH_GRADIENT
dp = 1
minDist = 20
circles = cv.HoughCircles(
gray_img, method, dp, minDist=minDist,
param1=70, param2=30, minRadius=0, maxRadius=20
)
# 检查是否检测到圆
if circles is not None:
circles = np.uint16(np.around(circles)) # 确保转换为整数并四舍五入
for circle in circles[0, :]:
x, y, r = circle
print(f"圆心坐标: ({x}, {y}), 半径: {r}") # 打印圆的坐标和半径
# 绘制圆心
cv.circle(img, (x, y), 2, (0, 255, 0), 1)
# 绘制圆形
cv.circle(img, (x, y), r, (0, 0, 255), 2)
cv.imshow("result", img)
# 调用函数,寻找霍夫圆
hough_circle(gray_img)
cv.waitKey(0)
cv.destroyAllWindows()
- method: 定义霍夫圆检测的方法,使用
cv.HOUGH_GRADIENT
,这是目前唯一实现的检测方法。 - dp: 累加器分辨率与图像分辨率的反比。例如,
dp = 1
表示累加器具有与输入图像相同的分辨率。如果dp = 2
,则累加器的宽度和高度都是输入图像的一半。 - minDist: 检测到的圆的圆心之间的最小距离。如果这个值太小,可能会导致检测到多个相邻的圆。如果值太大,可能会漏掉一些圆
- cv.HoughCircles: 执行霍夫圆检测。
- gray_img: 输入的灰度图像。
- method: 使用
cv.HOUGH_GRADIENT
方法检测圆。 - dp: 累加器分辨率与图像分辨率的反比。
- minDist: 检测到的圆心之间的最小距离。
- param1: 用于 Canny 边缘检测算法的高阈值,边缘检测用于检测可能存在圆的边缘。
- param2: 用于圆检测的累加器阈值,阈值越小,检测到的圆越多(但可能有更多误检)。
- if circles is not None: 检查是否有检测到圆。如果
circles
为None
,表示没有检测到圆。 - circles = np.uint16(np.around(circles)): 将
circles
中的浮点数转换为整数,并四舍五入,确保用于绘制的坐标和半径是整数。
检测圈出部分
- for circle in circles[0, :]: 遍历每一个检测到的圆,
circle
包含圆心坐标(x, y)
和半径r
。- cv.circle(img, (x, y), 2, (0, 255, 0), 1): 绘制圆心,颜色为绿色
(0, 255, 0)
,半径为 2 像素,线条宽度为 1。 - cv.circle(img, (x, y), r, (0, 0, 255), 2): 绘制圆形,颜色为红色
(0, 0, 255)
,线条宽度为 2。
- cv.circle(img, (x, y), 2, (0, 255, 0), 1): 绘制圆心,颜色为绿色
效果如下:
在字符串前添加 f
或 F
,并在字符串中使用花括号 {}
包围你想要嵌入的 Python 表达式。Python 会计算这些表达式的值,并将它们替换为对应的字符串表示形式。
--------- to be continue