O3.2 opencv高阶
直方图均衡化
直方图均衡化:是一种图像增强技术,它可以通过增加图像的对比度和亮度来改善图像的质量。 实现方法:通过将图像的像素值分布均匀化来实现这一目标。
在Python OpenCV中,可以使用cv2.equalizeHist()函数来实现直方图均衡化。
逻辑
1. 代码注释部分
python
#直方图均衡化:直方图均衡化是一种图像增强技术,它可以通过增加图像的对比度和亮度来改善图像的质量。
# 直方图均衡化通过将图像的像素值分布均匀化来实现这一目标。
# 在Python OpenCV中,可以使用cv2.equalizeHist()函数来实现直方图均衡化。
# 该函数将输入图像转换为灰度图像,并将其像素值分布均匀化,从而增强图像的对比度和亮度。
这部分注释解释了直方图均衡化的基本概念,即它是种图像增强技术,通过均匀化像素值分布来提升图像的对比度和亮度。同时说明在 OpenCV 库中可以使用cv2.equalizeHist()
函数来实现该功能,并且该函数会将输入图像先转换为灰度图再进行处理。
2. 读取图像并展示原始图像直方图
python
woman = cv2.imread('woman.png',cv2.IMREAD_GRAYSCALE)
plt.hist(woman.ravel(), bins=256)
plt.show()
cv2.imread('woman.png',cv2.IMREAD_GRAYSCALE)
:使用 OpenCV 的imread
函数读取名为 “woman.png” 的图像,并指定以灰度模式读取。这意味着图像将被处理为单通道图像,每个像素值表示其灰度强度,范围通常是 0(黑色)到 255(白色)。plt.hist(woman.ravel(), bins=256)
:woman.ravel()
将二维的图像数组展平为一维数组,这样plt.hist
函数就可以统计每个灰度值(共 256 个可能值,对应bins=256
)在图像中出现的频率,从而绘制出原始图像的直方图。plt.show()
:显示绘制的直方图。这一步让用户可以直观看到原始图像像素值的分布情况。
3. 进行直方图均衡化并展示处理后图像直方图
python
phone_equalize = cv2.equalizeHist(woman)
plt.hist(phone_equalize.ravel(), bins=256)
plt.show()
phone_equalize = cv2.equalizeHist(woman)
:调用cv2.equalizeHist
函数对之前读取的灰度图像woman
进行直方图均衡化处理,处理后的图像保存在phone_equalize
变量中。plt.hist(phone_equalize.ravel(), bins=256)
和plt.show()
:与展示原始图像直方图类似,这两行代码将处理后的图像展平并绘制其直方图,然后显示出来。通过对比这两个直方图,可以直观看到直方图均衡化后像素值分布变得更加均匀,反映出图像对比度的增强。
4. 展示原始图像与直方图均衡化后图像的对比
python
res = np.hstack((woman,phone_equalize))
cv2.imshow('phone_equalize',res)
cv2.waitKey(0)
res = np.hstack((woman,phone_equalize))
:使用numpy
的hstack
函数将原始图像woman
和直方图均衡化后的图像phone_equalize
在水平方向上拼接起来,形成一个新的图像res
,方便直接对比两者的视觉效果。cv2.imshow('phone_equalize',res)
:使用 OpenCV 的imshow
函数显示拼接后的图像,窗口标题为 “phone_equalize”。cv2.waitKey(0)
:等待用户按下任意键。这一步确保图像窗口不会立即关闭,用户可以有足够时间观察图像效果。
5. 进行自适应直方图均衡化并展示结果
python
# 自适应直方图均衡化(局部直方图处理),通过局部调整图像的直方图分布来提升图像的对比度和细节表现力,当需要保存细节特征,需要做局部处理
# cv2.createCLAHE([, clipLimit[, tileGridSize]]) → retval
# 参数说明:
# clipLimit:颜色对比度的阈值,可选项,默认值 8
# titleGridSize:局部直方图均衡化的模板(邻域)大小,可选项,默认值 (8,8)
clahe = cv2.createCLAHE(clipLimit=1, tileGridSize=(16,16))
phone_clahe = clahe.apply(woman)
res = np.hstack((woman,phone_equalize,phone_clahe))
cv2.imshow('phone_equalize',res)
cv2.waitKey(0)
- 这部分注释解释了自适应直方图均衡化(CLAHE)的概念,即通过局部调整图像直方图分布来提升图像细节和对比度,适用于需要保留图像细节特征的情况。同时说明了
cv2.createCLAHE
函数的参数含义。 clahe = cv2.createCLAHE(clipLimit=1, tileGridSize=(16,16))
:使用cv2.createCLAHE
函数创建一个自适应直方图均衡化对象clahe
,设置对比度阈值clipLimit
为 1,局部直方图均衡化的邻域大小tileGridSize
为 (16, 16)。phone_clahe = clahe.apply(woman)
:对原始灰度图像woman
应用自适应直方图均衡化处理,处理结果保存在phone_clahe
变量中。res = np.hstack((woman,phone_equalize,phone_clahe))
:再次使用hstack
函数,将原始图像woman
、直方图均衡化后的图像phone_equalize
以及自适应直方图均衡化后的图像phone_clahe
在水平方向上拼接起来,形成新的对比图像res
。cv2.imshow('phone_equalize',res)
和cv2.waitKey(0)
:与之前类似,显示拼接后的对比图像,并等待用户按键关闭窗口。这样用户可以直观对比原始图像、直方图均衡化后的图像以及自适应直方图均衡化后的图像之间的差异。
代码
#$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
#直方图均衡化:直方图均衡化是一种图像增强技术,它可以通过增加图像的对比度和亮度来改善图像的质量。
# 直方图均衡化通过将图像的像素值分布均匀化来实现这一目标。
# 在Python OpenCV中,可以使用cv2.equalizeHist()函数来实现直方图均衡化。
# 该函数将输入图像转换为灰度图像,并将其像素值分布均匀化,从而增强图像的对比度和亮度。woman = cv2.imread('woman.png',cv2.IMREAD_GRAYSCALE)
# # # phone_hist = cv2.calcHist([phone],[0],None,[256],[0,256])
plt.hist(woman.ravel(), bins=256)#numpy中的ravel将数组多维度拉成一维数组
plt.show()
# # #
phone_equalize = cv2.equalizeHist(woman)
plt.hist(phone_equalize.ravel(), bins=256)#numpy中的ravel将数组多维度拉成一维数组
plt.show()
# #
res = np.hstack((woman,phone_equalize))#横向拼接,将多个数组按水平方向(列顺序)堆叠成一个新的数组。
cv2.imshow('phone_equalize',res)
cv2.waitKey(0)
# # # 自适应直方图均衡化(局部直方图处理),通过局部调整图像的直方图分布来提升图像的对比度和细节表现力,当需要保存细节特征,需要做局部处理
# # # cv2.createCLAHE([, clipLimit[, tileGridSize]]) → retval
# # # 参数说明:
# # # clipLimit:颜色对比度的阈值,可选项,默认值 8
# # # titleGridSize:局部直方图均衡化的模板(邻域)大小,可选项,默认值 (8,8)
clahe = cv2.createCLAHE(clipLimit=1, tileGridSize=(16,16))#通过类创建了一个局部均衡化对象
phone_clahe = clahe.apply(woman)
res = np.hstack((woman,phone_equalize,phone_clahe))
cv2.imshow('phone_equalize',res)
cv2.waitKey(0)
效果
图像投影(透视)变换---cv2. getPerspectiveTransform,cv2.warpPerspective、
逻辑
1. 导入必要的库
python
import numpy as np
import cv2
导入numpy
库用于数值计算,cv2
即 OpenCV 库用于图像处理。
2. 定义辅助函数
cv_show
函数
python
def cv_show(name, img):cv2.imshow(name, img)cv2.waitKey(0)
这个函数用于显示图像。它接受两个参数,name
是窗口的名称,img
是要显示的图像。函数内部使用cv2.imshow
显示图像,并通过cv2.waitKey(0)
等待用户按键,确保图像窗口不会立即关闭。
order_points
函数
python
def order_points(pts):rect = np.zeros((4, 2), dtype="float32")s = pts.sum(axis=1)rect[0] = pts[np.argmin(s)]rect[2] = pts[np.argmax(s)]diff = np.diff(pts, axis=1)rect[1] = pts[np.argmin(diff)]rect[3] = pts[np.argmax(diff)]return rect
该函数的作用是对输入的四个点进行排序。
- 首先创建一个
rect
数组,用于存储排序后的四个点的坐标,数据类型为float32
。 - 通过对每个点的横纵坐标之和进行计算(
pts.sum(axis=1)
),找到和最小的点作为左上角的点(rect[0]
),和最大的点作为右下角的点(rect[2]
)。 - 然后通过对每个点的横纵坐标之差进行计算(
np.diff(pts, axis=1)
),找到差最小的点作为右上角的点(rect[1]
),差最大的点作为左下角的点(rect[3]
)。 - 最后返回排序后的四个点的坐标。
four_point_transform
函数
python
def four_point_transform(image, pts):rect = order_points(pts)(tl, tr, br, bl) = rectwidthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))maxWidth = max(int(widthA), int(widthB))heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))maxHeight = max(int(heightA), int(heightB))dst = np.array([[0, 0], [maxWidth - 1, 0],[maxWidth - 1, maxHeight - 1], [0, maxHeight - 1]], dtype="float32")M = cv2.getPerspectiveTransform(rect, dst)warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))return warped
该函数实现了图像的透视变换。
- 首先调用
order_points
函数对输入的四个点进行排序。 - 接着计算变换后图像的宽度和高度。通过计算对角点之间的欧几里得距离,分别得到两个可能的宽度值(
widthA
和widthB
)和两个可能的高度值(heightA
和heightB
),取其中的较大值作为变换后图像的宽度(maxWidth
)和高度(maxHeight
)。 - 定义变换后的目标四个点的坐标
dst
,分别对应左上角、右上角、右下角和左下角。 - 使用
cv2.getPerspectiveTransform
函数计算从原始四个点到目标四个点的透视变换矩阵M
。 - 最后通过
cv2.warpPerspective
函数应用这个变换矩阵,将原始图像变换为指定大小的新图像,并返回变换后的图像。
resize
函数
python
def resize(image, width=None, height=None, inter=cv2.INTER_AREA):dim = None(h, w) = image.shape[:2]if width is None and height is None:return imageif width is None:r = height / float(h)dim = (int(w * r), height)else:r = width / float(w)dim = (width, int(h * r))resized = cv2.resize(image, dim, interpolation=inter)return resized
该函数用于调整图像大小。
- 首先获取图像的高度
h
和宽度w
。 - 如果
width
和height
都为None
,则直接返回原始图像。 - 如果
width
为None
,则根据目标高度height
计算缩放比例r
,并计算出调整后的宽度,得到新的尺寸dim
。 - 如果
height
为None
,则根据目标宽度width
计算缩放比例r
,并计算出调整后的高度,得到新的尺寸dim
。 - 最后使用
cv2.resize
函数按照指定的尺寸dim
和插值方法inter
对图像进行缩放,并返回缩放后的图像。
3. 图像处理流程
读取和缩放图像
python
image = cv2.imread('fapiao.jpg')
cv_show('image', image)ratio = image.shape[0] / 500.0
orig = image.copy()
image = resize(orig, height=500)
cv_show('1',image)
- 读取发票图片
fapiao.jpg
并显示原始图像。 - 计算图像高度与 500 的比例
ratio
,并复制原始图像到orig
。 - 使用
resize
函数将图像高度调整为 500,得到缩小后的图像image
并显示。
轮廓检测
python
print("STEP 1: 轮廓检测")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
edged = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[-2]
image_contours = cv2.drawContours(image.copy(), cnts, -1, (0, 0, 255), 1)
cv_show('image_contours', image_contours)
- 将缩小后的图像转换为灰度图像
gray
。 - 使用
cv2.threshold
函数结合cv2.THRESH_OTSU
方法自动寻找阈值进行二值化处理,得到边缘图像edged
。 - 使用
cv2.findContours
函数查找图像中的轮廓,cv2.RETR_LIST
表示检索所有轮廓,cv2.CHAIN_APPROX_SIMPLE
表示压缩水平、垂直和对角方向的轮廓点。 - 使用
cv2.drawContours
函数在图像副本上绘制所有轮廓,并显示绘制轮廓后的图像。
获取最大轮廓
python
print("STEP 2: 获取最大轮廓")
screenCnt = sorted(cnts, key=cv2.contourArea, reverse=True)[0]
peri = cv2.arcLength(screenCnt, True)
screenCnt = cv2.approxPolyDP(screenCnt, 0.05 * peri, True)
print(screenCnt.shape)
image_contour = cv2.drawContours(image.copy(), [screenCnt], -1, (0, 255, 0), 2)
cv2.imshow("image_contour", image_contour)
cv2.waitKey(0)
- 对找到的轮廓按照面积从大到小排序,取面积最大的轮廓
screenCnt
。 - 使用
cv2.arcLength
函数计算该轮廓的周长peri
。 - 使用
cv2.approxPolyDP
函数对轮廓进行近似,0.05 * peri
表示近似精度,True
表示轮廓是闭合的。 - 在图像副本上绘制最大轮廓,并显示绘制后的图像。
透视变换
python
warped = four_point_transform(orig, screenCnt.reshape(4, 2) * ratio)
cv2.imwrite('invoice_new.jpg', warped)
cv2.namedWindow('xx',cv2.WINDOW_NORMAL)
cv2.imshow("xx", warped)
cv2.waitKey(0)
- 使用
four_point_transform
函数对原始图像orig
进行透视变换,将最大轮廓对应的四边形区域变换为矩形。这里需要将轮廓点的坐标乘以之前计算的缩放比例ratio
,以还原到原始图像的尺寸。 - 将变换后的图像保存为
invoice_new.jpg
,并显示变换后的图像。
二值处理和形态学操作
python
warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
ref = cv2.threshold(warped, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv_show('ref',ref)kernel = np.ones((2, 2), np.uint8)
ref_new = cv2.morphologyEx(ref, cv2.MORPH_CLOSE, kernel)
ref_new=resize(ref_new.copy(),width=500)
cv_show('ref_new',ref_new)
rotated_image = cv2.rotate(ref_new, cv2.ROTATE_90_COUNTERCLOCKWISE)
cv2.imshow("result", rotated_image)
cv2.waitKey(0)
- 将透视变换后的图像转换为灰度图像。
- 再次使用
cv2.threshold
函数结合cv2.THRESH_OTSU
方法进行二值化处理,得到二值图像ref
并显示。 - 创建一个大小为
(2, 2)
的结构元素kernel
。 - 使用
cv2.morphologyEx
函数对二值图像进行闭运算(先膨胀后腐蚀),得到处理后的图像ref_new
。 - 将
ref_new
图像宽度调整为 500 并显示。 - 使用
cv2.rotate
函数将图像逆时针旋转 90 度,显示最终结果图像。
代码
import numpy as np
import cv2
def cv_show(name, img):cv2.imshow(name, img)cv2.waitKey(0)
def order_points(pts):# 一共4个坐标点rect = np.zeros((4, 2), dtype="float32") # 用来存储排序之后的坐标位置# 按顺序找到对应坐标0123分别是 左上,右上,右下,左下s = pts.sum(axis=1) #对pts矩阵的每一行进行求和操作。(x+y)rect[0] = pts[np.argmin(s)]rect[2] = pts[np.argmax(s)]diff = np.diff(pts, axis=1) #对pts矩阵的每一行进行求差操作。(y-x)rect[1] = pts[np.argmin(diff)]rect[3] = pts[np.argmax(diff)]return rect
def four_point_transform(image, pts):# 获取输入坐标点rect = order_points(pts)(tl, tr, br, bl) = rect# 计算输入的w和h值widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))maxWidth = max(int(widthA), int(widthB))heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))maxHeight = max(int(heightA), int(heightB))# 变换后对应坐标位置dst = np.array([[0, 0], [maxWidth - 1, 0],[maxWidth - 1, maxHeight - 1], [0, maxHeight - 1]], dtype="float32")# 图像透视变换 cv2.getPerspectiveTransform(src, dst[, solveMethod]) → MP获得转换之间的关系# src:变换前图像四边形顶点坐标# cv2.warpPerspective(src, MP, dsize[, dst[, flags[, borderMode[, borderValue]]]]) → dst# 参数说明:# src:原图# MP:透视变换矩阵,3行3列# dsize: 输出图像的大小,二元元组(width, height)M = cv2.getPerspectiveTransform(rect, dst)warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))# 返回变换后结果return warped
def resize(image, width=None, height=None, inter=cv2.INTER_AREA):dim = None(h, w) = image.shape[:2]if width is None and height is None:return imageif width is None:r = height / float(h)dim = (int(w * r), height)else:r = width / float(w)dim = (width, int(h * r))resized = cv2.resize(image, dim, interpolation=inter)#参数interpolation指定了在图像大小调整过程中如何处理像素插值的方法。cv2.INTER_AREA具体意味着使用面积插值方法。return resized# 读取输入
image = cv2.imread('fapiao.jpg')
cv_show('image', image)# 图片过大,进行缩小处理
ratio = image.shape[0] / 500.0 # 计算缩小比率
orig = image.copy()
image = resize(orig, height=500)
cv_show('1',image)# 轮廓检测
print("STEP 1: 轮廓检测")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 读取灰度图edged = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] # 自动寻找阈值二值化
cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[-2]
image_contours = cv2.drawContours(image.copy(), cnts, -1, (0, 0, 255), 1)
cv_show('image_contours', image_contours)print("STEP 2: 获取最大轮廓")
screenCnt = sorted(cnts, key=cv2.contourArea, reverse=True)[0] # 获取面积最大的轮廓peri = cv2.arcLength(screenCnt, True) # 计算轮廓周长
screenCnt = cv2.approxPolyDP(screenCnt, 0.05 * peri, True) # 轮廓近似
print(screenCnt.shape)
image_contour = cv2.drawContours(image.copy(), [screenCnt], -1, (0, 255, 0), 2)cv2.imshow("image_contour", image_contour)
cv2.waitKey(0)# 透视变换
warped = four_point_transform(orig, screenCnt.reshape(4, 2) * ratio)
cv2.imwrite('invoice_new.jpg', warped)
cv2.namedWindow('xx',cv2.WINDOW_NORMAL)
cv2.imshow("xx", warped)
cv2.waitKey(0)# 二值处理
warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
ref = cv2.threshold(warped, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv_show('ref',ref)kernel = np.ones((2, 2), np.uint8) # 设置kenenel大小
ref_new = cv2.morphologyEx(ref, cv2.MORPH_CLOSE, kernel) # 闭运算,先膨胀再腐蚀
ref_new=resize(ref_new.copy(),width=500)
cv_show('ref_new',ref_new)
rotated_image = cv2.rotate(ref_new, cv2.ROTATE_90_COUNTERCLOCKWISE)
cv2.imshow("result", rotated_image)
cv2.waitKey(0)
特征检测:harris角点检测
Harris角点检测算法是一种常用的计算机视觉算法,用于检测图像中的角点。该算法通过计算图像中每个像素的局部自相关矩阵,来判断该像素是否为角点。
角点检测算法的基本思想:
使用一个固定的小窗口在图像上进行任意方向的滑动,比较滑动前与滑动后两种情况,窗口中的像素灰度变化程度,如果存在任意方向上的滑动,都有着较大灰度变化(sobel算子),那么我们可以认为该窗口中存在角点。
逻辑
- 代码功能概述
- 这段代码主要实现了对图像
huanghelou.png
的角点检测,并将检测到的角点在原图上标记出来进行显示。
- 这段代码主要实现了对图像
- 代码详细分析
- 导入与准备:虽然代码开头没有明确看到
import
语句,但从使用的函数可以推断,应该导入了cv2
(OpenCV 库)和可能的numpy
库(在cv2.cornerHarris
函数的返回值处理中可能涉及)。 - 读取与转换图像:
python
img = cv2.imread('huanghelou.png') gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv2.imread('huanghelou.png')
:读取名为huanghelou.png
的图像,并将其存储在img
变量中,此时img
是一个彩色图像(BGR 格式)。cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
:将彩色图像img
转换为灰度图像,并存储在gray
变量中。因为cv2.cornerHarris
函数通常要求输入的是灰度图像,所以这一步是必要的预处理。
- 角点检测:
python
dst = cv2.cornerHarris(gray,4,3,0.04)
cv2.cornerHarris
函数用于进行 Harris 角点检测。- 参数
gray
是输入的灰度图像。 blockSize = 4
表示角点检测中要考虑的邻域大小,即每个像素点周围的4x4
邻域会被用于计算角点响应。ksize = 3
是 Sobel 求导中使用的窗口大小,Sobel 算子用于计算图像的梯度,窗口大小影响梯度计算的精度和效果。k = 0.04
是 Harris 角点检测方程中的自由参数,取值范围一般在[0.04, 0.06]
之间,该参数影响角点检测的灵敏度和准确性。- 函数返回一个与输入图像大小相同的
dst
数组,数组中的值表示每个像素点是角点的可能性,值越大,该像素点是角点的概率越高。
- 标记角点:
python
img[dst > 0.01 * dst.max()] = [0, 0, 255]
- 这一步是在原始彩色图像
img
上标记出检测到的角点。 dst.max()
获取dst
数组中的最大值。0.01 * dst.max()
作为一个阈值,筛选出dst
数组中大于该阈值的像素点位置。- 对于这些位置,将原始图像
img
对应位置的像素值设置为[0, 0, 255]
,即红色,从而在图像上标记出角点。
- 这一步是在原始彩色图像
- 显示图像:
python
cv2.imshow('img',img) cv2.waitKey(0)
cv2.imshow('img',img)
将标记了角点的图像显示在名为img
的窗口中。cv2.waitKey(0)
等待用户按下任意键,确保图像窗口不会立即关闭,用户可以观察标记角点后的图像效果。
- 导入与准备:虽然代码开头没有明确看到
代码
#$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
'''-------------------角点检测-------------------------'''
# 角点指图像中局部区域与周围区域有较大灰度变化的点或像素。
# cornerHarris(img, blockSize, ksize, k[, dst[, borderType]]) -> dst
# • img: 输入图像。
# • blockSize: 角点检测中要考虑的领域大小。
# • ksize: Sobel求导中使用的窗口大小。
# • k: Harris角点检测方程中的自由参数,取值参数为 [0.04,0.06]。
# dst:返回numpy.ndarray对象,大小和src相同,值越大,对应像素点是角的概率越高img = cv2.imread('huanghelou.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
dst = cv2.cornerHarris(gray,4,3,0.04)
# 标记检测到的角点
img[dst > 0.01 * dst.max()] = [0, 0, 255]
# 这里通过对角点响应进行阈值处理,标记出检测到的角点。
# 0.05 * dst.max() 是一个阈值,大于这个值的像素点会被标记为红色。
cv2.imshow('img',img)
cv2.waitKey(0)
特征检测:sift特征检测
SIFT(Scale Invariant Feature Transform)尺度不变特征变换。SIFT特征具有对旋转、尺度缩放、亮度变化等保持不变性,是一种非常稳定的局部特征。
SIFT算法具的特点
1、图像的局部特征,对旋转、尺度缩放、亮度变化保持不变,对视角变化、仿射变换、噪声也保持一定程度的稳定性。
2、独特性好,信息量丰富,适用于海量特征库进行快速、准确的匹配。
3、多量性,即使是很少几个物体也可以产生大量的SIFT特征
4、高速性,经优化的SIFT匹配算法甚至可以达到实时性
5、扩招性,可以很方便的与其他的特征向量进行联合。
逻辑
- 代码功能概述
- 这段代码主要使用 SIFT(尺度不变特征变换,Scale - Invariant Feature Transform)算法对图像
man.png
进行特征提取。具体操作包括检测图像中的关键点,绘制这些关键点,以及计算关键点的描述符,为后续的特征匹配做准备。
- 这段代码主要使用 SIFT(尺度不变特征变换,Scale - Invariant Feature Transform)算法对图像
- 代码详细分析
- 导入与准备:同样,代码开头虽未明确显示,但应该导入了
cv2
库和numpy
库(从对关键点形状的处理以及print
语句中可以推断)。 - 读取与转换图像:
python
phone = cv2.imread('man.png') phone_gray = cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)
cv2.imread('man.png')
读取名为man.png
的图像,并将其存储在phone
变量中,图像格式为 BGR 彩色图像。cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)
将彩色图像phone
转换为灰度图像phone_gray
。因为 SIFT 算法通常在灰度图像上进行操作,所以这是必要的预处理步骤。
- 创建 SIFT 对象与检测关键点:
python
sift = cv2.SIFT_create() kp = sift.detect(phone_gray)
cv2.SIFT_create()
创建一个 SIFT 特征提取对象sift
。这个对象提供了一系列用于 SIFT 特征提取的方法。sift.detect(phone_gray)
在灰度图像phone_gray
中查找关键点。关键点是图像中具有独特特征的点,比如角点、边缘点等,它们在不同尺度和旋转下具有一定的稳定性。kp
是一个包含关键点信息的列表,每个关键点对象具有以下属性:kp.pt
:关键点的 (x, y) 坐标。kp.size
:关键点的大小(尺度),反映了关键点所在区域的大小,大的尺度表示关键点在图像中的重要性更高。kp.angle
:关键点的方向,用于使特征具有旋转不变性。kp.response
:关键点的响应值,该值越大表示该关键点越显著。kp.octave
:关键点所在的金字塔层级,SIFT 算法通过构建图像金字塔来实现尺度不变性,不同层级对应不同尺度的图像。
- 绘制关键点:
python
phone_sift = cv2.drawKeypoints(phone,kp,None,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) cv2.imshow('phone_sift',phone_sift) cv2.waitKey(0)
cv2.drawKeypoints
函数用于在图像上绘制关键点。- 参数
phone
是原始彩色图像,作为绘制关键点的基础图像。 kp
是前面检测到的关键点列表。None
表示输出图像直接在原始图像phone
上绘制(如果设为None
,函数会直接修改原始图像)。flags = cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS
这个标志设置绘图功能,使得绘制出的关键点更富有信息,例如会绘制关键点的方向和尺度等信息。绘制后的图像存储在phone_sift
中。cv2.imshow('phone_sift',phone_sift)
将绘制了关键点的图像显示在名为phone_sift
的窗口中。cv2.waitKey(0)
等待用户按下任意键,确保图像窗口不会立即关闭,用户可以观察绘制关键点后的图像效果。
- 计算关键点描述符:
python
kp,des = sift.compute(phone,kp) print(np.array(kp).shape,des.shape)
sift.compute(phone,kp)
计算关键点的描述符。描述符是用于描述关键点特征的向量,它包含了关键点周围区域的纹理等信息,用于后续的特征匹配。这里phone
是原始图像,kp
是之前检测到的关键点。计算后,kp
可能会更新一些属性(比如描述符相关的属性),des
是关键点的描述符数组。print(np.array(kp).shape,des.shape)
输出关键点的形状和描述符的形状。np.array(kp).shape
表示关键点的数量和属性维度(例如,如果每个关键点有多个属性,形状可能会反映这些属性的数量),des.shape
表示描述符的数量和每个描述符的维度。这些信息对于了解图像中提取的特征数量和特征表示的维度很有帮助,在后续的特征匹配和分析中可能会用到。
- 导入与准备:同样,代码开头虽未明确显示,但应该导入了
代码
'''---------------特征提取sift---------------------'''
# 检测图像中的关键点
# cv2.SIFT_create() #cv2.xfeatures2d.SIFT_create()#创建一个sift特征的提取对象
# sift.detect(img) #在图像中查找关键点phone = cv2.imread('man.png')
phone_gray = cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)#
sift = cv2.SIFT_create() #sift对象
kp = sift.detect(phone_gray)
# # kp.pt:关键点的(x, y)
# # 坐标。
# # kp.size:关键点的大小(尺度)。
# # kp.angle:关键点的方向。
# # kp.response:关键点的响应值。
# # kp.octave:关键点所在的金字塔层级。
# #查找关键点
# # drawKeypoints(image, keypoints, outImage, color=None, flags=None)
# # image:原始图片
# # keypoints:从原图中获得的关键点,这也是画图时所用到的数据
# # outputimage:输出图像,可以是原始图片,也可以是None
# # color:颜色设置,通过修改(b,g,r)的值,更改画笔的颜色,b=蓝色,g=绿色,r=红色。
# # flags:绘图功能的标识设置 绘制富有信息的关键点。
phone_sift = cv2.drawKeypoints(phone,kp,None,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow('phone_sift',phone_sift)
cv2.waitKey(0)
#
# # 使用sift.compute()计算关键点描述符,方便后期的特征匹配
kp,des = sift.compute(phone,kp) #
print(np.array(kp).shape,des.shape)
# # 输出关键点的形状和描述符的形状。
# # np.array(kp).shape 表示关键点的数量和属性。
# # des.shape 表示描述符的数量和属性。