OpenCV

您所在的位置:网站首页 如何旋转图像不变形的方法 OpenCV

OpenCV

2024-07-15 08:46| 来源: 网络整理| 查看: 265

文章目录 一、基于傅里叶变换的图像矫正1.1 傅里叶变换原理1.2 傅里叶变换过程一系列函数1.3 图像矫正处理流程 二、旋转图像矫正三、基于透视的图像矫正3.1 直接变换3.2 自动获取图像顶点变换直接获取图像轮廓矫正获取图像轮廓顶点矫正 图像校正运行环境 Anaconda| pycharm/jupyter notebook 你需要安装如下库

pip install numpy pip install matplotlib pip install opencv-python 一、基于傅里叶变换的图像矫正

由于拍照时,图像被旋转,为方便观看或使用,需要对旋转图像进行校正。 旋转图像矫正流程 思路借鉴 http://johnhany.net/2013/11/dft-based-text-rotation-correction/

1.1 傅里叶变换原理

2维图像的傅立叶变换可以用以下数学公式表达: F ( k , l ) = ∑ i = 0 N − 1 ∑ j = 0 N − 1 f ( i , j ) e − i 2 π ( k i N + l j N ) F(k,l) = \displaystyle\sum\limits_{i=0}^{N-1}\sum\limits_{j=0}^{N-1} f(i,j)e^{-i2\pi(\frac{ki}{N}+\frac{lj}{N})} F(k,l)=i=0∑N−1​j=0∑N−1​f(i,j)e−i2π(Nki​+Nlj​)

e i x = cos ⁡ x + i sin ⁡ x e^{ix} = \cos{x} + i\sin {x} eix=cosx+isinx

式中 f f f 是空间域(spatial domain)值, F F F 则是频域(frequency domain)值。

转换之后的频域值是复数, 因此,显示傅立叶变换之后的结果需要使用实数图像(real image) 加虚数图像(complex image), 或者幅度图像(magitude image)加相位图像(phase image)。 在实际的图像处理过程中,仅仅使用了幅度图像,因为幅度图像包含了原图像的几乎所有我们需要的几何信息。然而,如果你想通过修改幅度图像或者相位图像的方法来间接修改原空间图像,你需要使用逆傅立叶变换得到修改后的空间图像,这样你就必须同时保留幅度图像和相位图像了。

在此示例中,我将展示如何计算以及显示傅立叶变换后的幅度图像。由于数字图像的离散性,像素值的取值范围也是有限的。比如在一张灰度图像中,像素灰度值一般在0到255之间。 因此,我们这里讨论的也仅仅是离散傅立叶变换(DFT)。 如果你需要得到图像中的几何结构信息,那你就要用到它了。

在频域里面,对于一幅图像,高频部分代表了图像的细节、纹理信息;低频部分代表了图像的轮廓信息。如果对一幅精细的图像使用低通滤波器,那么滤波后的结果就剩下了轮廓了。这与信号处理的基本思想是相通的。如果图像受到的噪声恰好位于某个特定的“频率”范围内,则可以通过滤波器来恢复原来的图像。傅里叶变换在图像处理中可以做到:图像增强与图像去噪,图像分割之边缘检测,图像特征提取,图像压缩等等。

1.2 傅里叶变换过程一系列函数

1 . 将图像延展到最佳尺寸(提高运行速度)

getOptimalDFTSize():返回给定尺寸的傅里叶最优尺寸大小,提高运行速度(需要扩充图像,填充多少由此函数计算得到:被计算的数字序列长度vecsize为2的n次幂或者能够分解成2,3,5的乘积)copyMakeBorder() 边界扩充函数

2 . 为傅立叶变换的结果(实部和虚部)分配存储空间. 傅立叶变换的结果是复数,这就是说对于每个原图像值,结果是两个图像值。 此外,频域值范围远远超过空间值范围, 因此至少要将频域储存在 float 格式中。 结果我们将输入图像转换成浮点类型,并多加一个额外通道来储存复数部分 3 . 进行离散傅立叶变换. 支持图像原地计算 (输入输出为同一图像):

dtf() :对一维或者二维浮点数数组进行正向或反向傅里叶变换

4 . 将复数转换为幅度复数包含实数部分(Re)和复数部分 (imaginary - Im)。 离散傅立叶变换的结果是复数,对应的幅度可以表示为: M = R e ( D F T ( I ) ) 2 + I m ( D F T ( I ) ) 2 2 M = \sqrt[2]{ {Re(DFT(I))}^2 + {Im(DFT(I))}^2} M=2Re(DFT(I))2+Im(DFT(I))2 ​

magnitude() 计算二维矢量的幅值

5 . 对数尺度(logarithmic scale)缩放. 傅立叶变换的幅度值范围大到不适合在屏幕上显示。高值在屏幕上显示为白点,而低值为黑点,高低值的变化无法有效分辨。为了在屏幕上凸显出高低变化的连续性,我们可以用对数尺度来替换线性尺度: M 1 = log ⁡ ( 1 + M ) M_1 = \log{(1 + M)} M1​=log(1+M)

log() 自然对数函数

6 . 剪切和重分布幅度图象限.将新添加的像素剔除。为了方便显示,我们也可以重新分布幅度图象限位置(注:将第五步得到的幅度图从中间划开得到四张1/4子图像,将每张子图像看成幅度图的一个象限,重新分布即将四个角点重叠到图片中心)。 这样的话原点(0,0)就位移到图像中心。

7 . 归一化. 将像素值归一到 float(0,1) 再乘以 255用于显示 。

normalize() 矩阵归一化函数 cv2.getOptimalDFTSize(vecsize) # vecsize: 传入:image.shape[0]/image.shape[1] cv2.copyMakeBorder(src,top,bottom,left,right,borderType,dst=None) """ src: 图像 top,bottom,left,right: 上/下/左/右边扩充像素(int) borderType: 边界类型: BORDER_CONSTANT: 常量,增加的变量通通为value BORDER_REFLICATE: 直接用边界的颜色填充,比如 : aaaaaa | abcdefgh | hhhhhhh BORDER_REFLECT: 镜像:比如 : fedcba | abcdefgh | hgfedcb BORDER_REFLECT_101:倒映,和上面类似,但在倒映时,会把边界空开:比如 : gfedcb | abcdefgh |gfedcba BORDER_WRAP: 没有规律的,比如: cdefgh | abcdefgh | abcdefg """ cv2.magnitude(InputArray x, InputArray y, OutPutArray magnitude) """ 计算输入矩阵x和y对应该的每个像素平方求和后开根号保存在输出矩阵magnitude中。 """ 1.3 图像矫正处理流程 获取图像的傅里叶变换图二值化Hough直线检测计算倾斜角度旋转校正 import cv2 import numpy as np import math def fourier_demo(): #1、灰度化读取文件, img = cv2.imread('english_rotation.jpg',0) #2、图像延扩 h, w = img.shape[:2] new_h = cv2.getOptimalDFTSize(h) new_w = cv2.getOptimalDFTSize(w) right = new_w - w bottom = new_h - h nimg = cv2.copyMakeBorder(img, 0, bottom, 0, right, borderType=cv2.BORDER_CONSTANT, value=0) cv2.imshow('new image', nimg) #3、执行傅里叶变换,并过得频域图像 f = np.fft.fft2(nimg) fshift = np.fft.fftshift(f) magnitude = np.log(np.abs(fshift)) #二值化 magnitude_uint = magnitude.astype(np.uint8) ret, thresh = cv2.threshold(magnitude_uint, 11, 255, cv2.THRESH_BINARY) print(ret) cv2.imshow('thresh', thresh) print(thresh.dtype) #霍夫直线变换 lines = cv2.HoughLinesP(thresh, 2, np.pi/180, 30, minLineLength=40, maxLineGap=100) print(len(lines)) #创建一个新图像,标注直线 lineimg = np.ones(nimg.shape,dtype=np.uint8) lineimg = lineimg * 255 piThresh = np.pi/180 pi2 = np.pi/2 print(piThresh) for line in lines: x1, y1, x2, y2 = line[0] cv2.line(lineimg, (x1, y1), (x2, y2), (0, 255, 0), 2) if x2 - x1 == 0: continue else: theta = (y2 - y1) / (x2 - x1) if abs(theta)


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3