计算机视觉学习blog(三)——图像到图像的映射

单应性变换

单应性变换是将一个平面内的点映射到另一个平面内的二维投影变换。在这里,平面是指图像或者三维中的平面表示。单应性变换具有很强的实用性,比如图像配准,图像纠正和纹理扭曲,以及创建全景图像,我们将频繁的使用单应性变换。本质上,单应性变换H,按照下面的方程映射二维中的点(齐次坐标意义下):
在这里插入图片描述
或者 x’=Hx

对于图像平面内(甚至是三维中的点,后面我们会介绍到)的点,齐次坐标是个非常有用的表示方式。点的齐次坐标是依赖于其尺度定义的,所以,x=[x,y,w]=[ax,ay,aw]=[x/w,y/w,1]都表示同一个二维点。因此,单应性矩阵H也仅依赖尺度定义,所以,单应性矩阵具有8个独立的自由度。我们通常使用w=1来归一化点,这样,点具有唯一的图像坐标x和y。这个额外的坐标是的我们可以简单地使用一个矩阵来表示变换。

创建homography.py文件加入下面的函数,实现对点进行归一化和转换齐次坐标的功能:

def normallize(points):
    """在齐次坐标意义下,对点集进行归一化,是最后一行为1"""
    for row in points:
        row /= points[-1]
    return points


def make_homog(points):
    """将点集(dim×n的数组)转换为齐次坐标表示"""

    return vstack((points, ones((1, points.shape[1]))))

进行点和变换的处理时。我们会按照列优先的原则存储这些点。因此,n个二维点集将会存储为齐次坐标意义下的一个3×n数组。这种格式使得矩阵乘法和点的变换操作更加容易。对于其他的例子,比如对于聚类和分类的特征,我们将使用典型的行数组来存储数据。

单应性矩阵

单应性矩阵可以有两幅图像(或者平面)中对应点对计算出来。前面已经提到过,一个完全射影变换具有8个自由度。根据对应点约束,每个对应点对可以写出两个方程,分别对应于x和y坐标。因此,计算单应性矩阵H需要4个对应点对。

DLT(Direct Linear Transformation,直接线性变换)是给定4个点或者更多对应点对矩阵,来计算单应性矩阵H的算法。将单应性矩阵H作用在对应点上,重新写出该方程,我们可以得到下面的方程:

在这里插入图片描述
或者Ah=0,其中A是一个具有对应点对二倍数量行数的矩阵。将这些对应点对方程的系数堆叠到一个矩阵红,我们可以使用SVD(Singular Value Decomposition奇异值分解)算法找到H的最小二乘解。下面是算法代码,我们也将其加入到 homography.py 文件里:
H_from_points函数

def H_from_points(fp, tp):
    """使用线性DLT方法,计算单应性矩阵H,使fp映射到tp。点自动进行归一化"""

    if fp.shape != tp.shape:
        raise RuntimeError('number of points do not match')

    # 对点进行归一化(对数值计算很重要)
    # --- 映射起始点 ---
    m = mean(fp[:2], axis=1)
    maxstd = max(std(fp[:2], axis=1)) + 1e-9
    C1 = diag([1/maxstd, 1/maxstd, 1])
    C1[0][2] = -m[0]/maxstd
    C1[1][2] = -m[1]/maxstd
    fp = dot(C1, fp)

    # --- 映射对应点 ---
    m = mean(tp[:2], axis=1)
    maxstd = max(std(tp[:2], axis=1)) + 1e-9
    C2 = diag([1 / maxstd, 1 / maxstd, 1])
    C2[0][2] = -m[0] / maxstd
    C2[1][2] = -m[1] / maxstd
    tp = dot(C2, tp)

    # 创建用于线性方法的矩阵,对于每个对应对,在矩阵中会出现两行数值
    nbr_correspondences = fp.shape[1]
    A = zeros((2 * nbr_correspondences, 9))
    for i in range(nbr_correspondences):
        A[2*i] = [-fp[0][i], -fp[1][i], -1, 0, 0, 0,
                  tp[0][i]*fp[0][i], tp[0][i]*fp[1][i], tp[0][i]]
        A[2*i+1] = [0, 0, 0, -fp[0][i], -fp[1][i], -1,
                    tp[1][i]*fp[0][i], tp[1][i]*fp[1][i], tp[1][i]]

    U, S, V = linalg.svd(A)
    H = V[8].reshape((3, 3))

    # 反归一化
    H = dot(linalg.inv(C2), dot(H, C1))

    # 归一化,然后返回
    return H / H[2, 2]

仿射变换

由于仿射变换具有6个自由度,因此我们需要三个对应点来估计矩阵H。通过将最后两个元素设置为0,即h7=h8=0,仿射变换可以用上面的DLT算法估计得出。

下面的函数使用对应点来计算放射变换矩阵,我们继续将其添加到 homography.py 文件中:

Haffine_from_points函数

# 仿射变换
def Haffine_from_points(fp, tp):
    """计算H仿射变换,使得tp是fp经过仿射变换H得到的"""

    if fp.shape != tp.shape:
        raise RuntimeError('number of points do not match')

        # 对点进行归一化(对数值计算很重要)
        # --- 映射起始点 ---
        m = mean(fp[:2], axis=1)
        maxstd = max(std(fp[:2], axis=1)) + 1e-9
        C1 = diag([1 / maxstd, 1 / maxstd, 1])
        C1[0][2] = -m[0] / maxstd
        C1[1][2] = -m[1] / maxstd
        fp_cond = dot(C1, fp)

        # --- 映射对应点 ---
        m = mean(tp[:2], axis=1)
        C2 = C1.copy()  # 两个点集,必须都进行相同的缩放
        C2[0][2] = -m[0] / maxstd
        C2[1][2] = -m[1] / maxstd
        tp_cond = dot(C2, tp)

        # 因为归一化后点的均值为0,所以平移量为0
        A = concatenate((fp_cond[:2], tp_cond[:2]), axis=0)
        U, S, V = linalg.svd(A.T)

        # 如Hartley和Zisserman著的Multiplr View Geometry In Computer,Scond Edition所示,
        # 创建矩阵B和C
        tmp = V[:2].T
        B = tmp[:2]
        C = tmp[2:4]

        tmp2 = concatenate((dot(C, linalg.pinv(8)), zeros((2, 1))), axis=1)
        H = vstack((tmp2, [0, 0, 1]))

        # 反归一化
        H = dot(linalg.inv(C2), dot(H, C1))

        return H / H[2, 2]

图像扭曲

对图像块应用仿射变换,我们将其称为图像扭曲(或者仿射扭曲)

对图像块应用仿射变换,我们将其称为图像扭曲(或者仿射扭曲)。该操作不仅经常在计算机图形学中,而且经常出现在计算机视觉算法总。扭曲的操作可以使用SciPy工具包中的ndimage包来简单完成。

# 仿射扭曲
from scipy import ndimage
from numpy import *
from PIL import Image
from pylab import *
im1 = array(Image.open('3.jpg').convert('L'))
H = array([[1.4, 0.05, -100], [0.05, 1.5, -100], [0, 0, 1]])
im2 = ndimage.affine_transform(im1, H[:2, :2], (H[0, 2], H[1, 2]))

gray()
subplot(121)
imshow(im1)
axis('off')
subplot(122)
imshow(im2)
axis('off')
show()

从运行结果可以看出,原始图像(左)和扭曲后的图像(右)的差别,扭曲后的图像中丢失的像素用零来填充。
在这里插入图片描述

图3-1:用仿射变换扭曲图像。原始图像(左图)以及使用ndimage.affine_transform()函数扭曲后的图像(右图)

仿射扭曲的一个简单例子是,将图像或者图像的一部分放置在另一幅图像中,使得它们能够和指定的区域或者标记物对齐

将函数 image_in_image() 添加到 wary.py 文件中。该函数的输入参数为两幅图像和一个坐标。该坐标为将第一幅图像放置到第二幅图像中的角点坐标:

image_in_image函数

def image_in_image(im1, im2, tp):
    """使用仿射变换将im1放置在im2上,使im1图像的角和tp尽可能的靠近
        tp是齐次表示的,并且是按照从左上角逆时针计算的"""

    # 扭曲的点
    m, n = im1.shape[:2]
    fp = array([[0, m, m, 0], [0, 0, n, n], [1, 1, 1, 1]])

    # 计算仿射变换,并且将其应用于图像im1中
    H = homography.Haffine_from_points(tp, fp)
    im1_t = ndimage.affine_transform(im1, H[:2, :2],
                                     (H[0, 2], H[1, 2]), im2.shape[:2])
    alpha = (im1_t > 0)
    return (1-alpha)*im2 + alpha*im1_t
# -*- coding: utf-8 -*-

from pcv.geometry import warp, homography
from PIL import  Image
from pylab import *
from scipy import ndimage

# im1仿射到im2的例子
#打开两张图片
im1 = array(Image.open('3.jpg').convert('L'))
im2 = array(Image.open('9.jpg').convert('L'))
# 选定一些目标点,数组tp表示目标区域,三行分别代表y、x和齐次,其中区域按从左上角逆时针旋转,
tp = array([[120,260,260,120],[16,16,305,305],[1,1,1,1]])#将一些目标点存储到数组中
im3 = warp.image_in_image(im1,im2,tp) #使用仿射变换将m1放置到m2
figure()
gray()
subplot(141)
axis('off')
imshow(im1)
subplot(132)
axis('off')
imshow(im2)
subplot(133)
axis('off')
imshow(im3)
show()

运行结果:
在这里插入图片描述

图3-2:使用仿射变换将一副图像放置到另一幅图像中

修改参数tp = array([[233, 301, 303, 241],[23, 18, 333, 332],[1,1,1,1]])

坐标值可以通过查看绘制的图像(在Pylab图像中,鼠标的坐标显示在图像底部附近)手工确定,也可以使用Pylab库中的ginput函数获得

from PIL import Image
from pylab import *
import numpy as np

im = array(Image.open('image/image3.jpg'))
imshow(im)

print('Please click 4 point')
points = ginput(4)

# 转整数
int_points = np.int_(points)

# 行列互换操作
new_points = list(map(list, zip(*int_points)))

print('you clicked x:', new_points[1])
print('you clicked y:', new_points[0])
show()

从左上角逆时针选取四个点

修改后结果:
在这里插入图片描述

图3-3:将图像放置在学校门口的石碑上

以上图片来源集美大学实拍建筑(陈延奎图书馆,集美大学东大门)
https://www.cnblogs.com/Easy-/p/14638459.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
第1章 数字图像图像处理 1 1.1 数字图像相关概念 1 1.1.1 数字图像 1 1.1.2 图像处理 2 1.1.3  图像识别 2 1.1.4 图像理解 3 1.2 图像的获取、显示与表示 3 1.2.1 图像的获取 3 1.2.2 图像显示 4 1.2.3 图像表示 4 1.3 数字图像处理系统的基本组成结构 9 第2章 相关的图像处理技术 10 2.1  图像分割技术 10 2.1.1 阈值与图像分割 10 2.1.2 梯度与图像分割 11 2.1.3 边界提取与轮廓跟踪 11 2.1.4  Hough变换 12 2.1.5 区域增长 12 2.2 图像复原 12 2.2.1 数学模型 12 2.2.2 维纳滤波(Wiener Filtering) 13 2.3 图像的纹理分析技术 13 2.3.1 空间灰度层共现矩阵 14 2.3.2  纹理能量测量 16 2.3.3 纹理的结构分析方法和纹理梯度 18 2.3.4 纹理识别示例——云类自动识别 19 2.4 图像的形态学处理技术 20 2.4.1 基本概念 21 2.4.2 开运算和闭运算 22 2.4.3 击中、击不中、变换 (HMT-Hit Miss Transform) 23 2.4.4 边界和骨架(Boundary and Skeleton) 23 第 3章 指纹识别系统(上) 24 3.1 指纹识别的历史 24 3.2 指纹识别研究的现状 24 3.3 指纹识别系统的构成  25 3.3.1 指纹的录入 26 3.3.2 指纹图像增强 28 3.3.3 指纹识别的基本原理 29 3.3.4  系统问题 30 3.3.5 系统性能评估 31 3.3.6 一套指纹识别算法库的构成 32 3.4 指纹的粗分类与匹配 89 3.5  基于Matlab的指纹识别系统 92 3.5.1 主界面程序 93 3.5.2 指纹中心计算程序 115 3.5.3 计算有效区域 117 3.5.4 二维Gabor变换 118 3.5.5 归一化扇区 119 3.5.6 读取图像 120 3.5.7  旋转角度计算 121 第4章 指纹识别系统(下) 123 4.1 指纹图像的预处理 123 4.1.1 预处理概述  123 4.1.2 指纹质量评估 124 4.1.3 指纹图像分割 129 4.1.4 指纹图像增强 134 4.1.5  指纹图像二值化 135 4.1.6 指纹图像细化 136 4.1.7 相关预处理算法代码 139 4.2 指纹特征提取  177 4.2.1 指纹特征的表述 177 4.2.2 局部细节特征提取 180 4.2.3 特征提取算法代码 186 4.3  基于点模式的细节匹配 194 4.4 指纹识别的实际应用案例 204 4.4.1 指纹门禁系统 204 4.4.2 指纹考勤系统 205 4.5 指纹处理算法库测试程序 206 4.6 本章小结 218 第5章 数字水印技术 219 5.1  基本概念 219 5.1.1 水印技术的基本要求 219 5.1.2 数字水印算法基本思路 219 5.1.3 一些关键问题 220 5.2 水印应用现状分析 220 5.2.1 现有水印算法不适应版权保护 220 5.2.2 盲检测算法 222 5.2.3  盲检测算法的公证 222 5.2.4 数字水印系统的一般组成 223 5.3 基于DCT域的数字水印方案 223 5.3.1  离散余弦变换 223 5.3.2 Torus自同构映射 224 5.3.3 人眼视觉频率响应及DCT变换系数的选取 224 5.3.4  水印算法 226 5.4 基于扩频通信的水印算法 228 5.4.1 扩频通信原理 228 5.4.2 扩频通信在数字水印中的利用 229 5.4.3 加载强度的讨论 233 5.4.4 水印加载算法的实现 237 5.5 一个基于DCT域的实例  240 5.5.1 一些算法代码 240 5.5.2 加载水印 271 5.5.3 提取水印 275 5.5.4 水印算法评价 281 5.6 本章小结 294 第6章 条形码技术 295 6.1 常用的条码编码规则 295 6.1.1  条码的一般组成 295 6.1.2 条码的种类 296 6.1.3 EAN-13码的构造 296 6.2 一个简单的条形码打印系统 298 6.3 一维条形码的识别 312 6.3.1 硬件识别系统 312 6.3.2 预处理过程 312 6.3.3  译码过程 314 6.4 一维条形码识别系统实例 315 6.4.1 DIB.H位图存取头文件 316 6.4.2  DIB.CPP位图存取源程序 317 6.4.3 BARRECOG.H条码识别头文件 322 6.4.4 BARRECOG.CPP条码识别源程序 323 6.5 二维条形码介绍 337 6.5.1 PDF417符号的结构 338 6.5.2 簇及符号字符定义 338 6.5.3 层编码 339 6.5.4 模式结构 339 6.5.5 起始符和终止符 340 6.5.6  空白区 340 6.5.7 错误监测与纠正 340 6.6 二维条形码打印程序 340 6.6.1 PDF417LIB.H二维条形码库头文件 340 6.6.2 PDF417LIBIMP.H数据定义 342 6.6.3 PDF417LIB.C函数实现文件  353 6.6.4 PDF417.C主程序 377 6.7 本章小结 378 第7章 手势识别系统 379 7.1  立体测量 379 7.1.1 立体匹配法 379 7.1.2 立体视觉的原理 379 7.1.3 用立体视觉进行距离测量  381 7.2 用一台摄像头进行距离测量 382 7.2.1 摄像头正对前方 382 7.2.2 摄像头倾斜 383 7.2.3  一台摄像头测量距离 385 7.3 假想演奏系统的构成 387 7.3.1 系统概述 387 7.3.2 肤色提取 388 7.3.3  右手位置检测 390 7.3.4 摄像机的距离测量 391 7.3.5 音阶范围与音量范围 391 7.3.6 声音的表现方法 392 7.3.7 系统整体构成 393 7.4 程序代码 393 7.5 本章小结 432 第8章 印鉴鉴定系统 433 8.1 伪印鉴的制作及人工防伪技术 433 8.1.1 常用伪造印鉴的方法及其特征 433 8.1.2 真假印鉴印文的检验 435 8.2 印鉴图像的分离 435 8.2.1 封闭凸多边形图像提取的算法提出 436 8.2.2 封闭凸多边形图像的提取方法——种子扩散浮置实体算法 436 8.3 基于矩不变量的印鉴识别 439 8.4 基于Fourier描述符的印鉴识别方法 441 8.4.1 提取字符包络线 441 8.4.2 字符包络线的Fourier描述 442 8.5 基于边缘和模板匹配的印鉴识别 443 8.6 部分算法代码 446 8.6.1 背景去除(利用颜色) 446 8.6.2 基于矩不变量的代码 450 8.7 本章小结 455 第9章 光学字符识别技术(上) 456 9.1 概述 456 9.1.1 文字识别系统的构成 456 9.1.2 文字识别技术 457 9.1.3 印刷体汉字识别 459 9.1.4 存在的问题 461 9.2  预处理技术 461 9.2.1 二值化 462 9.2.2 版面分析 463 9.2.3 倾斜度校正 464 9.2.4  版面切分 467 9.2.5 行、字分割 467 9.2.6 细化和规范化 469 9.2.7 预处理算法源代码示例 470 9.3  特征提取 537 9.3.1 概述 538 9.3.2 边缘跟踪 538 9.3.3 笔画的分类 540 9.3.4 笔画识别前的噪声处理 541 9.3.5 笔画方向码合并处理及笔画识别 542 9.3.6 笔画间特征量的定义及识别 543 9.3.7  整字匹配的距离准则 544 9.3.8 一些统计特征 545 第10章 光学字符识别技术(下) 549 10.1 分类与识别 549 10.1.1 判别器的选择 549 10.1.2 决策树的基本概念 550 10.1.3 决策树设计 552 10.1.4  节点分类器设计 555 10.1.5 多方案组合识别器 558 10.1.6 代码示例 560 10.2 后处理 623 10.3  OCR程序示例 639 10.4 本章小结 640

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值