Python机器视觉(3)——特征描述与图像配准

梯度直方图

2D透视变换(图像配准)

       透视矩阵有8个未知数(右下角i恒为1),我们只需要标定原图像和新图像的四个角点,即可解出透视矩阵。解透视矩阵的步骤如下:

       化为Ax=b形式后,求解方法有很多,经查阅资料,测试了两种方法。第一种是对A求广义逆,然后求出x值,第二种方法是利用最小二乘法求解矩阵。公式如下:

       经过测试,发现最小二乘法解透视矩阵,与opencv自带函数解出的结果一致。

       随后就是针对每个像素点遍历求坐标,再将原图像坐标的像素值赋给新图像对应坐标点即可。但是,变换后的矩阵有许多噪声点,可以通过滤波器消除噪声。

       但如果目标标定点位选取不好,则会造成大量缺失点,因为原图像坐标×透视矩阵后,很可能输出的点超过新图像大小,为避免这个问题,本题将遍历每个新图像点,求对应原图像坐标,加上一些边界约束,保证新图像每个像素都能被赋值。

       如果出现了图像超出坐标范围而显示不全的情况,感觉可以扩展新图像的空间大小(如500×500的图片,扩展为以相同中心点的1500×1500图片)。

       下面是2D透视变换的代码,有三部分:调用opencv的鼠标回调函数标定原图和目标图的四个角点、求解透视矩阵、透视变换。

import cv2
import numpy as np
import time

def mark_points(img):                               #鼠标标记点位的坐标
    Points = []                               #初始化
    def on_mouse(event, x, y, flags, param):        #opencv调用函数的格式
        if event == cv2.EVENT_LBUTTONDOWN:          #如果是鼠标左键按下
            Points.append([x,y])              #添加点位坐标
    cv2.namedWindow('img', cv2.WINDOW_AUTOSIZE)
    cv2.setMouseCallback('img', on_mouse)           #调用鼠标函数
    while True:
        cv2.imshow('img', img)
        # 按 q 键退出
        if cv2.waitKey(1) & 0xFF == ord('q'):
            cv2.destroyAllWindows()
            break
    return np.float32(Points)                 #转为numpy数组格式,方便科学计算

def calculate_perspective_matrix(originPoints, targetPoints):
    # 构建线性方程组 Ax = b
    A = []
    b = []
    for i in range(4):      #一共有四组点,依次赋值
        x_origin, y_origin = originPoints[i]
        x_target, y_target = targetPoints[i]
        A.append([x_origin, y_origin, 1, 0, 0, 0, -x_target*x_origin, -x_target*y_origin])
        A.append([0, 0, 0, x_origin, y_origin, 1, -y_target*x_origin, -y_target*y_origin])
        b.append(x_target)
        b.append(y_target)

    A = np.array(A)
    b = np.array(b)
    '''A_inv = np.dot(A.T,np.linalg.inv(np.dot(A,A.T)))             #用广义逆求解矩阵
    x = np.dot(A_inv,b)
    matrix1 = np.append(x,1).reshape(3, 3)
    print('the Generalized inverse matrix is :')
    print(matrix1)'''
    matrix = np.dot(np.dot(np.linalg.inv(np.dot(A.T,A)),A.T),b)     #最小二乘法计算
    matrix = np.append(matrix,1).reshape(3, 3)                      #添加透视矩阵中右下角的常量1,然后变为3×3矩阵
    #print('the OLS matrix is :')
    #print(matrix)
    return matrix

def transformed(img,matrix):
    result = np.zeros(img.shape,dtype=np.uint8)
    for row in range(img.shape[0]):         #对每一个像素坐标进行变换
        for col in range(img.shape[1]):
            temp = np.dot(np.linalg.inv(matrix),np.append([col,row],1))
            temp /= temp[2]                 #将算出的数,转化为平面图像坐标系的数,即除以z轴数据
            temp = np.round(temp).astype(int)               #数据转为int型
            if temp[0] < 0:
                temp[0] = 0
            if temp[0] >= img.shape[1]:
                temp[0] = img.shape[1]-1
            if temp[1] < 0:
                temp[1] = 0
            if temp[1] >= img.shape[0]:
                temp[1] = img.shape[0]-1
            result[row,col] = img[temp[1]][temp[0]]
    return result

if __name__ == '__main__':
    img = cv2.imread('img.jpg')         #读取图片
    print('please mark the 4 points of origin image')
    originPoints = mark_points(img)     #标记原图片四个角点
    #targetPoints = np.float32([[0,0],[img.shape[1]/4,0],[img.shape[1]/4,img.shape[0]/4],[0,img.shape[0]/4]])
    time.sleep(1)
    print('please mark the 4 points of target image')
    targetPoints = mark_points(img)     #标记你目标图像的四个角点(如果想为完美矩形,可以用上方赋值,不用鼠标标记)
    start =time.time()                  #一个计时器start
    print('calculating the perspective matrix......')
    matrix = calculate_perspective_matrix(originPoints, targetPoints)   #计算透视矩阵
    print('the perspective matrix is:')
    print(matrix)
    print('calculating the transformed image......')
    result = transformed(img, matrix)   #根据透视矩阵求变换后的图像
    result = cv2.medianBlur(result,5)   #中值滤波去噪声点
    end = time.time()                   #一个计时器end
    print('Running time: %s Seconds'%(end-start))
    cv2.imshow('result', result)        #展示图像
    cv2.imwrite('result1.jpg',result)    #保存
    cv2.waitKey(0)
    cv2.destroyAllWindows()

参数估计

       上述广义逆矩阵可能会在计算上有偏差,最小二乘法只适用于标点精确的场合(最小二乘法没法避免离群点),可以使用RANSAC随机抽样一致性算法来进行参数估计。它的主要思想是:随机选择一组点,拟合变换参数,寻找与该变换相符的点,重新拟合参数。

全景图

  • 15
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于特征的图像配准是一种常用的图像处理技术,可以将两幅图像进行对齐,使它们在空间上重合。Python中有多种库可以实现基于特征的图像配准,比如OpenCV和scikit-image等。 其中,OpenCV提供了cv2.findHomography()函数来计算两幅图像之间的单应性矩阵,从而实现图像配准。具体步骤如下: 1. 读入两幅待配准的图像 2. 提取两幅图像的特征点,可以使用SIFT、SURF、ORB等算法 3. 匹配两幅图像的特征点,可以使用FLANN或暴力匹配算法 4. 根据匹配的特征点计算单应性矩阵 5. 将待配准的图像进行透视变换,使其与参考图像重合 下面是一个基于OpenCV实现基于特征的图像配准的示例代码: ```python import cv2 # 读入两幅待配准的图像 img1 = cv2.imread('img1.jpg') img2 = cv2.imread('img2.jpg') # 提取两幅图像的特征点 sift = cv2.xfeatures2d.SIFT_create() kp1, des1 = sift.detectAndCompute(img1, None) kp2, des2 = sift.detectAndCompute(img2, None) # 匹配两幅图像的特征点 bf = cv2.BFMatcher() matches = bf.knnMatch(des1, des2, k=2) # 根据匹配的特征点计算单应性矩阵 good_matches = [] for m, n in matches: if m.distance < 0.75 * n.distance: good_matches.append(m) src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2) dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2) M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0) # 将待配准的图像进行透视变换,使其与参考图像重合 result = cv2.warpPerspective(img1, M, (img2.shape[1], img2.shape[0])) # 显示结果 cv2.imshow('result', result) cv2.waitKey(0) cv2.destroyAllWindows() ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值