Python使用Opencv实现图像特征检测与匹配的方法

特征检测是计算机对一张图像中最为明显的特征进行识别检测并将其勾画出来。大多数特征检测都会涉及图像的角点、边和斑点的识别、或者是物体的对称轴。

角点检测 是由Opencv的cornerHarris函数实现,其他函数参数说明如下:

cv2.cornerHarris(src=gray, blockSize=9, ksize=23, k=0.04)
# cornerHarris参数:
# src - 数据类型为 float32 的输入图像。
# blockSize - 角点检测中要考虑的领域大小。
# ksize - Sobel 求导中使用的窗口大小
# k - Harris 角点检测方程中的自由参数,取值参数为 [0,04,0.06].

以国际象棋为例,这是计算机视觉最为常见的分析对象,如图所示:

角点检测代码如下:

import cv2
import numpy as np

img = cv2.imread('chess_board.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# cornerHarris函数图像格式为 float32 ,因此需要将图像转换 float32 类型
gray = np.float32(gray)
# cornerHarris参数:
# src - 数据类型为 float32 的输入图像。
# blockSize - 角点检测中要考虑的领域大小。
# ksize - Sobel 求导中使用的窗口大小
# k - Harris 角点检测方程中的自由参数,取值参数为 [0,04,0.06].
dst = cv2.cornerHarris(src=gray, blockSize=9, ksize=23, k=0.04)
# 变量a的阈值为0.01 * dst.max(),如果dst的图像值大于阈值,那么该图像的像素点设为True,否则为False
# 将图片每个像素点根据变量a的True和False进行赋值处理,赋值处理是将图像角点勾画出来
a = dst>0.01 * dst.max()
img[a] = [0, 0, 255]
# 显示图像
while (True):
 cv2.imshow('corners', img)
 if cv2.waitKey(120) & 0xff == ord("q"):
  break
 cv2.destroyAllWindows()

运行代码,结果如图所示:

但有时候,图像的像素大小对角点存在一定的影响。比如图像越小,角点看上去趋向近似一条直线,这样很容易造成角点的丢失。如果按照上述的检测方法,会造成角点检测结果不相符,因此引入DoG和SIFT算法进行检测Opencv的SIFT类是DoG和SIFT算法组合。

DoG是对同一图像使用不同高斯滤波器所得的结果。

SIFT是通过一个特征向量来描述关键点周围区域的情况。

我们以下图为例:

import cv2
# 读取图片并灰度处理
imgpath = 'varese.jpg'
img = cv2.imread(imgpath)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 创建SIFT对象
sift = cv2.xfeatures2d.SIFT_create()
# 将图片进行SURF计算,并找出角点keypoints,keypoints是检测关键点
# descriptor是描述符,这是图像一种表示方式,可以比较两个图像的关键点描述符,可作为特征匹配的一种方法。
keypoints, descriptor = sift.detectAndCompute(gray, None)

# cv2.drawKeypoints() 函数主要包含五个参数:
# image: 原始图片
# keypoints:从原图中获得的关键点,这也是画图时所用到的数据
# outputimage:输出
# color:颜色设置,通过修改(b,g,r)的值,更改画笔的颜色,b=蓝色,g=绿色,r=红色。
# flags:绘图功能的标识设置,标识如下:
# cv2.DRAW_MATCHES_FLAGS_DEFAULT 默认值
# cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS
# cv2.DRAW_MATCHES_FLAGS_DRAW_OVER_OUTIMG
# cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS
img = cv2.drawKeypoints(image=img, outImage=img, keypoints = keypoints, flags=cv2.DRAW_MATCHES_FLAGS_DEFAULT, color = (51, 163, 236))

# 显示图片
cv2.imshow('sift_keypoints', img)
while (True):
 if cv2.waitKey(120) & 0xff == ord("q"):
  break
cv2.destroyAllWindows()

运行代码,结果如图所示:

除了SIFT算法检测之外,还有SURF特征检测算法,比SIFT算法快,并吸收了SIFT算法的思想。SURF采用Hessian算法检测关键点,而SURF是提取特征,这个与SIFT很像。Opencv的SURF类是Hessian算法和SURF算法组合。我们根据SIFT的代码进行修改,代码如下:

import cv2
# 读取图片并灰度处理
imgpath = 'varese.jpg'
img = cv2.imread(imgpath)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 创建SURF对象,对象参数float(4000)为阈值,阈值越高,识别的特征越小。
sift = cv2.xfeatures2d.SURF_create(float(4000))
# 将图片进行SURF计算,并找出角点keypoints,keypoints是检测关键点
# descriptor是描述符,这是图像一种表示方式,可以比较两个图像的关键点描述符,可作为特征匹配的一种方法。
keypoints, descriptor = sift.detectAndCompute(gray, None)

# cv2.drawKeypoints() 函数主要包含五个参数:
# image: 原始图片
# keypoints:从原图中获得的关键点,这也是画图时所用到的数据
# outputimage:输出
# color:颜色设置,通过修改(b,g,r)的值,更改画笔的颜色,b=蓝色,g=绿色,r=红色。
# flags:绘图功能的标识设置,标识如下:
# cv2.DRAW_MATCHES_FLAGS_DEFAULT 默认值
# cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS
# cv2.DRAW_MATCHES_FLAGS_DRAW_OVER_OUTIMG
# cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS
img = cv2.drawKeypoints(image=img, outImage=img, keypoints = keypoints, flags=cv2.DRAW_MATCHES_FLAGS_DEFAULT, color = (51, 163, 236))

# 显示图片
cv2.imshow('sift_keypoints', img)
while (True):
 if cv2.waitKey(120) & 0xff == ord("q"):
  break
cv2.destroyAllWindows()

上述代码我们只修改sift = cv2.xfeatures2d.SURF_create(float(4000))即可实现SURF特征检测算法。运行结果如图所示:

对比SURF和SIFT算法,ORB算法更处于起步阶段,在2011年才首次发布。但比前两者的速度更快。ORB基于FAST关键点检测和BRIEF的描述符技术相结合,因此我们先了解FAST和BRIEF。

FAST:特征检测算法。

BRIEF:只是一个描述符,这是图像一种表示方式,可以比较两个图像的关键点描述符,可作为特征匹配的一种方法。

暴力匹配:比较两个描述符并产生匹配结果。

在上述的例子中,我们只是将检测的关键点进行勾画,在这例子中,将使用ORB检测关键点之外,还将两图进行匹配,匹配的图像如下:

实现方法:首先分别对两图进行ORB处理,然后将两图的关键点进行暴力匹配。具体代码如下:

# ORB算法实现特征检测+暴力匹配

import numpy as np
import cv2
from matplotlib import pyplot as plt

# 读取图片内容
img1 = cv2.imread('aa.jpg',0)
img2 = cv2.imread('bb.png',0)

# 使用ORB特征检测器和描述符,计算关键点和描述符
orb = cv2.ORB_create()
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)

# 暴力匹配BFMatcher,遍历描述符,确定描述符是否匹配,然后计算匹配距离并排序
# BFMatcher函数参数:
# normType:NORM_L1, NORM_L2, NORM_HAMMING, NORM_HAMMING2。
# NORM_L1和NORM_L2是SIFT和SURF描述符的优先选择,NORM_HAMMING和NORM_HAMMING2是用于ORB算法
bf = cv2.BFMatcher(normType=cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(des1,des2)
matches = sorted(matches, key = lambda x:x.distance)
# matches是DMatch对象,具有以下属性:
# DMatch.distance - 描述符之间的距离。 越低越好。
# DMatch.trainIdx - 训练描述符中描述符的索引
# DMatch.queryIdx - 查询描述符中描述符的索引
# DMatch.imgIdx - 训练图像的索引。

# 使用plt将两个图像的匹配结果显示出来
img3 = cv2.drawMatches(img1=img1,keypoints1=kp1,img2=img2,keypoints2=kp2, matches1to2=matches, outImg=img2, flags=2)
plt.imshow(img3),plt.show()

运行结果如图所示:

# SURF和SIFT算法+暴力匹配

暴力匹配BFMatcher是一种匹配方法,只要提供两个关键点即可实现匹配。若将上述例子改为SURF和SIFT算法,只需修改以下代码:

将orb = cv2.ORB_create()改为
orb = cv2.xfeatures2d.SURF_create(float(4000))

将bf = cv2.BFMatcher(normType=cv2.NORM_HAMMING, crossCheck=True)改为
bf = cv2.BFMatcher(normType=cv2.NORM_L1, crossCheck=True)

# 获取匹配关键点的坐标位置

在上述例子中,matches是DMatch对象,DMatch是以列表的形式表示,每个元素代表两图能匹配得上的点。如果想获取某个点的坐标位置,在上述例子添加以下代码:

# 由于匹配顺序是:matches = bf.match(des1,des2),先des1后des2。
# 因此,kp1的索引由DMatch对象属性为queryIdx决定,kp2的索引由DMatch对象属性为trainIdx决定

# 获取aa.jpg的关键点位置
x,y = kp1[matches[0].queryIdx].pt
cv2.rectangle(img1, (int(x),int(y)), (int(x) + 5, int(y) + 5), (0, 255, 0), 2)
cv2.imshow('a', img1)

# 获取bb.png的关键点位置
x,y = kp2[matches[0].trainIdx].pt
cv2.rectangle(img2, (int(x1),int(y1)), (int(x1) + 5, int(y1) + 5), (0, 255, 0), 2)
cv2.imshow('b', img2)

# 使用plt将两个图像的第一个匹配结果显示出来
img3 = cv2.drawMatches(img1=img1,keypoints1=kp1,img2=img2,keypoints2=kp2, matches1to2=matches[:1], outImg=img2, flags=2)
plt.imshow(img3),plt.show()

运行结果如图所示:

上述讲到的暴力匹配是使用BFMatcher匹配器实现的,然后由match函数实现匹配。接下来讲解K-最近邻匹配(KNN),并在BFMatcher匹配下实现。在所有机器学习的算法中,KNN可能是最为简单的算法。针对上述例子,改为KNN匹配,实现代码如下:

import numpy as np
import cv2
from matplotlib import pyplot as plt

# 读取图片内容
img1 = cv2.imread('aa.jpg',0)
img2 = cv2.imread('bb.png',0)

# 使用ORB特征检测器和描述符,计算关键点和描述符
orb = cv2.ORB_create()
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)

# 暴力匹配BFMatcher,遍历描述符,确定描述符是否匹配,然后计算匹配距离并排序
# BFMatcher函数参数:
# normType:NORM_L1, NORM_L2, NORM_HAMMING, NORM_HAMMING2。
# NORM_L1和NORM_L2是SIFT和SURF描述符的优先选择,NORM_HAMMING和NORM_HAMMING2是用于ORB算法
bf = cv2.BFMatcher(normType=cv2.NORM_HAMMING, crossCheck=True)
# knnMatch 函数参数k是返回符合匹配的个数,暴力匹配match只返回最佳匹配结果。
matches = bf.knnMatch(des1,des2,k=1)

# 使用plt将两个图像的第一个匹配结果显示出来
# 若使用knnMatch进行匹配,则需要使用drawMatchesKnn函数将结果显示
img3 = cv2.drawMatchesKnn(img1=img1,keypoints1=kp1,img2=img2,keypoints2=kp2, matches1to2=matches, outImg=img2, flags=2)
plt.imshow(img3),plt.show()

最后是介绍FLANN匹配,相对暴力匹配BFMatcher来讲,这匹配算法比较准确、快速和使用方便。FLANN具有一种内部机制,可以根据数据本身选择最合适的算法来处理数据集。值得注意的是,FLANN匹配器只能使用SURF和SIFT算法。
FLANN实现方式如下:

import numpy as np
import cv2
from matplotlib import pyplot as plt

queryImage = cv2.imread('aa.jpg',0)
trainingImage = cv2.imread('bb.png',0)

# 只使用SIFT 或 SURF 检测角点
sift = cv2.xfeatures2d.SIFT_create()
# sift = cv2.xfeatures2d.SURF_create(float(4000))
kp1, des1 = sift.detectAndCompute(queryImage,None)
kp2, des2 = sift.detectAndCompute(trainingImage,None)

# 设置FLANN匹配器参数
# algorithm设置可参考https://docs.opencv.org/3.1.0/dc/d8c/namespacecvflann.html
indexParams = dict(algorithm=0, trees=5)
searchParams = dict(checks=50)
# 定义FLANN匹配器
flann = cv2.FlannBasedMatcher(indexParams,searchParams)
# 使用 KNN 算法实现匹配
matches = flann.knnMatch(des1,des2,k=2)

# 根据matches生成相同长度的matchesMask列表,列表元素为[0,0]
matchesMask = [[0,0] for i in range(len(matches))]

# 去除错误匹配
for i,(m,n) in enumerate(matches):
  if m.distance < 0.7*n.distance:
    matchesMask[i] = [1,0]

# 将图像显示
# matchColor是两图的匹配连接线,连接线与matchesMask相关
# singlePointColor是勾画关键点
drawParams = dict(matchColor = (0,255,0),
          singlePointColor = (255,0,0),
          matchesMask = matchesMask,
          flags = 0)
resultImage = cv2.drawMatchesKnn(queryImage,kp1,trainingImage,kp2,matches,None,**drawParams)
plt.imshow(resultImage,),plt.show()

运行结果如图所示:

FLANN的单应性匹配,单应性是一个条件,该条件表面当两幅图像中的一副出像投影畸变时,他们还能匹配。FLANN的单应性实现代码如下:

import numpy as np
import cv2
from matplotlib import pyplot as plt

MIN_MATCH_COUNT = 10

img1 = cv2.imread('tattoo_seed.jpg',0)
img2 = cv2.imread('hush.jpg',0)

# 使用SIFT检测角点
sift = cv2.xfeatures2d.SIFT_create()
# 获取关键点和描述符
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)

# 定义FLANN匹配器
index_params = dict(algorithm = 1, trees = 5)
search_params = dict(checks = 50)
flann = cv2.FlannBasedMatcher(index_params, search_params)
# 使用KNN算法匹配
matches = flann.knnMatch(des1,des2,k=2)

# 去除错误匹配
good = []
for m,n in matches:
  if m.distance < 0.7*n.distance:
    good.append(m)

# 单应性
if len(good)>MIN_MATCH_COUNT:
  # 改变数组的表现形式,不改变数据内容,数据内容是每个关键点的坐标位置
  src_pts = np.float32([ kp1[m.queryIdx].pt for m in good ]).reshape(-1,1,2)
  dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good ]).reshape(-1,1,2)
  # findHomography 函数是计算变换矩阵
  # 参数cv2.RANSAC是使用RANSAC算法寻找一个最佳单应性矩阵H,即返回值M
  # 返回值:M 为变换矩阵,mask是掩模
  M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0)
  # ravel方法将数据降维处理,最后并转换成列表格式
  matchesMask = mask.ravel().tolist()
  # 获取img1的图像尺寸
  h,w = img1.shape
  # pts是图像img1的四个顶点
  pts = np.float32([[0,0],[0,h-1],[w-1,h-1],[w-1,0]]).reshape(-1,1,2)
  # 计算变换后的四个顶点坐标位置
  dst = cv2.perspectiveTransform(pts,M)

  # 根据四个顶点坐标位置在img2图像画出变换后的边框
  img2 = cv2.polylines(img2,[np.int32(dst)],True,(255,0,0),3, cv2.LINE_AA)

else:
  print("Not enough matches are found - %d/%d") % (len(good),MIN_MATCH_COUNT)
  matchesMask = None

# 显示匹配结果
draw_params = dict(matchColor = (0,255,0), # draw matches in green color
          singlePointColor = None,
          matchesMask = matchesMask, # draw only inliers
          flags = 2)
img3 = cv2.drawMatches(img1,kp1,img2,kp2,good,None,**draw_params)
plt.imshow(img3, 'gray'),plt.show()

运行结果如下所示:

单应性实际应用

从上述的例子可以看到,单应性是在两图片匹配的时候,其中某一图片发生变换处理,变换后图像会呈现一种立体空间的视觉效果,图像发生变换程度称为变换矩阵。以下例子将图像中的书本替换成其他书本,例子中所使用图片如下:

我们根据图1和图2计算变换矩阵,然后通过变换矩阵将图3进行变换,最后将图3加入到图1中,实现图片替换。实现代码如下:

import numpy as np
import cv2
from matplotlib import pyplot as plt

img1 = cv2.imread('logo.jpg',0)
img2 = cv2.imread('book.jpg',0)

# 使用SIFT检测角点
sift = cv2.xfeatures2d.SIFT_create()
# 获取关键点和描述符
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)

# 定义FLANN匹配器
index_params = dict(algorithm = 1, trees = 5)
search_params = dict(checks = 50)
flann = cv2.FlannBasedMatcher(index_params, search_params)
# 使用KNN算法匹配
matches = flann.knnMatch(des1,des2,k=2)

# 去除错误匹配
good = []
for m,n in matches:
  if m.distance < 0.7*n.distance:
    good.append(m)

# 单应性实际应用
# 改变数组的表现形式,不改变数据内容,数据内容是每个关键点的坐标位置
src_pts = np.float32([ kp1[m.queryIdx].pt for m in good ]).reshape(-1,1,2)
dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good ]).reshape(-1,1,2)
# findHomography 函数是计算变换矩阵
# 参数cv2.RANSAC是使用RANSAC算法寻找一个最佳单应性矩阵H,即返回值M
# 返回值:M 为变换矩阵,mask是掩模
M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0)
# 获取img1的图像尺寸
h,w = img1.shape
# pts是图像img1的四个顶点
pts = np.float32([[0,0],[0,h-1],[w-1,h-1],[w-1,0]]).reshape(-1,1,2)
# 计算变换后的四个顶点坐标位置
dst = cv2.perspectiveTransform(pts,M)

# 图片替换
img3 = cv2.imread('aa.png',0)
# 降维处理
b = np.int32(dst).reshape(4, 2)
x,y = img2.shape
# 根据变换矩阵将图像img3进行变换处理
res = cv2.warpPerspective(img3, M, (y,x))
img_temp = img2.copy()
# 将图像img2的替换区域进行填充处理
cv2.fillConvexPoly(img_temp, b, 0)
# 将变换后的img3图像替换到图像img2
cv2.imshow('bb',img_temp)
res = img_temp + res
cv2.imshow('aa',res)
plt.imshow(res),plt.show()

运行结果如图所示:

从结果可以看到,替换后的图像周边出现黑色线条,这是正常的现象。在上图最左边的图bb可以看到,黑色区域是由图1和图2检测匹配所得的结果,如果匹配结果会存在一定的误差,这个误差是由多个因素所导致的。

在实际中,我们根据一张图片在众多的图片中查找匹配率最高的图片。如果按照上面的例子,也可以实现,但每次匹配时都需要重新检测图片的特征数据,这样会导致程序运行效率。因此,我们可以将图片的特征数据进行保存,每次匹配时,只需读取特征数据进行匹配即可。我们以下图为例:

我们根据图1在图2中查找最佳匹配的图片。首先获取图2的全部图片的特征数据,将代码保存在features.py:

import cv2
import numpy as np
from os import walk
from os.path import join

def create_descriptors(folder):
  files = []
  for (dirpath, dirnames, filenames) in walk(folder):
    files.extend(filenames)
  for f in files:
    if '.jpg' in f:
      save_descriptor(folder, f, cv2.xfeatures2d.SIFT_create())

def save_descriptor(folder, image_path, feature_detector):
  # 判断图片是否为npy格式
  if image_path.endswith("npy"):
    return
  # 读取图片并检查特征
  img = cv2.imread(join(folder,image_path), 0)
  keypoints, descriptors = feature_detector.detectAndCompute(img, None)
  # 设置文件名并将特征数据保存到npy文件
  descriptor_file = image_path.replace("jpg", "npy")
  np.save(join(folder, descriptor_file), descriptors)

if __name__=='__main__':
  path = 'E:\\anchors'
  create_descriptors(path)

运行代码,结果如图所示:

我们将图片的特征数据保存在npy文件。下一步是根据图1与这些特征数据文件进行匹配,从而找出最佳匹配的图片。代码存在matching.py:

from os.path import join
from os import walk
import numpy as np
import cv2

query = cv2.imread('tattoo_seed.jpg', 0)
folder = 'E:\\anchors'
descriptors = []
# 获取特征数据文件名
for (dirpath, dirnames, filenames) in walk(folder):
  for f in filenames:
    if f.endswith("npy"):
      descriptors.append(f)
  print(descriptors)

# 使用SIFT算法检查图像的关键点和描述符
sift = cv2.xfeatures2d.SIFT_create()
query_kp, query_ds = sift.detectAndCompute(query, None)

# 创建FLANN匹配器
index_params = dict(algorithm=0, trees=5)
search_params = dict(checks=50)
flann = cv2.FlannBasedMatcher(index_params, search_params)

potential_culprits = {}
for d in descriptors:
  # 将图像query与特征数据文件的数据进行匹配
  matches = flann.knnMatch(query_ds, np.load(join(folder, d)), k=2)
  # 清除错误匹配
  good = []
  for m, n in matches:
    if m.distance < 0.7 * n.distance:
      good.append(m)
  # 输出每张图片与目标图片的匹配数目
  print("img is %s ! matching rate is (%d)" % (d, len(good)))
  potential_culprits[d] = len(good)

# 获取最多匹配数目的图片
max_matches = None
potential_suspect = None
for culprit, matches in potential_culprits.items():
  if max_matches == None or matches > max_matches:
    max_matches = matches
    potential_suspect = culprit

print("potential suspect is %s" % potential_suspect.replace("npy", "").upper())

代码运行后,输出结果如图所示:

从输出的结果可以看到,图1与图2的hush.jpg最为匹配,如图所示:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 使用Python和OpenCV检测图像中的物体并将物体裁剪下来

    介绍 硕士阶段的毕设是关于昆虫图像分类的,代码写到一半,上周五导师又给我新的昆虫图片数据集了,新图片中很多图片很大,但是图片中的昆虫却很小,所以我就想着先处理一下图片,把图片中的昆虫裁剪下来,这样除去大部分无关背景,应该可以提高识别率. 原图片举例(将红色矩形框部分裁剪出来)): step1:加载图片,转成灰度图 image = cv2.imread("353.jpg") gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) step2:用Sob

  • OpenCV实现图像轮廓检测以及外接矩形

    前两篇博文分别介绍了图像的边缘检测和轮廓检测,本文接着介绍图像的轮廓检测和轮廓外接矩形: 一.代码部分: // extract_contours.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<cv.h> #include<highgui.h> using namespace cv; using namespace std; int _tmain(int argc, _TCHAR* argv[]) { /

  • OpenCV实现图像的直线检测

    上一篇博文介绍了图像的Canny边缘检测,本文主要介绍图像的直线检测部分,主要使用概率霍夫变换来检测直线,调用的函数为HoughLinesP(),下面给出代码部分以及直线检测效果图: 1.代码部分: // Detect_Lines.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <cv.h> #include "highgui.h" using namespace std; using names

  • opencv python 图像轮廓/检测轮廓/绘制轮廓的方法

    图像的轮廓检测,如计算多边形外界.形状毕竟.计算感兴趣区域等. Contours : Getting Started 轮廓 简单地解释为连接所有连续点(沿着边界)的曲线,具有相同的颜色或强度. 轮廓是形状分析和物体检测和识别的有用工具 NOTE 为获得更好的准确性,请使用二值图,在找到轮廓之前,应用阈值法或canny边缘检测 从OpenCV 3.2开始,findContours()不再修改源图像,而是将修改后的图像作为三个返回参数中的第一个返回 在OpenCV中,查找轮廓是从黑色背景中查找白色对

  • python opencv实现图像边缘检测

    本文利用python opencv进行图像的边缘检测,一般要经过如下几个步骤: 1.去噪 如cv2.GaussianBlur()等函数: 2.计算图像梯度 图像梯度表达的是各个像素点之间,像素值大小的变化幅度大小,变化较大,则可以认为是出于边缘位置,最多可简化为如下形式: 3.非极大值抑制 在获得梯度的方向和大小之后,应该对整幅图像做一个扫描,去除那些非边界上的点.对每一个像素进行检查,看这个点的梯度是不是周围具有相同梯度方向的点中最大的.如下图所示: 4.滞后阈值 现在要确定那些边界才是真正的

  • OpenCV实现图像角点检测

    历时一个多月,于今天上午终于将项目交上去了,这期间虽很辛苦,但是成长了不少,在此将项目中涉及到的知识点进行整理,本文主要介绍图像的角点检测: 一.代码部分: // Detect_Corners.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include "opencv2/opencv.hpp" #include <opencv2/imgproc/imgproc.hpp> #include <iostre

  • OpenCV实现图像边缘检测

    最近自己在做一个有关图像处理的小项目,涉及到图像的边缘检测.直线检测.轮廓检测以及角点检测等,本文首先介绍图像的边缘检测,使用的是Canny边缘检测算法,具体代码以及检测效果如下: 1.代码部分: // Image_Canny.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <cv.h> #include "highgui.h" using namespace cv; int _tmain(int

  • Python使用Opencv实现图像特征检测与匹配的方法

    特征检测是计算机对一张图像中最为明显的特征进行识别检测并将其勾画出来.大多数特征检测都会涉及图像的角点.边和斑点的识别.或者是物体的对称轴. 角点检测 是由Opencv的cornerHarris函数实现,其他函数参数说明如下: cv2.cornerHarris(src=gray, blockSize=9, ksize=23, k=0.04) # cornerHarris参数: # src - 数据类型为 float32 的输入图像. # blockSize - 角点检测中要考虑的领域大小. #

  • Python和OpenCV进行多尺度模板匹配实现

    目录 1. 效果图 2. 原理 3. 步骤 4. 源码 5. 参考 这篇博文将实现如何将标准模板匹配扩展到多尺度,从而使其更加健壮.使其可以处理模板和输入图像大小不同的匹配. 1. 效果图 模板匹配问题:对于模板和图像中不一致的情况,会发生错误检测. 如下图左侧模板小,右侧图像中大,虽然完全一致,只是大小不一样,却未被检测到. 优化:多尺度模板匹配,对于模板和图像中有平移和缩放的情况可以完美工作. 如下图: 多尺度模板匹配,gif 详细效果图: 2. 原理 使用cv2.matchTemplate

  • 基于Python和openCV实现图像的全景拼接详细步骤

    基本介绍 图像的全景拼接,即"缝合"两张具有重叠区域的图来创建一张全景图.其中用到了计算机视觉和图像处理技术有:关键点检测.局部不变特征.关键点匹配.RANSAC(Random Sample Consensus,随机采样一致性)和透视变形. 具体步骤 (1)检测左右两张图像的SIFT关键特征点,并提取局部不变特征 : (2)使用knnMatch检测来自右图(左图)的SIFT特征,与左图(右图)进行匹配 : (3)计算视角变换矩阵H,用变换矩阵H对右图进行扭曲变换: (4)将左图(右图)

  • Python OpenCV中的drawMatches()关键匹配绘制方法

    目录 作用说明 函数原型 参数详解 结果 作用说明 该方法被用于绘制关键点的匹配情况.我们看到的许多匹配结果都是使用这一方法绘制的——一左一右两张图像,匹配的关键点之间用线条链接. 函数原型 cv.drawMatches( img1, keypoints1, img2, keypoints2, matches1to2, outImg[, matchColor[, singlePointColor[, matchesMask[, flags]]]]) -> outImg cv.drawMatche

  • Python基于opencv的图像压缩算法实例分析

    本文实例讲述了Python基于opencv的图像压缩算法.分享给大家供大家参考,具体如下: 插值方法: CV_INTER_NN - 最近邻插值, CV_INTER_LINEAR - 双线性插值 (缺省使用) CV_INTER_AREA - 使用象素关系重采样.当图像缩小时候,该方法可以避免波纹出现.当图像放大时,类似于 CV_INTER_NN 方法.. CV_INTER_CUBIC - 立方插值. 函数 cvResize 将图像 src 改变尺寸得到与 dst 同样大小.若设定 ROI,函数将按

  • python使用opencv resize图像不进行插值的操作

    如下所示: def resize(src, dsize, dst=None, fx=None, fy=None, interpolation=None): 如果使用vanilla resize,不改变默认参数,就会对原图像进行插值操作.不关你是扩大还是缩小图片,都会通过插值产生新的像素值. 对于语义分割,target的处理,如果是对他进行resize操作的话.就希望不产生新的像素值,因为他的颜色信息,代表了像素的类别信息. 但是我们有时候希望resize之后不产生新的像素值,而是产生利用最近邻点

  • python 利用opencv实现图像网络传输

    本代码主要实现的是利用网络传输图片,用在我的树莓派项目之上.该项目在PC上运行服务端,树莓派上运行客户端,两者连接到同一局域网中,修改代码中的IP地址,就可以实现将树莓派采集到的图像数据实时传输到PC端.先运行服务端代码,然后运行客户端代码即可.树莓派摄像头使用的是普通的USB摄像头,并且在树莓派上安装了opencv,在树莓派上安装opencv的过程可以参考https://www.pyimagesearch.com/2017/09/04/raspbian-stretch-install-open

  • python 用opencv实现图像修复和图像金字塔

    我们将学习如何通过一种称为修复的方法去除旧照片中的小噪音,笔画等.基本思路很简单:用相邻像素替换那些坏标记,使其看起来像邻域. cv2.inpaint() cv2.INPAINT_TELEA cv2.INPAINT_NS import numpy as np import cv2 as cv img = cv.imread('messi_2.jpg') mask = cv.imread('mask2.png',0) dst = cv.inpaint(img,mask,3,cv.INPAINT_T

  • python 基于opencv 绘制图像轮廓

    图像轮廓概念 轮廓是一系列相连的点组成的曲线,代表了物体的基本外形. 谈起轮廓不免想到边缘,它们确实很像.简单的说,轮廓是连续的,边缘并不全都连续(下图).其实边缘主要是作为图像的特征使用,比如可以用边缘特征可以区分脸和手:而轮廓主要用来分析物体的形态,比如物体的周长和面积等,可以说边缘包括轮廓. 寻找轮廓的操作一般用于二值图像,所以通常会使用阈值分割或Canny边缘检测先得到二值图. 注意:寻找轮廓是针对白色物体的,一定要保证物体是白色,而背景是黑色,不然很多人在寻找轮廓时会找到图片最外面的一

  • python基于opencv 实现图像时钟

    解决方案详解 绘制表盘 表盘上只有60条分/秒刻线和12条小时刻线,当然还有表盘的外部轮廓圆,也就是重点在如何画72根线.先把简单的圆画出来: import cv2 as cv import math import datetime import numpy as np margin = 5 # 上下左右边距 radius = 220 # 圆的半径 center = (center_x, center_y) = (225, 225) # 圆心 # 1. 新建一个画板并填充成白色 img = np

随机推荐