计算机视觉opencv之图像透视转换&角点检测&sift特征检测&指纹识别

一、图像透视转换

对该发票图像进行处理,只识别这个发票

1.函数设置

python 复制代码
import numpy as np
import  cv2

def cv_show(name,img):
    cv2.imshow(name,img)
    cv2.waitKey(0)

将给定的4个点(通常是从图像中检测到的四边形角点)按固定顺序排列,这里为什么不直接用x和y的值对比是因为当图片不是平行于xy的时候可能会出现排序的其他情况,这里使用x和y的相加和相减,适用于不是很严重的扭曲的四边形,而不知服务于这一张图片。

x+y左上是最小的,y-x右上是最小的,x+y右下是最大的,y-x左下是最大的

python 复制代码
def order_points(pts):
    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

图像透视变换 cv2.getPerspectiveTransform(src,dst[,solveMethod]) MP获得转换之间的关系

src:变换前图像四边形顶点坐标

dst:变换后图像四边形顶点坐标

cv2.warpPerspective(src, MP, dsizel, dst[, flags[, borderNode[, borderValue]]]]) dst

参数说明:

  • src:原图
  • MP:透视变换矩阵,3行3列
  • dsize:输出图像的大小,二元元组(width,height)
python 复制代码
def four_point_transform(image, pts):
    # 获取输入坐标点,把四个点进行排序左上,右上,右下,左下
    rect = order_points(pts)
    #计算原始四边形的宽和高(也许不是矩形,所以宽高两边不一定相等)
    (tl, tr, br, bl) = rect
    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")#左下
    #计算透视变换矩阵
    M = cv2.getPerspectiveTransform(rect, dst)
    #应用变换
    warped = cv2.warpPerspective(image, M,(maxWidth, maxHeight))
    return warped

将图像中倾斜、扭曲的四边形区域(如倾斜拍摄的文档、车牌、票据等)转换为正面的矩形视图

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 image
    if 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)    #默认为cv2.INTER_AREA,即面积插值,适用于缩放图像。
    return resized
python 复制代码
#读取输入
image=cv2.imread('fapiao.jpg')
# cv_show('image',image)

#图片过大,进行缩小处理
radio=image.shape[0]/500#计算缩小比率
orig=image.copy()
image=resize(orig,height=500)
# cv_show('1',image)
python 复制代码
#轮廓检测
print('step1:轮廓检测')
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('step2:最大轮廓获取')
screencnt=sorted(cnts,key=cv2.contourArea,reverse=True)[0]#获取面积最大的轮廓
print(screencnt.shape)
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)

cv2.namedWindow( 'xx2',cv2.WINDOW_NORMAL),能让窗口能放大拉小

python 复制代码
warped = four_point_transform(orig, screencnt.reshape(4, 2) * radio)
cv2.namedWindow( 'xx2',cv2.WINDOW_NORMAL)
# cv2.imshow("xx1", warped3)
cv2.imshow("xx2", warped)
cv2.waitKey(0)

输出结果:

想要更清晰的结果,可以对该图片继续处理,二值化,腐蚀等......,也可以用图片旋转把他旋转正(这里我们需要注意,如果我们想让文字变粗,该图片二值化之后是白底黑字,用的是腐蚀,因为腐蚀是让黑色区域变大,如果我们二值化的时候就把黑白颠倒,使得图片是黑底白字,就要用膨胀,因为膨胀是让白色区域更大)

二、角点检测

角点指图像中局部区域与周围区域有较大灰度变化的点或像素。不仅限于上下有较大变化,左右也有很大变化的时候才是角点。

eg:左上图上下时候有明显改变,但左右平移的时候颜色就没有明显改变的,无角点

左下图,左右有明显改变,但上下没有,所以无角点

右图中1到3有明显改变,1到2也有明显改变,那么1中有角点

cornerHarris(img, blockSize, ksize, k[, dst[, borderType]]) -> dst

  • img:输入图像。
  • blockSize:角点检测中要考虑的领域大小。
  • ksize:Sobel求导中使用的窗口大小。
  • k:Harris角点检测方程中的自由参数,取值参数为[0.04,0.06]。
  • dst:返回numpy.ndarray对象,大小和src相同,值越大,对应像素点是角的概率越高
python 复制代码
import cv2

img=cv2.imread(r"D:\project\whitex.jpg")
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
dst=cv2.cornerHarris(gray,4,3,0.04)#blocksize,ksize,k
#标记检测到的角点
#这里通过对角点响应进行阈值处理,标记出检测到的角点。
#0.05*dst.max()是一个阈值,大于这个值的像素点会被标记为红色。
img[dst>0.01*dst.max()]=[0,255,255]#超过最大值的百分之五就被划为角点
cv2.namedWindow( 'img',cv2.WINDOW_NORMAL)
cv2.imshow('img',img)
cv2.waitKey(0)

三、sift特征检测

检测图像中的关键点

  • cv2.SIFT_create()
  • cv2.xfeatures2d.SIFT_create()创建一个sift特征的提取对象
  • sift.detect(img)在图像中查找关键点

kp:

  • kp.pt:关键点的(x,y) 坐标。
  • kp.size:关键点的大小(尺度).
  • kp.angle:关键点的方向.
  • kp.response:关键点的响应值。
  • kp.0ctave:关键点所在的金字塔层级.

查找关键点

  • drawkeypoints(image, keypoints, outImage, color=None, flags=None)
  • image:原始图片 keypoints:从原图中获得的关键点,这也是画图时所用到的数据
  • outpytimag:输出图像,可以是原始图片,也可以是None color:颜色设置,通过修改(b,9,r)的值,更改画笔的颜色,b=蓝色,g=绿色,r=红色。
  • flags:绘图功能的标识设置,绘制富有信息的关键点。
python 复制代码
import cv2
import numpy as np
img=cv2.imread("qqqqss.jpg")
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
sift=cv2.SIFT_create()#sift对象
kp=sift.detect(gray)
gray=cv2.drawKeypoints(img,kp,None,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow('gray',gray)
cv2.waitKey(0)
#使用sift.compute()计算关键点描述符,方便后期的特征匹配
kp,des=sift.compute(img,kp)
print(np.array(kp).shape,des.shape)
#输出关键点的形状和描述符的形状。
# np.array(kp).shape表示关键点的数量和属性。
#des.shape表示描述符的数量和属性。

四、指纹识别

python 复制代码
import cv2
def cv_show(name,img):
    cv2.imshow(name,img)
    cv2.waitKey(0)
python 复制代码
def verification(src,model):
    sift=cv2.SIFT_create()#创建sift特征提取器
    # 检测关键点和计算描述符(特征向量)源图像
    kp1,des1=sift.detectAndCompute(src,None)
    # 检测关键点和计算描述符(特征向量)模板图像
    kp2,des2=sift.detectAndCompute(model,None)
    #创建flann匹配器
    flann=cv2.FlannBasedMatcher()
    #使用k近邻匹配(des1中的每个描述符与des2中的最近链各个描述符进行匹配
    matches=flann.knnMatch(des1,des2,k=2)
    #distance:匹配的特征点描述符的欧式距离,数值越小也就越说明两个特征点越相近
    #queryidx:测试图像的特征点描述符的下标(第几个特征点描述符),同时也是描述对应特征点的下标
    #trainidx:样本图像的特征点描述符下标,同时也是描述符对应特征点的下标
    #进行比较筛选
    ok=[]
    for m,n in matches:
        #根据lowe比率测试:选择最佳匹配
        if m.distance<0.4*n.distance:#值越小越严格
            ok.append((m,n))
    num=len(ok)#统计通过筛选匹配的数量
    if num >=50:#共同点设置标准,多少为成功,是可以调整的,要根据上面数值进行设置
        result='认证通过'
    else:
        result='认证失败'
    return  result
python 复制代码
if __name__=='__main__':
    src1=cv2.imread('zhiwen1.bmp')
    src2=cv2.imread('zhiwen2.bmp')
    model = cv2.imread('zhiwen_model.bmp')
    cv2.imshow('src1',src1)
    cv2.imshow('src2',src2)
    cv2.imshow('model',model)
    cv2.waitKey(0)

    reselt1=verification(src1,model)
    reselt2=verification(src2,model)


    print('src1的结果为:',reselt1)
    print('src2的结果为:',reselt2)

这里能进行识别,但是没有展示出指纹那些点匹配上了,如果要展示哪些点匹配上了我们需要修改函数verification

python 复制代码
def verification(src,model,show_matchs=False):
    sift=cv2.SIFT_create()#创建sift特征提取器
    kp1,des1=sift.detectAndCompute(src,None)
    kp2,des2=sift.detectAndCompute(model,None)
    flann=cv2.FlannBasedMatcher()
    matches=flann.knnMatch(des1,des2,k=2)
    ok=[]
    src_matches=[]
    model_matches=[]
    for m,n in matches:#m是最佳匹配,n为次家匹配
        if m.distance<0.4*n.distance:
            ok.append((m,n))
            src_matches.append(kp1[m.queryIdx].pt)#测试图像中匹配点的坐标
            model_matches.append(kp2[m.trainIdx].pt)#模版图像中的匹配点坐标
    num=len(ok)
    if num >=50:
        result='认证通过'
    else:
        result='认证失败'
    if show_matchs and len(src_matches)>0:#复制图像,避免修改原图
        src_with_matches=src.copy()
        model_with_matches=model.copy()
        for (x,y) in src_matches[:100]:#在测试图像上绘制匹配点
            cv2.circle(src_with_matches,(int(x),int(y)),3,(0,0,255),-1)
        for (x,y) in model_matches[:100]:#在模版图上绘制匹配点
            cv2.circle(model_with_matches,(int(x),int(y)),3,(0,0,255),-1)
        cv2.imshow('src_matches',src_with_matches)
        cv2.imshow('model_matches',model_with_matches)
        cv2.waitKey(0)
    return  result,num,src_matches,model_matches

最后主函数中修改:

python 复制代码
    reselt1,num1,src1_matches,model1_matches=verification(src1,model,show_matchs=True)
    reselt2,num2,src2_matches,model2_matches=verification(src2,model,show_matchs=True)

    print('src1的结果为:',reselt1,'匹配点数:{}'.format(num1))
    print('src2的结果为:',reselt2,'匹配点数:{}'.format(num2))
相关推荐
2501_944332161 小时前
如何联系北京的金融业务流程外包服务商?
大数据·人工智能·金融
m0_466525291 小时前
重新定义智能出行体验 东软与Cerence AI达成战略合作
人工智能·汽车
CHrisFC1 小时前
环境第三方检测机构LIMS系统选型:从合规基础到效率制胜
java·大数据·人工智能
Ro Jace2 小时前
A Real-Time Cross Correlator for Neurophysiological Research
人工智能·python·算法
ai产品老杨2 小时前
企业级AI视频管理平台,内置算法商城,集群管理、标注平台开源了
人工智能·开源·音视频
边缘计算社区2 小时前
谁将主导AI边缘战场?2026中国边缘计算20强榜单征选启动
人工智能·边缘计算
OpenBayes2 小时前
Nemotron Speech ASR低延迟英文实时转写的语音识别服务;GLM-Image开源混合自回归与扩散解码架构的图像生成模型
人工智能·深度学习·机器学习·架构·数据集·语音识别·图像编辑
啊阿狸不会拉杆2 小时前
《机器学习》第 7 章 - 神经网络与深度学习
人工智能·python·深度学习·神经网络·机器学习·ai·ml
星爷AG I2 小时前
9-8 客体构型(AGI基础理论)
人工智能·agi