基于OpenCV的图像变换

一、基于OpenCV的边缘检测

        针对二维图像的边缘检测一般步骤:滤波(边缘检测是基于图像强度的一阶与二阶导数,但导数对图像噪声敏感,需要采用滤波器过滤掉噪声),增强(增强边缘是确定图像各点领域强度的变化值,并通过梯度幅值凸显出来),检测(图像领域各点的梯度表征这图像的边缘,但还有部分点非边缘需要进行筛选,通过阈值化方法可实现)。

      边缘检测的三个主要评价标准:(1)低错误率;(2)高定位性;(3)最小响应。

       OpenCV处理库中常见边缘检测的各种算子和滤波器-Canny算子、Sobel算子、Laplacian算子已经Scharr滤波器。

1.Canny算子

(1)介绍

        A.滤波:使用高斯平滑滤波器卷积降噪;B.计算梯度赋值和方向:使用Sobel滤波器;C.非极大值抑制;D.滞后阈值。

(2)优缺点:使用高斯滤波平滑图像,抗噪能力强;Canny算法产生边缘线很细。适合于用于不同的场合,不过速度较慢。 它的参数允许根据不同实现的特定要求进行调整以识别不同的边缘特性。

(3)Canny()函数

void Canny(InputArray image,OutputArray edges, double threshold1, double threshold2, int apertureSize=3,bool L2gradient=false)

  • 第一个参数,InputArray类型的image,输入图像,即源图像,填Mat类的对象即可,且需为单通道8位图像
  • 第二个参数,OutputArray类型的edges,输出的边缘图,需要和源图片有一样的尺寸和类型。
  • 第三个参数,double类型的threshold1,第一个滞后性阈值【低阈值】。值越大,找到的边缘越少
  • 第四个参数,double类型的threshold2,第二个滞后性阈值【高阈值】。
  • 第五个参数,int类型的apertureSize,表示应用Sobel算子的孔径大小,其有默认值3。
  • 第六个参数,bool类型的L2gradient,一个计算图像梯度幅值的标识,有默认值false

注意:阈值1与2两者中叫小的值用于边缘连接,而较大的值用于控制边缘的初始段,推荐的高低阈值比在2:1到3:1之间。

2. Sobel算子

(1)介绍:主要用于边缘检测的离散微分算子,结合了高斯平滑处理和微分求导,用来计算图像灰度函数的近似梯度。利用此算子都会产生对应的梯度矢量或其法矢量。

对两个方向求导(卷积):

           G_{x}=\begin{bmatrix} -1 & 0 &+1 \\ -2& 0 & +2\\ -1 & 0&+1 \end{bmatrix}               G_{y}=\begin{bmatrix} -1 & -2 &-1 \\ 0 & 0 & 0\\ +1 &+2 &+1 \end{bmatrix}          G=\sqrt{G_{x}^{2}+G_{y}^{2}};or G=\left | G_{x}+G_{y} \right |

(2)优缺点:对噪声具有平滑作用,抗噪能力强,计算量大,但定位精度不高,得到的边缘比较粗,适用于精度要求不高的场合。常用于噪声较多、灰度渐变的图像;

(3)Sobel()函数--计算一阶、二阶、三阶或者混合图像差分

void Sobel (InputArray src,OutputArray dst,int ddepth,int dx,int dy,int ksize=3,double scale=1,double delta=0,int borderType=BORDER_DEFAULT )

  • 第一个参数,InputArray类型的image,输入图像,即源图像,填Mat类的对象即可
  • 第二个参数,OutputArray类型的dst,即目标图像,函数的输出参数,需要和源图片有一样的尺寸和类型。
  • 第三个参数,int类型的ddepth,输出图像的深度,支持如下src.depth()和ddepth的组合:

             若src.depth() = CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F
             若src.depth() = CV_16U/CV_16S, 取ddepth =-1/CV_32F/CV_64F
             若src.depth() = CV_32F, 取ddepth =-1/CV_32F/CV_64F
             若src.depth() = CV_64F, 取ddepth = -1/CV_64F

  • 第四个参数,int类型dx,x 方向上的差分阶数。
  • 第五个参数,int类型dy,y方向上的差分阶数。
  • 第六个参数,int类型ksize,有默认值3,表示Sobel核的大小;必须取1,3,5或7。
  • 第七个参数,double类型的scale,计算导数值时可选的缩放因子,默认值是1,表示默认情况下是没有应用缩放的。我们可以在文档中查阅getDerivKernels的相关介绍,来得到这个参数的更多信息。
  • 第八个参数,double类型的delta,表示在结果存入目标图(第二个参数dst)之前可选的delta值,有默认值0。
  • 第九个参数, int类型的borderType,我们的老朋友了(万年是最后一个参数),边界模式,默认值为BORDER_DEFAULT。这个参数可以在官方文档中borderInterpolate处得到更详细的信息。

说明:一般确定内核是用 ksize \times ksize 来计算导数。但当ksize=1时,往往会使用3\times1或者1\times3的内核,且没有进行高斯滤波处理;当内核大小为3时,Sobel内核可能产生明显的误差,为解决这一问题可以使用Scharr函数,计算速度一样快精度更高,但仅仅作用于内核为3;Sobel算子结合了高斯平滑和分化,结果具有更多的抗噪性。

在进行Sobel算子处理之后,还需要调用convertScaleAbs()函数计算绝对值,并将图像转换为8位图进行显示。也常用于将CV_16S、CV_32F等其他类型的输出图像转变成CV_8U型的图像。其算法原型如下:

convertScaleAbs(InputArray  src,OutputArray dst,double alpha = 1.0, double beta = 0.0)

  • 第一个参数,InputArray类型的image,输入图像,即源图像,填Mat类的对象即可。
  • 第二个参数,OutputArray类型的dst,即目标图像,函数的输出参数,深度为8位
  • 第三个参数,alpha表示比例因子
  • 第四个参数,beta表示原数组元素按比例缩放后添加的值

3. Laplacian算子

(1)概念:Laplacian算子是一个二阶微分算子,常用于图像增强领域和边缘提取。,根据图像处理原理,二阶导数可以用来进行边缘检测,该定义如下:

                                                            Laplacian(f)=\frac{\partial ^{2}f}{\partial x^{2}} +\frac{\partial ^{2}f}{\partial y^{2}}

可近似为:

                                Laplacian\left ( f \right )=\left [ f ( x+1,y ) +f ( x-1,y ) +f ( x,y+1 )+f( x,y-1 ) ]-4f\left ( x,y \right )

        说明:由于Laplacian使用了图像梯度,他内部运行代码其实调用了Sobel算子。让一幅图像减去他的Laplacian算子可以增强对比度。

(2)优缺点:对孤立像素的响应要比对边缘或线的响应要更强烈,因此只适用于无噪声图像。

(3)Laplacian()函数

void Laplacian(InputArray src,OutputArray dst, int ddepth, int ksize=1, double scale=1, double delta=0, int borderType=BORDER_DEFAULT );

  • 第一个参数,InputArray类型的image,输入图像,即源图像,填Mat类的对象即可,且需为单通道8位图像。
  • 第二个参数,OutputArray类型的edges,输出的边缘图,需要和源图片有一样的尺寸和通道数。
  • 第三个参数,int类型的ddept,目标图像的深度,与Sobel一样;
  • 第四个参数,int类型的ksize,用于计算二阶导数的滤波器的孔径尺寸,大小必须为正奇数,且有默认值1。
  • 第五个参数,double类型的scale,计算拉普拉斯值的时候可选的比例因子,有默认值1。
  • 第六个参数,double类型的delta,表示在结果存入目标图(第二个参数dst)之前可选的delta值,有默认值0。
  • 第七个参数, int类型的borderType,边界模式,默认值为BORDER_DEFAULT。这个参数可以在官方文档中borderInterpolate()处得到更详细的信息。

注意:Laplacian函数主要利用Sobel算子运算,通过加上Sobel算子运算出图像X方向和Y方向上导数。可以分为四分域和八分域。但ksize=1时,函数采用以下3\times3孔径。

                                                                                  \begin{bmatrix} 0 &1 &0 \\ 1& -4& 1\\ 0&1 &0 \end{bmatrix}

4. Scharr滤波器

(1)概念:它作为内核为3的Sobel算子一个特殊例子,使用Scharr滤波器运算符计算X或Y方向的图像差分。其原理和设计参数与Sobel一样,但是ksize核大小固定为3。

(2)Scharr()函数

void Scharr(InputArray src,OutputArray dst,int ddepth,int dx,int dy,double scale=1,double delta=0, int borderType= BORDER_DEFAULT )

  • 第一个参数,InputArray 类型的src,为输入图像,填Mat类型即可。
  • 第二个参数,OutputArray类型的dst,即目标图像,函数的输出参数,需要和源图片有一样的尺寸和类型。
  • 第三个参数,int类型的ddepth,输出图像的深度,支持如下src.depth()和ddepth的组合与Sobel算子一样。
  • 第四个参数,int类型dx,x方向上的差分阶数。
  • 第五个参数,int类型dy,y方向上的差分阶数。
  • 第六个参数,double类型的scale,计算导数值时可选的缩放因子,默认值是1,表示默认情况下是没有应用缩放的。我们可以在文档中查阅getDerivKernels的相关介绍,来得到这个参数的更多信息。
  • 第七个参数,double类型的delta,表示在结果存入目标图(第二个参数dst)之前可选的delta值,有默认值0。
  • 第八个参数, int类型的borderType,我们的老朋友了(万年是最后一个参数),边界模式,默认值为BORDER_DEFAULT。这个参数可以在官方文档中borderInterpolate处得到更详细的信息。

5. Roberts算子

(1)概念:又称为交叉微分梯度算法,通过局部差分计算检测边缘线条。算子模板分水平和垂直方向,如下

d_{x}=\begin{bmatrix} -1 &0 \\ 0& 1 \end{bmatrix}         d_{y}=\begin{bmatrix} 0 &-1 \\ 1 &0 \end{bmatrix}   

推导如下:d_{x}\left ( i,j \right )=f\left ( i+1,j+1 \right )-f\left ( i,j \right )和 d_{y}\left ( i,j \right )=f\left ( i,j+1 \right )-f\left ( i+1,j \right )

                  S=\sqrt{d_{x}\left ( i,j \right )^{2}+d_{y}\left ( i,j \right )^{2}}

(2)优缺点:边缘定位较准,对噪声敏感。常用来处理具有陡峭的低噪声图像,当图像边缘接近于正45度或负45度时,该算法处理效果更理想。其缺点是对边缘的定位不太准确,提取的边缘线条较粗。

(3)Roberts算法

Roberts算子在OpenCV库里没有定义函数,但可以通过在Python里用Numpy定义模板,再调用OpenCV的filter2D()函数实现边缘提取。该函数主要是利用内核实现对函数的卷积运算,该函数原型如下:

filter2D(InputArray src, int ddepth,size kernel,OutputArray dst,size anchor, double delta=0, int borderType=BORDER_DEFAULT)

filter2D( InputArray src, OutputArray dst, int ddepth,InputArray kernel, Point anchor=Point(-1,-1), double delta=0, int borderType=BORDER_DEFAULT );

  • 第一个参数,InputArray类型Image,src表示输入图像
  • 第二个参数,dst表示输出的边缘图,其大小和通道数与输入图像相同
  • 第三个参数,ddepth表示目标图像所需的深度
  • 第四个参数,kernel表示卷积核,一个单通道浮点型矩阵
  • 第五个参数,anchor表示内核的基准点,其默认值为(-1,-1),位于中心位置
  • 第六个参数,delta表示在储存目标图像前可选的添加到像素的值,默认值为0
  • 第七个参数,borderType表示边框模式

6. Prewitt算子

(1)概念:为一种图像边缘检测的微分算子,其原理是利用特定区域内像素灰度值产生的差分实现边缘检测。由于Prewitt算子采用33模板对区域内的像素值进行计算,而Robert算子的模板为22,故Prewitt算子的边缘检测结果在水平方向和垂直方向均比Robert算子更加明显。

                                                d_{x}=\begin{bmatrix} 1 & 0& -1\\ 1& 0& -1\\ 1& 0& -1 \end{bmatrix}     d_{y}=\begin{bmatrix} -1 &-1 &-1 \\ 0& 0& 0\\ 1&1 &1 \end{bmatrix}

(2)优缺点:该算子更加适合用来识别噪声较多、灰度渐变的图像。

(3)Prewitt算法

        Prewitt算子的实现过程与Roberts算子比较相似。通过Numpy定义模板,再调用OpenCV的filter2D()函数实现对图像的卷积运算,最终通过convertScaleAbs()和addWeighted()函数实现边缘提取。

二、霍夫变换

        霍夫变换(Hough Transform)是图像处理中的一种特征提取技术,该过程在一个参数空间中通过计算累计结果的局部最大值得到一个符合该特定形状的集合作为霍夫变换结果。

        霍夫变换运用两个坐标空间之间的变换将在一个空间中具有相同形状的曲线或直线映射到另一个坐标空间的一个点上形成峰值,从而把检测任意形状的问题转化为统计峰值问题。

        霍夫变换在OpenCV中分为霍夫线变换和霍夫圆变换两种。

1. 霍夫线变换

(1)原理

        一条直线在图像二维空间可由两个变量表示,分别为笛卡尔坐标系下的斜率和截距\left ( k,b \right );极坐标系下极径和极角\left ( r,\theta \right )

两者变化关系:

                                                    y=-\frac{\cos \theta }{\sin \theta }x+\frac{r}{\sin \theta }              r=x\cos \theta +y\sin \theta

        于是选择用极坐标系下极径和极角两个变量来表示图像中直线,并给定一个点\left ( x_{0},y_{0} \right ),就可以直接画出在直线下极坐标系下的曲线(为一条正弦曲线)

                                                                           r_{0}=x_{0}\cos \theta +y_{0}\sin \theta

需要注意的是:通过不同给点的正弦曲线在平面\theta -r相交,这意味着他们通过了同一条直线。

        以上说明了条直线能够通过在平面\theta -r寻找交于一点的曲线数量来检测。而越多曲线交于一点也就意味着这个交点表示的直线由更多的点组成. 一般来说我们可以通过设置直线上点的阈值来定义多少条曲线交于一点我们才认为检测到了一条直线。

(2)分类

       霍夫线变换是一种用来寻找直线的方法. 在使用霍夫线变换之前, 首先要对图像进行边缘检测的处理,也即霍夫线变换的直接输入只能是边缘二值图像

  • 标准霍夫变换(SHT):以上原理介绍为标准传统霍夫变换。
  • 多尺度霍夫变换(MSHT):多尺度霍夫变换(MSHT)为经典霍夫变换(SHT)在多尺度下的一个变种。
  • 累计概率霍夫变换(PPHT):标准霍夫变换(SHT)算法的一个改进,它在一定的范围内进行霍夫变换,计算单独线段的方向以及范围,从而减少计算量,缩短计算时间,只计算部分点数。

(3)函数

A.  void HoughLines(InputArray image, OutputArray lines, double rho, double theta, int threshold, double srn=0, double stn=0 )---针对SHT和MSHT

  • 第一个参数,InputArray类型的image,输入图像,即源图像,需为8位的单通道二进制图像,可以将任意的源图载入进来后由函数修改成此格式后,再填在这里。
  • 第二个参数,InputArray类型的lines,经过调用HoughLines函数后储存了霍夫线变换检测到线条的输出矢量。每一条线由具有两个元素的矢量表示,其中,是离坐标原点((0,0)(也就是图像的左上角)的距离。 是弧度线条旋转角度(0~垂直线,π/2~水平线)。
  • 第三个参数,double类型的rho,以像素为单位的距离精度。另一种形容方式是直线搜索时的进步尺寸的单位半径。PS:Latex中/rho就表示 。
  • 第四个参数,double类型的theta,以弧度为单位的角度精度。另一种形容方式是直线搜索时的进步尺寸的单位角度。
  • 第五个参数,int类型的threshold,累加平面的阈值参数,即识别某部分为图中的一条直线时它在累加平面中必须达到的值。大于阈值threshold的线段才可以被检测通过并返回到结果中。
  • 第六个参数,double类型的srn,有默认值0。对于多尺度的霍夫变换,这是第三个参数进步尺寸rho的除数距离。粗略的累加器进步尺寸直接是第三个参数rho,而精确的累加器进步尺寸为rho/srn。
  • 第七个参数,double类型的stn,有默认值0,对于多尺度霍夫变换,srn表示第四个参数进步尺寸的单位角度theta的除数距离。且如果srn和stn同时为0,就表示使用经典的霍夫变换。否则,这两个参数应该都为正数

B. void HoughLinesP(InputArray image, OutputArray lines, double rho, double theta, int threshold, double minLineLength=0, double maxLineGap=0 )---针对PPHT

  • 第一个参数,InputArray类型的image,输入图像,即源图像,需为8位的单通道二进制图像,可以将任意的源图载入进来后由函数修改成此格式后,再填在这里。
  • 第二个参数,InputArray类型的lines,经过调用HoughLinesP函数后后存储了检测到的线条的输出矢量,每一条线由具有个元素的矢量(x_1,y_1, x_2, y_2)  表示,其中,(x_1, y_1)和(x_2, y_2) 是是每个检测到的线段的结束点。
  • 第三个参数,double类型的rho,以像素为单位的距离精度。另一种形容方式是直线搜索时的进步尺寸的单位半径。
  • 第四个参数,double类型的theta,以弧度为单位的角度精度。另一种形容方式是直线搜索时的进步尺寸的单位角度。
  • 第五个参数,int类型的threshold,累加平面的阈值参数,即识别某部分为图中的一条直线时它在累加平面中必须达到的值。大于阈值threshold的线段才可以被检测通过并返回到结果中。
  • 第六个参数,double类型的minLineLength,有默认值0,表示最低线段的长度,比这个设定参数短的线段就不能被显现出来。
  • 第七个参数,double类型的maxLineGap,有默认值0,允许将同一行点与点之间连接起来的最大的距离

2. 霍夫圆变换

(1)原理

      霍夫圆变换的基本原理和上面讲的霍夫线变化大体上是很类似的,只是点对应的二维极径极角空间被三维的圆心点x, y还有半径r空间取代。需要大量的内存而且执行效率会很低,速度会很慢。

利用三个参数来表示一个圆(二维累加器变三维累加器)

                                                                             C:\left ( x_{center},y_{center},r \right )

Opencv通过“霍夫梯度法”的方法来解决圆变换的问题。

  • 首先对图像应用边缘检测,比如用canny边缘检测。
  • 然后,对边缘图像中的每一个非零点,考虑其局部梯度,即用Sobel()函数计算x和y方向的Sobel一阶导数得到梯度。
  • 利用得到的梯度,由斜率指定的直线上的每一个点都在累加器中被累加,这里的斜率是从一个指定的最小值到指定的最大值的距离。
  • 同时,标记边缘图像中每一个非0像素的位置。
  • 然后从二维累加器中这些点中选择候选的中心,这些中心都大于给定阈值并且大于其所有近邻。这些候选的中心按照累加值降序排列,以便于最支持像素的中心首先出现。
  • 接下来对每一个中心,考虑所有的非0像素。
  • 这些像素按照其与中心的距离排序。从到最大半径的最小距离算起,选择非0像素最支持的一条半径。
  • 如果一个中心收到边缘图像非0像素最充分的支持,并且到前期被选择的中心有足够的距离,那么它就会被保留下来。

缺点:使用Sobel一阶导数来计算局部梯度容易产生噪声;并且对同心圆只识别出直径最大的圆。

(2)函数

void HoughCircles(InputArray image,OutputArray circles, int method, double dp, double minDist, double param1=100,double param2=100, int minRadius=0, int maxRadius=0 )

  • 第一个参数,InputArray类型的image,输入图像,即源图像,需为8位的灰度单通道图像
  • 第二个参数,InputArray类型的circles,经过调用HoughCircles函数后此参数存储了检测到的圆的输出矢量,每个矢量由包含了3个元素的浮点矢量(x, y, radius)表示。
  • 第三个参数,int类型的method,即使用的检测方法,目前OpenCV中就霍夫梯度法一种可以使用,它的标识符为CV_HOUGH_GRADIENT,在此参数处填这个标识符即可。
  • 第四个参数,double类型的dp,用来检测圆心的累加器图像的分辨率于输入图像之比的倒数,且此参数允许创建一个比输入图像分辨率低的累加器。上述文字不好理解的话,来看例子吧。例如,如果dp= 1时,累加器和输入图像具有相同的分辨率。如果dp=2,累加器便有输入图像一半那么大的宽度和高度。
  • 第五个参数,double类型的minDist,为霍夫变换检测到的圆的圆心之间的最小距离,即让我们的算法能明显区分的两个不同圆之间的最小距离。这个参数如果太小的话,多个相邻的圆可能被错误地检测成了一个重合的圆。反之,这个参数设置太大的话,某些圆就不能被检测出来了。
  • 第六个参数,double类型的param1,有默认值100。它是第三个参数method设置的检测方法的对应的参数。对当前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示传递给canny边缘检测算子的高阈值,而低阈值为高阈值的一半。
  • 第七个参数,double类型的param2,也有默认值100。它是第三个参数method设置的检测方法的对应的参数。对当前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示在检测阶段圆心的累加器阈值。它越小的话,就可以检测到更多根本不存在的圆,而它越大的话,能通过检测的圆就更加接近完美的圆形了。
  • 第八个参数,int类型的minRadius,有默认值0,表示圆半径的最小值。
  • 第九个参数,int类型的maxRadius,也有默认值0,表示圆半径的最大值。

注意:HoughCircles函数可以利用霍夫变换算法检测出灰度图中的圆,它不需要源图是二值的。使用此函数可以很容易地检测出圆的圆心,但是它可能找不到合适的圆半径。我们可以通过第八个参数minRadius和第九个参数maxRadius指定最小和最大的圆半径,来辅助圆检测的效果。或者,我们可以直接忽略返回半径,因为它们都有着默认值0,单单用HoughCircles函数检测出来的圆心,然后用额外的一些步骤来进一步确定半径。不需要进行边缘检测。

三、重映射

1.概念

        重映射,就是把一幅图像中某位置的像素放置到另一个图片指定位置的过程。为了完成映射过程, 我们需要获得一些插值为非整数像素的坐标,因为源图像与目标图像的像素坐标不是一一对应的。一般情况下,我们通过重映射来表达每个像素的位置 (x,y),像这样 :

                                                                                 g\left ( x,y \right )=f\left ( h\left ( x,y \right ) \right )

在这里, g\left ( \right )是目标图像,f\left ( \right )是源图像, 而h\left ( x,y \right )是作用于\left ( x,y \right )的映射方法函数。

2.函数

       remap( )函数会根据我们指定的映射形式,将源图像进行重映射几何变换,基于的式子如下:

                                                                     dst\left ( x,y \right )=src\left ( map_{x}\left ( x,y \right ),map_{y}\left ( x,y \right ) \right )

需要注意,此函数不支持就地(in-place)操作。

void remap(InputArray src, OutputArray dst, InputArray map1, InputArray map2, int interpolation, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())

  • 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可,且需为单通道8位或者浮点型图像
  • 第二个参数,OutputArray类型的dst,函数调用后的运算结果存在这里,即这个参数用于存放函数调用后的输出结果,需和源图片有一样的尺寸和类型。
  • 第三个参数,InputArray类型的map1,它有两种可能的表示对象。

        表示点(x,y)的第一个映射
        表示CV_16SC2,CV_32FC1或CV_32FC2类型的X值

  • 第四个参数,InputArray类型的map2,同样,它也有两种可能的表示对象,而且他是根据map1来确定表示那种对象。

        若map1表示点(x,y)时,这个参数不代表任何值
        表示CV_16UC1,CV_32FC1类型的Y值(第二个值)

  • 第五个参数,int类型的interpolation,插值方式,之前的resize( )函数中有讲到,需要注意,resize( )函数中提到的CV_INTER_AREA插值方式在这里是不支持的,所以可选的插值方式如下:

        CV_INTER_NEAREST一最近邻插值
        CV_INTER_LINEAR一双线性插值(默认值)
        CV_INTER_CUBIC一双三次样条插值(逾4\times4像素邻域内的双三次插值)
        CV_INTER_LANCZ0S4一Lanczos插值(逾8\times8像素邻域内的Lanczos插值)

  • 第六个参数,int类型的borderMode,边界模式,有默认值BORDER_CONSTANT,表示目标图像中“离群点(outliers)”的像素值不会被此函数修改。
  • 第七个参数,const Scalar&类型的borderValue,当有常数边界时使用的值,其有默认值Scalar( ),即默认值为0。

四、仿射变换

1.概念

       仿射变换(Affine Transformation或 Affine Map),又称仿射映射,是指在几何中,一个向量空间进行一次线性变换并接上一个平移,变换为另一个向量空间的过程。它保持了二维图形的“平直性”(即:直线经过变换之后依然是直线)和“平行性”(即:二维图形之间的相对位置关系保持不变,平行线依然是平行线,且直线上点的位置顺序不变)。

      一个任意的仿射变换都能表示为乘以一个矩阵(线性变换)接着再加上一个向量(平移)的形式。

常见仿射变换有如下三种常见的变换形式:

  • 旋转(rotation):线性变换
  • 平移(translation):向量
  • 缩放(scale):线性变换

2. 原理

        仿射变换代表的是两幅图之间的一种映射关系,通常使用2 x 3的矩阵来表示仿射变换。

                         A=\begin{bmatrix} a_{00} &a_{01} \\ a_{10}& a_{11} \end{bmatrix}_{2\times 2}      B=\begin{bmatrix} b_{00}\\ b_{10} \end{bmatrix}_{2\times 1}       M=\begin{bmatrix} A & B \end{bmatrix}=\begin{bmatrix} a_{00} & a_{01} &b_{00} \\ a_{10}&a_{11} & b_{10} \end{bmatrix}_{2\times 3}

两幅图像存在如下关系:

                                    T=A\cdot \begin{bmatrix} x\\ y \end{bmatrix}+B  或者    T=M\cdot \left [ x,y,1 \right ]^{T}

  • 已知 X和T,求出矩阵 M;
  • 已知 M和X,要想求得 T。

                                                              

       其中,点1, 2 和 3 (在图一中形成一个三角形) 与图二中三个点是一一映射的关系, 且他们仍然形成三角形, 但形状已经和之前不一样了。我们能通过这样两组三点求出仿射变换 (可以选择自己喜欢的点), 接着就可以把仿射变换应用到图像中去。

3.函数

(1)wrapAffine()函数

warpAffine函数的作用是依据如下式子,对图像做仿射变换:

                                            dst\left ( x,y \right )=src\left ( M_{11}x+M_{12}y+M_{13}, M_{21}x+M_{22}y+M_{23}\right )

void warpAffine(InputArray src,OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())

  • 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。
  • 第二个参数,OutputArray类型的dst,函数调用后的运算结果存在这里,需和源图片有一样的尺寸和类型。
  • 第三个参数,InputArray类型的Mat,2×3的变换矩阵
  • 第四个参数,Size类型的dsize,表示输出图像的尺寸
  • 第五个参数,int类型的flags,插值方法的标识符。此参数有默认值INTER_LINEAR(线性插值),可选的插值方式如下:

       INTER_NEAREST - 最近邻插值
       INTER_LINEAR - 线性插值(默认值)
       INTER_AREA - 区域插值
       INTER_CUBIC –三次样条插值
       INTER_LANCZOS4 -Lanczos插值
       CV_WARP_FILL_OUTLIERS - 填充所有输出图像的象素。如果部分象素落在输入图像的边界外,那么它们的值设定为 fillval.
       CV_WARP_INVERSE_MAP –表示M为输出图像到输入图像的反变换,即 。因此可以直接用来做象素插值。否则, warpAffine函数从M矩阵得到反变换。

  • 第六个参数,int类型的borderMode,边界像素模式,默认值为BORDER_CONSTANT。
  • 第七个参数,const Scalar&类型的borderValue,在恒定的边界情况下取的值,默认值为Scalar(),即0。

求解变换矩阵M:

Mat getAffineTransform(InputArray src, InputArray dst)

  • 第一个参数,InputArray类型的Point2f是数组(大小为3)即可
  • 第二个参数,InputArray类型的Point2f是数组(大小为3)即可

(2)二维旋转变换矩阵:getRotationMatrix2D()

        计算二维旋转变换矩阵。变换会将旋转中心映射到它自身。

Mat getRotationMatrix2D(Point2f center, double angle, double scale)

  • 第一个参数,Point2f类型的center,表示源图像的旋转中心
  • 第二个参数,double类型的angle,旋转角度。角度为正值表示向逆时针旋转(坐标原点是左上角)。
  • 第三个参数,double类型的scale,缩放系数

此函数计算旋转缩放矩阵:

                                                           \begin{bmatrix} \alpha &\beta & \left ( 1-\alpha \right )\cdot center.x-\beta\cdot center.y \\ -\beta & \alpha & \beta \cdot center.x+\left ( 1-\alpha \right )\cdot center.y \end{bmatrix}

其中

                                                            \alpha =scale\cdot \cos angle;\beta =scale\cdot \sin angle

五、直方图均衡化

1. 概念

图像灰度数值范围比较小,导致图像对比度不强,特征不明显。扩大图像的动态范围

(1)直方图均衡化:通过拉伸像素强度分布范围来增强图像的对比度,对图像进行非线性拉伸,重新分配图像像素值,使一定灰度范围内的像素数量大致相同。其中心思想是把原始图像的灰度直方图从比较集中的某个灰度区间变成在全部灰度范围内的均匀分布。

(2)特点:

  • 扩大图像的动态范围,增强对比度,使得图像更具有表现力。
  • 原灰度不同图像经过直方图均衡化形成相同的灰度区域,导致各区域之间有明显的边界,从而出现伪轮廓。
  • 扩大了量化间隔,但量化级别(灰度级)减少了,导致某些细节消失。
  • 原来图像对比度很高,经过均衡化后,对比度可能下降或者保持不变。

(3)均衡化过程:

  • 计算输入图像的直方图H。
  • 进行直方图归一化,直方图的组距的和为255。
  • 计算直方图的积分:

                                          H^{'}\left ( i \right )=\sum_{0\leq j\leq i}H\left ( j \right )

  • H^{'}作为查询表进行图像变换:

                                       dst\left ( x,y \right )=H^{'}\left ( src\left ( x,y \right ) \right )

2. 函数

        在OpenCV中,直方图均衡化功能实现由equalizeHist函数实现,原型描述如下:

void equalizeHist(InputArray src,OutputArray dst)

  • 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可,需为8位单通道的图像。
  • 第二个参数,OutputArray类型的dst,函数调用后的运算结果存在这里,需和源图片有一样的尺寸和类型。

        由equalizeHist()函数实现的灰度直方图均衡化算法是把直方图的每一个灰度级进行归一化处理,求每一种灰度的累计分布,得到一个映射的灰度映射表,然后根据相应的灰度值来修正原图中的每一个像素灰度值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值