opencv-python:图像处理

一、基础概念

1.几何变换

图像的几何变换是改变图像的几何属性,如位置、大小、形状和方向等的变换。
常见的几何变换包括平移、旋转、缩放、翻转和错切等。
平移是将图像在方向上移动一定的距离。
旋转是以图像的中心或指定的点为中心,将图像旋转一定的角度。
缩放是改变图像的大小,可以沿着水平方向和垂直方向进行不同比例的缩放。
翻转是将图像在水平方向或垂直方向上进行对称变换。
错切则是在一定方向上拉伸或压缩图像。
仿射变换可以看作是平移、旋转、缩放、翻转和错切的综合,仿射变换保持了二维图形的“平直性”和“平行性”,即直线在变换后仍然是直线,平行线在变换后仍然是平行线。
透视变换是三维空间上的非线性变换,可以看作是仿射变换的更一般形式,透视变换通过一个3x3的变换矩阵将原图投影到一个新的视平面

2.图像滤波

图像滤波

图像滤波是图像预处理操作,简单的讲,就是一幅图像通过滤波器得到另一幅图像。
图像滤波目的是在尽量保留图像细节特征的条件下,对目标图像的噪声进行抑制。
常见的图像滤波方法包括均值滤波、中值滤波和高斯滤波等。
均值滤波是一种简单的线性滤波方法,通过对图像中的像素进行平均操作,实现图像的平滑。
中值滤波是一种非线性滤波方法,通过对图像中的像素进行排序,选择中间值作为输出值,实现图像的去噪。
高斯滤波是一种基于高斯函数的线性滤波方法,通过对图像中的像素进行加权平均操作,实现图像的平滑。

滤波器(wave filter)

在图像处理中,滤波器,也叫卷积核 Convolutional Kernel是一种用于平滑图像、消除噪声或提取特定特征的工具。滤波的过程,称为卷积convolution。它通过在原始图像上滑动并卷积,利用相邻像素的值来确定每个像素的最终输出。
卷积核的大小一般为奇数,如3 * 3,5 * 5,7 * 7。
一是为了保证锚点anchor(卷积核的中心),刚好在正中间,方便以模块中心为标准进行滑动而不会发生偏移。
二是为了保证填充padding时,图像的两边依然对称。
一般情况下,卷积核越大,感受野越大,看到的图片信息越多,所获得的全局特征越好。但大的卷积核会导致计算量的暴增,计算性能也会降低。

输出图片尺寸计算公式

计算公式:N = (W - F + 2P) / S + 1
N(New)表示输出图像大小
W(Width)表示原图宽度
F(Filter)表示卷积核大小
P(Padding)表示扩充尺寸
S(Step)表示步长大小,默认为1

3.形态学处理(Morphological Processing)

  • 基于形状对图像进行处理的图像处理方法。
  • 利用一种特殊的结构元素(可以理解为卷积核)来测量或提取输入图像中相应的形状或特征
  • 针对二进制图像,因此需要对图片做二值化处理
  • 形态学处理包括腐蚀、膨胀、开运算(先腐蚀后膨胀)和闭运算(先膨胀后腐蚀)
    腐蚀操作:将一个对象的边界向内收缩,从而消除小物体或分离相连的物体。
    膨胀操作:将一个对象的边界向外扩张,从而填补物体内部的空洞或连接相邻的物体。
    开运算:可以用来消除小物体、在纤细点处分离物体、平滑较大物体的边界的同时并不明显改变其面积。
    闭运算:可以用来填充物体内细小空洞、连接邻近物体、平滑其边界的同时并不明显改变其面积。
    图像二值化:将图像中的每个元素均变为0或255

4.图像轮廓处理

图像轮廓是图像中不同颜色或亮度相邻区域之间的边界,也可以理解为将边缘连接起来形成的一个整体,本质上是具有相同颜色或强度的连续点的曲线。
查找图像轮廓前

  • 需要对图像进行二值化处理或Canny边缘检测
  • 需要对原图像进行深拷贝
  • 尽量将图片做成黑底白字更易于轮廓的查找

5.特征检测

特征图像或视频中有意义的信息,如边缘、角点、斑点、纹理等。
特征检测的应用:图像搜索、图像拼接等。
角点:灰度梯度最大值对应的像素、线条交点、极值点

二、opencv-python几何变换函数

1.图像缩放

resize(src, dst, dsize, fx, fy, interpolation)
fx, fy 分别是 x, y 轴的缩放因子

interpolation插值算法
INTER_NEAREST近邻算法,速度快,效果差
INTER_LINEAR近邻算法,速度快,效果差
INTER_CUBIC三次插值,原图中的16个点
INTER_AREA效果最好
# 用dsize
import cv2 as cv
img = cv.imread("D://dev/opencv/sources/samples/data/starry_night.jpg")
img_resize = cv.resize(img, (400, 400))
cv.imshow("img", img)
cv.imshow("img_resize", img_resize)
cv.waitKey(0)
# 用缩放因子fx,fy
import cv2 as cv
img = cv.imread("D://dev/opencv/sources/samples/data/starry_night.jpg")
img_resize = cv.resize(img, None, fx=0.3, fy=0.3)
cv.imshow("img", img)
cv.imshow("img_resize", img_resize)
cv.waitKey(0)

2.图像翻转

flip(img, flipCode)

flipCode翻转方向
flipCode == 0上下翻转
flipCode > 0左右翻转
flipCode < 0上下左右翻转
import cv2 as cv
img = cv.imread("D://dev/opencv/sources/samples/data/starry_night.jpg")
img_flip = cv.flip(img, 0)
cv.imshow("img", img)
cv.imshow("img_flip", img_flip)
cv.waitKey(0)

3.图像旋转

rotate(img, rotateCode)

rotateCode旋转角度
ROTATE_90_CLOCKWISE逆向旋转90°
ROTATE_180旋转180°
ROTATE_90_COUNTERCLOCKWISE正向旋转90°
import cv2 as cv
img = cv.imread("D://dev/opencv/sources/samples/data/starry_night.jpg")
img_rotate = cv.rotate(starry_night, cv.ROTATE_90_CLOCKWISE)
cv.imshow("img", img)
cv.imshow("img_rotate", img_rotate)
cv.waitKey(0)

4.仿射变换

warpAffine(src, M, dsize, flags, borderMode, borderValue)
M:变换矩阵
flags:插值算法
后两个参数是原图移到边界之外的部分怎么处理

borderMode边界模式
cv.BORDER_CONSTANT(default)常值模式
cv.BORDER_REPLICATE复制近邻元素
cv.BORDER_REFLECT镜像填充

borderValue(在常值模式时, (0, 0, 0)默认值)

import cv2 as cv
import numpy as np 
img = cv.imread("D://dev/opencv/sources/samples/data/starry_night.jpg")
M = np.array([[1, 0, 100], [0, 1, 50]], dtype=np.float32)
h, w, ch = img.shape
img_Affine = cv.warpAffine(img, M, [w, h])
cv.imshow("img", img)
cv.imshow("img_Affine", img_Affine)
cv.waitKey(0)

5.获取旋转变换矩阵

getRotationMatrix2D(center, angle, scale)
center:旋转的中心点。
angle:旋转的角度,以度为单位。
scale:可选参数,缩放因子。如果提供了这个参数,那么在旋转的同时还会进行缩放。

import cv2 as cv
img = cv.imread("D://dev/opencv/sources/samples/data/starry_night.jpg")
M = cv.getRotationMatrix2D([100, 100], 45, 0.5)
h, w, ch = img.shape
img_Affine = cv.warpAffine(img, M, [w, h])
cv.imshow("img", img)
cv.imshow("img_Affine", img_Affine)
cv.waitKey(0)

retval, mat = cv.getAffineTransform(src, dst)
src:源图像中三角形顶点的坐标,这是一个点的数组。
dst:目标图像中相应三角形顶点的坐标,这也是一个点的数组。

import cv2 as cv
import numpy as np 
src = np.array([[100, 100], [100, 200], [200, 200]], dtype=np.float32)
dst = np.array([[200, 200], [200, 300], [300, 300]], dtype=np.float32)
M = cv.getAffineTransform(src, dst)
print(M)

6.透视变换

warpPerspective(src, M, dsize, flags, borderMode, borderValue)

import cv2 as cv
import numpy as np 
img = cv.imread("D://dev/opencv/sources/samples/data/right.jpg")
src_P = np.float32([[360, 105], [300, 315], [525, 345], [585, 120]])
dst_P = np.float32([[0, 0], [0, 459], [612, 459], [612, 0]])
M_P = cv.getPerspectiveTransform(src_P, dst_P)
img_Perspective = cv.warpPerspective(img, M_P, [612, 459])
cv.imshow("img", img)
cv.imshow("img_Perspective", img_Perspective)
cv.waitKey(0)

三、opencv-python滤波函数

1.滤波函数

filter2D(src, ddepth, kernel, anchor, delta, borderType)

src的深度ddepth(输出图像位深)
输出图像与输入图像具有相同的深度-1
CV_8U-1、CV_16S、CV_32F、CV_64F
CV_16U、CV_16S-1、CV_32F、CV_64F
CV_32F-1、CV_32F、CV_64F
CV_64F-1、CV_64F

anchor默认为(-1, -1),表示卷积核的中心是锚点。
delta是偏移量

# 低通滤波:去除噪声,平滑图像
# 高通滤波:边缘检测,识别轮廓
import cv2 as cv
import numpy as np

squirrel = cv.imread("D://dev/opencv/sources/samples/data/squirrel_cls.jpg")
# 均值滤波卷积核
kernal = np.ones((5, 5), dtype=np.float32) / 25
squi_filter = cv.filter2D(squirrel, -1, kernal)

cv.imshow("squirrel", squirrel)
cv.imshow("squi_filter", squi_filter)
cv.waitKey(0)

2.低通滤波

方盒滤波

boxFilter(src, ddepth, ksize, anchor, normalize, borderType)
blur(src, ksize, anchor, borderType)
ksize:滤波器的大小,必须是奇数
normalize == True 时, 滤波器是均值滤波器(默认值)
normalize == False时,滤波器是方盒滤波器

squi_filter = cv.blur(squirrel, (5, 5))

高斯滤波

GaussianBlur(src, ksize, sigmaX, sigmaY, borderType)
sigmaX:X方向上的标准差。
sigmaY:Y方向上的标准差,默认等于sigmaX。

# ksize越大,sigma越大,模糊处理越大
# 高斯滤波对高斯噪声滤波效果最好
squi_filter = cv.GaussianBlur(squirrel, (3, 3), sigmaX=1)

中值滤波(非线性)

medianBlur(src, ksize, borderType)

# 中值滤波对椒盐噪声效果很好
squi_filter = cv.medianBlur(squirrel, 5)

双边滤波(非线性)

bilateral(src, d, sigmaColor, sigmaSpace, borderType)
d:滤波模板的大小。
sigmaColor:颜色空间的滤波的标准差。
sigmaSpace:空间坐标的滤波的标准差。

# 双边滤波,可以保留边缘,同时平滑边缘内的信息
squi_filter = cv.bilateralFilter(squirrel, 7, 20, 50)

3.高通滤波

Sobel算子

抗噪声效果好,内含高斯滤波,常用于边缘检测。
Sobel(src, ddepth, dx, dy, ksize)

squirrel = cv.imread("D://dev/opencv/sources/samples/data/squirrel_cls.jpg", cv.IMREAD_GRAYSCALE)
# 对x,y方向均求导
squi_filterx = cv.Sobel(squirrel, cv.CV_64F, 1, 0, ksize=3)
squi_filtery = cv.Sobel(squirrel, cv.CV_64F, 0, 1, ksize=3)
squi_filter = cv.add(squi_filterx, squi_filtery)

Scharr算子

与Sobel类似,但其kernel不同且只支持3 * 3的kernel
只能求单方向的导数
cv.Scharr(src, ddepth, dx, dy)

# 也可以使用Sobel的API将ksize设为-1
squi_filterx = cv.Scharr(squirrel, cv.CV_64F, 1, 0)
squi_filtery = cv.Scharr(squirrel, cv.CV_64F, 0, 1)
squi_filter = cv.add(squi_filterx, squi_filtery)

Laplacian算子

可以同时求两个方向上的导数
对噪声敏感,使用前需要去噪
dst = cv2.Laplacian(src, ddepth, ksize)

squi_filter = cv.Laplacian(squirrel, cv.CV_64F, ksize=5)

Canny边缘检测

5 * 5高斯滤波降噪
Sobel算子从四个方向计算图像的梯度(0°/45°/90°/135°)
非极大值抑制(取局部最大值)
阈值计算
Canny(image, threshold1, threshold2)

squi_filter = cv.Canny(squirrel, 150, 200)

四、opencv-python形态学处理

1.全局二值化

threshold(src, thresh, maxval, thresholdType)
src:最好是灰度图像
thresh:阈值,用于分类像素值。
maxval:当像素值超过了阈值(或者小于阈值,根据阈值类型来决定)所赋予的值。

thresholType阈值类型
cv.THRESH_BINARY正向二值化
cv.THRESH_BINARY_INV反向二值化
cv.THRESH_TRUNC截断trancate:高于阈值的部分置为阈值
cv.THRESH_TOZERO低于阈值的部分置零,其余不变
cv.THRESH_TOZERO_INV高于阈值的部分置零,其余不变
import cv2 as cv
img = cv.imread("D://dev/opencv/sources/samples/data/squirrel_cls.jpg",cv.IMREAD_GRAYSCALE)
ret, dst = cv.threshold(img, 90, 255, cv.THRESH_BINARY)
cv.imshow("img", img)
cv.imshow("dst", dst)
cv.waitKey(0)

2.自适应阈值

由于光照不均匀以及阴影的存在,只有一个阈值会导致阴影处的白色被置为黑色
adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C)
adaptiveMethod:自适应方法,决定如何计算阈值。有两种常见的方法:
cv.ADAPTIVE_THRESH_MEAN_C:阈值是邻域内像素的平均值减去常数C。
cv.ADAPTIVE_THRESH_GAUSSIAN_C:阈值是邻域内像素值的加权和减去常数C,权重通过高斯窗口确定。
blockSize:邻域大小(用于计算阈值的区域大小),必须是奇数。
C:从均值或加权均值中减去的常数,可以是正数或负数。

import cv2 as cv
img = cv.imread("D://dev/opencv/sources/samples/data/squirrel_cls.jpg", cv.IMREAD_GRAYSCALE)
dst = cv.adaptiveThreshold(img, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 3, 0)
cv.imshow("img", img)
cv.imshow("dst", dst)
cv.waitKey(0)

3.获取形态学处理的结构元素

getStructuringElement(shape, ksize)

shape结构元素的形状
cv.MORPH_RECT矩形结构元素
cv.MORPH_ELLIPSE椭圆结构元素
cv.MORPH_CROSS十字形结构元素
import cv2 as cv
kernel = cv.getStructuringElement(cv.MORPH_CROSS, (7, 7))
print(kernel)

4.腐蚀和膨胀

erode(src, kernel, iterations)
dilate(src, kernel, iterations)
iterations:操作的次数,默认是1

# 图片可以选择黑底白字的文字图片,实践一下效果
kernel = np.ones((1, 1), dtype=np.uint8)
dst = cv.erode(src, kernel)

5.形态学高级操作

运算作用结果
开运算去除大图形外的小图形
闭运算去除大图形内的小图形
形态学梯度捕获图形边缘
顶帽运算去除小图形外的大图形
黑帽运算去除蕴含小图形的大图形

开运算可以先利用腐蚀去除噪点,再膨胀恢复
闭运算可以先利用膨胀去掉噪点,再腐蚀恢复
形态学梯度是原图减去腐蚀图片,作用结果是捕获边缘
顶帽运算是原图减去开运算
黑帽运算是原图减去闭运算
morphologyEx(src, op, kernel)

op形态学操作的类型
cv.MORPH_ERODE腐蚀
cv.MORPH_DILATE膨胀
cv.MORPH_OPEN开运算
cv.MORPH_CLOSE闭运算
cv.MORPH_GRADIENT形态学梯度
cv.MORPH_TOPHAT顶帽
cv.MORPH_BLACKHAT黑帽

五、opencv-python轮廓处理

1.查找轮廓

findContours(src, mode, method)

mode轮廓检索模式
cv.RETR_EXTERNAL=0只检索最外层的轮廓
cv.RETR_LIST=1检索所有的轮廓并从里到外,从右到左的顺序保存到列表中
cv.RETR_CCOMP=2每层最多两级
cv.RETR_TREE=3按树形存储轮廓,从右到左,每个里面从外到里
method轮廓近似方法
cv.CHAIN_APPROX_NONE存储所有的轮廓点
cv.CHAIN_APPROX_SIMPLE仅存储角点:水平、垂直和对角线方向上的端点
返回值
contours一个Python列表,其中每个元素都是代表图像中一个轮廓的点集
hierarchy有关图像顶级轮廓、轮廓之间的关系等信息的数组,但在很多应用中通常不使用

2.绘制轮廓

drawContours(src, contours, contoursIdx, color, thickness)

src通常是原始图像的一个深拷贝,以避免修改原始图像
contours由 cv2.findContours 获得
contourIdx指定绘制哪个轮廓的索引,如果要绘制所有轮廓,则将其设置为 -1
color轮廓的颜色
thickness轮廓线条的厚度。如果指定为负数(例如 -1),则轮廓内部将被填充

3.计算轮廓周长和面积

arcLength(curve,closed)
contourArea(contour[index])

import cv2 as cv
import numpy as np
# 绘制一个二值图像作为实例
src = 255 * np.ones((500, 500, 3), dtype=np.uint8)
cv.rectangle(src, (100, 100), (400, 300), (110, 0, 110), -1)
cv.circle(src, (250, 350), 100, (255, 255, 0), -1)
img = src.copy()
# 转为灰度
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# 二值化
ret, bina = cv.threshold(gray, 180, 255, cv.THRESH_BINARY)
# 用二值化图像查找轮廓
contour, hierarchy = cv.findContours(bina, 1, cv.CHAIN_APPROX_NONE)
# 在原图像的深拷贝里绘制轮廓
cv.drawContours(img, contour, -1, (0, 0, 255), 2)
# 计算轮廓周长和面积
area = cv.contourArea(contour[0])
len = cv.arcLength(contour[0], True)

print(f"轮廓的面积为{area}")
print(f"轮廓的周长为{len}")
cv.imshow("img", img)
cv.waitKey(0)

4.多边形逼近和凸包

多边形逼近:就是通过多边形逼近一个给定的形状,用于简化轮廓的表示或进行形状的匹配
多边形凸包:就是包含给定点集中所有点的最小凸多边形,可以找到一个形状的外壳
approxPloyDP(curve, epsilon, closed)
epsilon精度
convexHull(points, clockwise)

5.最小外接矩阵和最小无旋转外接矩阵

minAreaRect(points)
points:ndarray数组,可以是轮廓
返回值:RotatedRect由起始点、宽和高、旋转角度组成
boundingRect(array)
array:ndarray数组,可以是轮廓
返回值:Rect由起始点、宽和高组成

import cv2 as cv
import numpy as np

def drawShape(img_src, points):
    i = 0
    while i < len(points):
        if i == len(points) - 1:
            x, y = points[i][0]
            x1, y1 = points[0][0]
            cv.line(img_src, (x, y), (x1, y1), (0, 0, 255), 2)
        else:
            x, y = points[i][0]
            x1, y1 = points[i+1][0]
            cv.line(img_src, (x, y), (x1, y1), (0, 0, 255), 2)
        i += 1

src = cv.imread(r"D:\dev\opencv\sources\samples\data\hand.png")
img = src.copy()
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
ret, bina = cv.threshold(gray, 180, 255, cv.THRESH_BINARY)
contour, hierarchy = cv.findContours(bina, 1, cv.CHAIN_APPROX_NONE)
cv.drawContours(img, contour[0], -1, (0, 255, 0), 2)
e = 20
# 多边形逼近
approx = cv.approxPolyDP(contour[0], e, True)
# 多边形凸包
hull = cv.convexHull(contour[0])
# 最小外接矩阵和最小无旋转外接矩阵
min_rect = cv.minAreaRect(contour[0])
x, y, w, h = cv.boundingRect(contour[0])
box = cv.boxPoints(min_rect)
box = np.int_(box)
cv.drawContours(img, [box], 0, (0, 255, 255), 2)
cv.rectangle(img, (x, y), (x + w, y + h), (255, 0, 255), 2)

drawShape(img, approx)
drawShape(img, hull)
cv.imshow("img", img)
cv.waitKey(0)

6. 行人识别

import cv2 as cv
# import numpy as np

cap = cv.VideoCapture("D://dev/opencv/sources/samples/data/vtest.avi")
# 去除背景
bgsubmog = cv.createBackgroundSubtractorMOG2()
# 形态学结构元素
kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
while True:
    ret, frame = cap.read()
    if ret:
        # 灰度
        cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
        # 高斯模糊去噪
        blur = cv.GaussianBlur(frame, (3, 3), 5)
        # 去背景
        mask = bgsubmog.apply(blur)
        # 腐蚀
        erode = cv.erode(mask, kernel, 2)
        # 膨胀
        dilate = cv.dilate(erode, kernel, 3)
        # 闭操作去黑点
        close = cv.morphologyEx(dilate, cv.MORPH_CLOSE, kernel)
        # 查找轮廓
        contours, hierachy = cv.findContours(close, cv.RETR_TREE,
                                             cv.CHAIN_APPROX_SIMPLE)
        for (i, c) in enumerate(contours):
            x, y, w, h = cv.boundingRect(c)
            if w < 40 and h < 40:
                continue
            cv.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2)

        cv.imshow("video", frame)

    else:
        break
        print("video failed to load")
    key = cv.waitKey(20)
    # Esc的ASCII是27
    if key & 0xff == 27:
        break

cap.release()
cv.destroyAllWindows()

六、opencv-python特征检测

1.角点检测

Harris角点检测

  • 光滑地区:无论从哪个方向移动,衡量的系数均不变
  • 边缘地区:存在一个方向移动衡量系数不变,而垂直于这个方向剧烈变化
  • 交点处:无论往哪个方向移动,衡量系统都剧烈变化

cornerHarris(src, blockSize, ksize, k)
src:输入图像,应该是灰度图,且数据类型为float32。
blockSize:角点检测中要考虑的领域大小。
ksize:Sobel求导中使用的窗口大小。
k:Harris角点检测方程中的自由参数,取值参数为[0.04,0.06]。

import cv2 as cv

blocksize = 2
ksize = 3
k = 0.04

src = cv.imread(r"D:\dev\opencv\sources\samples\data\chessboard.png")
img = cv.resize(src, None, fx=0.3, fy=0.3)
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
dst = cv.cornerHarris(gray, blocksize, ksize, k)
img[dst > 0.01 * dst.max()] = [0, 0, 255]
cv.imshow("img", img)
cv.waitKey(0)

Shi-Tomasi角点检测

Shi-Tomasi角点检测是Harris角点检测的改进,其角点测算稳定性不会受到经验值k 的影响
goodFeaturesToTrack(image,…)

parameters参数说明
image输入灰度图像,且数据类型通常为 np.uint8 或 np.float32
maxCorners返回的最大角点数目,0表示无限大
qualityLevel角点质量等级,取小于1的正浮点数,一般为0.01~0.1
minDistance角点之间的最小欧氏距离,用于避免检测到相邻的角点
corners可选参数,用于存储检测到的角点位置
mask可选参数,指定一个掩码图像,用于限制角点检测的区域
blockSize角点检测中要考虑的邻域大小
useHarrisDetector默认是False使用Shi-Tomasi角点检测
k使用Harris算法的时候设置
import cv2 as cv
import numpy as np
maxCorners = 1000
ql = 0.01
minDistance = 35

src = cv.imread(r"D:\dev\opencv\sources\samples\data\chessboard.png")
img = cv.resize(src, None, fx=0.3, fy=0.3)
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
corners = cv.goodFeaturesToTrack(gray, maxCorners, ql, minDistance)

corners = np.int_(corners)
for i in corners:
    # 转成一维数组
    x, y = i.ravel()
    cv.circle(img, (x, y), 3, (0, 0, 255), -1)

cv.imshow("img", img)
cv.waitKey(0)

2.关键点检测

SIFT(Scale-Invariant Feature Transform,尺度不变特征变换)

当图像尺度发生变化时,Harris算法可能会在放大或缩小的图片中失效从而检测不出角点,这个时候SIFT就很重要

import cv2 as cv
src = cv.imread(r"D:\dev\opencv\sources\samples\data\chessboard.png")
img = cv.resize(src, None, fx=0.5, fy=0.5)
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 创建SIFT对象
sift = cv.SIFT_create()
# 对整张图进行检测关键点和描述子
keypoints, discriptors = sift.detectAndCompute(gray, None)
cv.drawKeypoints(gray, keypoints, img)

cv.imshow("img", img)
cv.waitKey(0)

SURF(Speeded Up Robust Features,加速鲁棒特征)

改善了SIFT的速度
surf = cv.xfeatures2d.SURF_create()

ORB(Oriented FAST and Rotated BRIEF)

实时检测,但是精度低,适用于大批量实时检测

import cv2 as cv

src = cv.imread(r"D:\dev\opencv\sources\samples\data\chessboard.png")
img = cv.resize(src, None, fx=0.5, fy=0.5)
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 创建ORB对象
orb = cv.ORB_create()
# 对整张图进行检测关键点和描述子
keypoints, discriptors = orb.detectAndCompute(gray, None)
cv.drawKeypoints(gray, keypoints, img)

cv.imshow("img", img)
cv.waitKey(0)

3.特征匹配

BF(Brute-Force,暴力特征匹配)

一张图片的每个关键点描述子与另一张图片每一个描述子进行匹配

import cv2 as cv
img1 = cv.imread(r"D:\dev\opencv\sources\samples\data\opencv-logo-white.png")
img2 = cv.imread(r"D:\dev\opencv\sources\samples\data\opencv-logo.png")
gray1 = cv.cvtColor(img1, cv.COLOR_BGR2GRAY)
gray2 = cv.cvtColor(img2, cv.COLOR_BGR2GRAY)
sift = cv.SIFT_create()

kp1, des1 = sift.detectAndCompute(gray1, None)
kp2, des2 = sift.detectAndCompute(gray2, None)

bf = cv.BFMatcher(cv.NORM_L1)
match = bf.match(des1, des2)
img3 = cv.drawMatches(img1, kp1, img2, kp2, match, None)

cv.imshow("img3", img3)
cv.waitKey(0)

FLANN(Fast Approximate Nearest Neighbor Search Library,最快近邻区特征匹配)

速度更快,精度较差

  • 21
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

阿卡不吃秋葵

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

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

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

打赏作者

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

抵扣说明:

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

余额充值