OpenCV各模块函数使用实例(8)--几何图像变换(Geometric Image Transformations)

        这一节介绍的函数执行2D图像上的各种几何变换。它们并不改变图像本身的内容,而是对变形的像素栅格进行校正并映射变形栅格到目的图像。事实上,为了避免采样空点痕迹,映射是逆序进行的(避免小数坐标位置点的空白),即,对于每一个目的图像的像素点(x,y),函数计算对应源图象的坐标,并拷贝这一点的值:

                                

 在指定了向前映射后 gx,gy:srcdstopenCV函数首先计算逆映射fx,fy:dstsrc ,然后再使用上面公式。

       几何变换的实际实现,从最普通的remap到最简单和快速的resize,都需要解决上面公式中的两个主要问题:

  1. 外推不存在的点。类似于前面章节中描述的滤波函数,对于某个(xy),或者是fx(x,y) fy(x,y),或二者均落在图像之外,此时,需要使用外推法。Opencv提供与滤波函数一样的外推算法选择方式。同时它还提供了一种算法BORDER_TRANSPARENT,意思是对应的像素在目的图像中不被修改。
  2. 内插像素值(插值)。通常,fx(x,y)和fy(x,y)都是浮点值。也就是说fx,fy 既可以是一个仿射或透明变换,也可以是径向透镜的畸变矫正。所以,小数坐标的像素值需要加以补偿。最简单的方法是使用最靠近的整数坐标并且使用对应像素的值,这就是称之为最近邻域插值的方法。然而较好的结果可以通过使用更复杂的插值方法获得。多项式函数适合像素(fx(x,y),fy(x,y))邻域计算,而多项式的值可以作为在(fx(x,y),fy(x,y))的插值像素值。在opencv中有多种插值方法可供选择。详细参见resize函数的注释。

       几何变换不能操作CV_8SCV_32S类型的图像。

1)、cv::remap (InputArray src, OutputArray dst, InputArray map1, InputArray map2,

     int interpolation, int borderMode=BORDER_CONSTANTconst Scalar &borderValue=Scalar())

对图像执行普通几何变换。这个函数使用指定的映射对图像进行再映射变换:

        ​​​​​​    

其中对于非整数坐标的像素使用合适的插值算法进行计算。mapx  mapy可以分别使用浮点映射map1  map2map1中(x,y)的交错浮点映射,或由convertMaps建立的浮点映射编码。remap函数的定点变换比浮点变换快2x。转换中map1含有(cvFloor(x), cvFloor(y))对,而map2含有插值系数表的索引。这个函数不支持源图像直接操作。

参数

src

源图像

dst

目的图像。它与map1有相同尺寸,而与src有相同类型

map1

第一个映射,或者是(x,y)点或者是x 值,有如下类型CV_16SC2,CV_32FC1,CV_32FC2,详见convertMaps关于转换浮点到定点的速度描述。

map2

第二映射,y的映射,有如下类型CV_16UC1,CV_32FC1,或空(当map1为(x,y)点时,为空映射)。

interpolation

插值算法(见InterpolationFlags)。这个函数不支持INTER_AREA 算法

borderMode

像素外推法(见BorderTypes)。当 borderMode = BORDER_TRANSPARENT时,说明目的图像中的超出源图像范围的像素不被函数修改

borderValue

用于边框内容的值。默认为0

由于当前实现的限制,输入输出图像的尺寸应该小于32767x32767

小结:目的图像是根据map1map2的映射给出的,当map1指定为(xy)形式时,说明映射已经由map1指定(两通道的浮点值),其中的(xy)表明了源图像对应的坐标(两通道分别是xy),对于map1 = mapxmap2=mapy的情况(分别是单通道图像),二者分别表示对应点在原图像中的坐标(mxmyà源图坐标。因此可以生成相关的map映射,如缩放、翻转,旋转等。

//缩放,比例=1/4

if (col >(src.cols * 0.25) && col <= (src.cols*0.75) &&

        row > (src.rows*0.25) && row <= (src.rows*0.75)) {

         map_x.at<float>(row, col) = 2 * (col - (src.cols*0.25));

         map_y.at<float>(row, col) = 2 * (row - (src.rows*0.25));

}else {

         map_x.at<float>(row, col) = 0;

         map_y.at<float>(row, col) = 0;

}

//左右翻转

map_x.at<float>(row, col) = (src.cols - col - 1);

map_y.at<float>(row, col) = row;

//旋转180

map_x.at<float>(row, col) = (src.cols - col - 1);

map_y.at<float>(row, col) = (src.rows - row - 1);

2)、cv::resize (InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0,

                                int interpolation=INTER_LINEAR)

改变图像尺寸。函数resize放大或缩小原图像到指定的尺寸。注意,初始的dst图像类型和尺寸是不再考虑范围内的。相反,其尺寸和类型是从srcdsizefxfy导出的。如果想要改变原图像使其适合预设立的dst,可如下使用resize函数:

        //显式指定dsize=dst.size();fxfy则被指定如下

        resize(src, dst, dst.size(), 0, 0, interpolation);

如果想要缩减图像使用2倍因子在每一个方向,则如下调用函数:

        // 指定fxfy 以及让函数计算目的图像的尺寸

        resize(src, dst, Size(), 0.5, 0.5, interpolation);

要缩小图像一般最好使用INTER_AREA插值,而放大图像则使用c::INTER_CUBIC ()  INTER_LINEAR (较快而且也较好)

参数

src

输入图像

dst

输出图像;有dsize (在非零时)的尺寸,或尺寸由src.size(),fx,和fy计算;dst的类型与src相同

dsize

输出图像的尺寸;如果等于0,则如下计算:

​ 或者dsize 或者fx和fy二者必须有一个是非0的

fx

水平轴的比例因子;当它等于0时,如下计算

 

fy

垂直轴的比例因子;如果等于0时,如下计算

  

interpolation

插值算法,见InterpolationFlags

参见

warpAffinewarpPerspectiveremap

3)、cv::convertMaps (InputArray map1, InputArray map2,

              OutputArray dstmap1, OutputArray dstmap2,int dstmap1type, bool nninterpolation=false)

转换图像的变换映射从一种表现形式到另一种表现形式(类型转换)。这个函数为remap转换映射对从一种表现形式到另一种表现形式。((map1.type()map2.type())  (dstmap1.type()dstmap2.type()))支持下面的选择:

  • (CV_32FC1, CV_32FC1)→(CV_16SC2, CV_16UC1)。这是最常用的转换操作,其中,初始的浮点映射(见remap)被转换成较简便且快得多的定点形式。头一个输出的数组含有整数坐标,第二个数组(仅在nninterpolation=false时建立)含有插值表的索引值
  • (CV_32FC2)→(CV_16SC2, CV_16UC1). 与上面的相同,但初始映射存储在2通道矩阵中
  • 逆转换。显然,这个重构的浮点映射与初始的并不精确相等

参数

map1

头一个输入的映射,类型为CV_16SC2,CV_32FC1,或 CV_32FC2

map2

第二个输入的映射,类型为CV_16UC1,CV_32FC1,或空矩阵

dstmap1

头一个输出的映射,其类型有dstmap1type的类型并与src有相同尺寸

dstmap2

第二个输出的映射

dstmap1type

头一个输出映射的类型,应该是CV_16SC2,CV_32FC1,或CV_32FC2

nninterpolation

标志,表示定点映射是用于最近邻域算法还是较复杂插值算法。

参见

remapundistortinitUndistortRectifyMap

4)、cv::getAffineTransform (const Point2f src[], const Point2f dst[])

             cv::getAffineTransform (InputArray src, InputArray dst)

用三个对应的点对计算一个仿射变换。这个函数计算仿射变换的2×3矩阵,如下:

                 ​

其中

                 ​

注:该函数返回2×3映射矩阵。

参数

src

源图像的三角形顶点坐标

dst

在目的图像中的对应三角形顶点坐标

参见

warpAffinetransform

5)、cv::invertAffineTransform (InputArray M, OutputArray iM)

逆仿射变换。这个函数计算一个2×3矩阵M表示的仿射变换的逆变换:

                        

结果也是一个与变换M同类型的2×3矩阵。

参数

M

初始仿射变换

iM

输出的逆仿射变换

6)、cv::getPerspectiveTransform (InputArray src, InputArray dst, 

                                int solveMethod=DECOMP_LU)

cv::getPerspectiveTransform (const Point2f src[], const Point2f dst[],

                                int solveMethod=DECOMP_LU)

用四个对应点对计算透射变换。这个函数计算透射变换的3×3矩阵使得下式成立:

        ​​​​​​​        ​​​​​​​         ​

其中

        ​​​​​​​        ​​​​​​​        

参数

src

源图像四边形顶点的坐标

dst

目的图像中对应的四边应顶点坐标

solveMethod

传递到cv::solve (DecompTypes)的算法

参见

findHomographywarpPerspectiveperspectiveTransform

7)、cv::getRotationMatrix2D (Point2f center, double angle, double scale)

             cv::getRotationMatrix2D_ (Point2f center, double angle, double scale)

计算2D旋转的仿射矩阵。这个函数计算下面的矩阵:

        ​​​​​​​         ​

其中

        ​​​​​​​         ​

这个变换映射旋转中心到它自身。如果不对,可以调节偏移参量。

参数

center

原图象的旋转中心

angle

度数为单位的旋转角度。正值表示逆时针旋转(坐标原点设定为左上角)

scale

各向同性的比例因子

参见

getAffineTransformwarpAffinetransform

(8)、cv::getRectSubPix (InputArray image, Size patchSize, Point2f center,

        ​​​​​​​        ​​​​​​​        ​​​​​​​        OutputArray patch, int patchType=-1)

以亚像素级精度重新定位一个图像的矩形。函数getRectSubPix从原图像中提取像素:

        ​​​​​​​        

此时在非整数坐标点的像素值使用插值获得。多通道图像的每一个通道都单独处理。当然,图像应该是单通道或三通道的。而矩形的中心必须落在图像内,部分矩形可以落在图像外。

参数

image

源图像

patchSize

提取的补丁尺寸

center

源图像内提取矩形的中心浮点坐标,这个中心必须在图像内

patch

提取的补丁图像,有patchSize尺寸和与源图像相同的通道数。

patchType

提取像素的深度。默认与源图像有相同的深度

See also

warpAffinewarpPerspective

9)、cv::linearPolar (InputArray src, OutputArray dst,

        ​​​​​​​        ​​​​​​​        ​​​​​​​        Point2f center, double maxRadius, int flags)

映射图像到极坐标空间。这是一个被遗弃的函数,其结果与cv::warpPolar相同。

10)、cv::logPolar (InputArray src, OutputArray dst,

        ​​​​​​​        ​​​​​​​        ​​​​​​​        Point2f center, double M, int flags)

映射图像到半对数极坐标空间。这是一个被遗弃的函数,其结果与cv::warpPolar相同。

11)、cv::warpAffine (InputArray src, OutputArray dst, InputArray M,

     ​​​​​​​        ​​​​​​​        ​​​​​​​        Size dsize, int flags=INTER_LINEARint borderMode=BORDER_CONSTANT,

                             const Scalar &borderValue=Scalar())

对图像执行仿射变换。函数warpAffine使用指定的矩阵对源图像进行变换:

        ​​​​​​​        ​​​​​​​         ​

当标志设置为WARP_INVERSE_MAP 时,直接使用上面公式。否则,先使用invertAffineTransform进行逆变换,然后再使用逆变换的矩阵代替上面的M使用上面公式进行变换操作。这个函数不能使用源图像直接操作。

参数

src

输入图像

dst

有指定尺寸dsize 的输出图像,与源图像有相同类型

M

2×3 变换矩阵

dsize

输出图像的尺寸

flags

组合插值算法(见InterpolationFlags)与可选择标志WARP_INVERSE_MAP ,这个标志说明M是逆变换(dst→src)

borderMode

外推像素算法(见BorderTypes);当borderMode=BORDER_TRANSPARENT时,说明目的图像中对应超源图像范围的像素在函数中不被修改(在图像叠加时可用到透明标志)

borderValue

在常量边框情况下使用的像素值;默认为0

See also

warpPerspectiveresizeremapgetRectSubPixtransform

12)、cv::warpPerspective (InputArray src, OutputArray dst, InputArray M,

        ​​​​​​​        ​​​​​​​        Size dsize, int flags=INTER_LINEARint borderMode=BORDER_CONSTANT,

                        const Scalar &borderValue=Scalar())

对图像进行透射变换。函数warpPerspective使用指定的矩阵变换源图像:

        ​​​​​​​        ​​​​​​​         

在标志设置为WARP_INVERSE_MAP 时直接使用上面公式,否则,先进行逆变换映射M,然后再使用获得的逆映射矩阵代替M使用上面公式。这个函数不能源图像直接操作。

参数

src

输入图像

dst

有dsize尺寸的输出图像,与源图像同类型

M

3×3 变换矩阵

dsize

输出图像尺寸

flags

插值算法(INTER_LINEARINTER_NEAREST) 与选择标志WARP_INVERSE_MAP的组合,这个标志可以设置M作为逆变换(dst→src)

borderMode

像素外推算法(BORDER_CONSTANT 或 BORDER_REPLICATE)

borderValue

常量边框使用的像素值;默认为0

参见

warpAffineresizeremapgetRectSubPixperspectiveTransform

13)、cv::warpPolar (InputArray src, OutputArray dst,

        ​​​​​​​        ​​​​​​​        ​​​​​​​        Size​​​​​​​ dsize, Point2f center, double maxRadius, int flags)

映射图像到极坐标或半对数极坐标空间。

极坐标映射参照系

使用下面的变换转换源图像:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        

其中

        ​​​​​​​        ​​​​​​​        ​​​​​​​         ​

        ​​​​​​​        ​​​​​​​        ​​​​​​​         ​

线性或半对数映射。

极坐标映射可以是线性的或半对数的。附加一个WarpPolarMode flags 来指定特殊的极坐标映射模式。

线性是默认模式。半对数映射仿真了人类的“视网膜曲面”的视觉,对视线中心有非常高的灵敏度,而对视线外围灵敏度较低。

关于dsize的选择:

  • 如果dsize的两个值dsize <=0 (默认),则目的图像几乎与源图象的外接圆有相同的面积:        

      

  • 如果仅是dsize.height <= 0,则目的图像的面积将是Kx * Kx因子等比例的外接圆面积:​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

  • 如果dsize的两个值dsize > 0,则,目的图像有给定的尺寸,因而外接圆的面积等比例于dsize。

反向映射

附加WARP_INVERSE_MAPflag,可以获得反向映射(逆映射)

//直接变换

warpPolar(src,lin_polar_img,Size(),center,maxRadius,flags);//线性极坐标

warpPolar(src,log_polar_img,Size(),center,maxRadius,flags+WARP_POLAR_LOG);//半对数极坐标

//逆变换

warpPolar(lin_polar_img,recovered_lin_polar_img,src.size(),center,maxRadius,flags+        WARP_INVERSE_MAP);

warpPolar(log_polar_img,recovered_log_polar,src.size(),center,maxRadius,flags+WARP_POLAR_LOG+WARP_INVERSE_MAP);

此外,要从极坐标映射的坐标计算初始坐标(rho,phi)−>(x,y),如下

   double angleRad, magnitude;

   double Kangle = dst.rows / CV_2PI;

   angleRad = phi / Kangle;

   if (flags & WARP_POLAR_LOG){

      double Klog = dst.cols / std::log(maxRadius);

      magnitude = std::exp(rho / Klog);

   }else{

      double Klin = dst.cols / maxRadius;

      magnitude = rho / Klin;

   }

   int x = cvRound(center.x + magnitude * cos(angleRad));

   int y = cvRound(center.y + magnitude * sin(angleRad));

参数

src

源图像

dst

目的图像。与源图像同类型

dsize

目的图像尺寸(参见可用选择的描述)

center

变换的中心

maxRadius

变换的外接圆半径。它也确定逆映射的模的比例参数。

flags

组合插值算法InterpolationFlags + WarpPolarMode的标志

注意

  • 这个函数不能源图像直接操作。
  • 计算模和度数单位的角度,内部使用了cartToPolar 因而角度的度数在0360范围,精度为0.3
  • 这个函数使用了remap。当前的实现限制了输入输出图像的尺寸必需小于32767 x 32767

参见

cv::remap

几何图像变换(Geometric Image Transformations)编程实例

几何变换属于图像的空间变换范畴,与灰度和颜色变换不同,是对像素点的几何空间进行调整,比如消除光学畸变,图像的缩放等。几何变换通过空间变换矩阵计算像素平面或立体空间的位置,通过变换形成新的图像,比如旋转,平移,极坐标变换等。可以通过几何变换使图像从一个平面转换到另一个平面,此两平面可以是不共面的空间平面。

1、void cv::remap (InputArray src, OutputArray dst, 

        ​​​​​​​        ​​​​​​​        InputArray map1, InputArray map2,

                        int interpolation, int borderMode=BORDER_CONSTANT,

                        const Scalar &borderValue=Scalar())

       使用指定的映射对图像进行变换,可以是翻转、缩放、旋转等。其中的map映射是已经经过变换矩阵计算过的浮点坐标。

 

这是使用remap做对角线翻转操作的例子,根据映射要求,先计算出mapxmapy,然后使用remap即可。

2、void cv::resize (InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0,

                                int interpolation=INTER_LINEAR)

根据指定比例缩放图像,对于非整数坐标像素点使用指定插值算法进行估值,对于缩小图像,采用INTER_AREA插值算法较好,对于放大图像,采用INTER_CUBIC(慢),或INTER_LINEAR(快并且好)插值算法为好。

源图和放大图。可以按比例缩放,也可以指定尺寸缩放。

3、void cv::convertMaps (InputArray map1, InputArray map2,

        ​​​​​​​        ​​​​​​​        OutputArray dstmap1, OutputArray dstmap2,

                        int dstmap1type, bool nninterpolation=false)

对映射的类型进行变换,以求加快remap函数的处理速度。比如在图像旋转映射中,浮点类型的映射到定点类型的映射,remap的处理速度可能要提高20%左右,到整数类型映射则可提高2xconvertMaps是图像变换的中间处理函数,它转变映射的类型,无论是(x,y)形式的映射还是mapxmapy形式的映射,都可以通过该函数进行映射类型的转换,然后通过remap对图像进行变换处理。这种映射类型的转换对单个图片处理意义不大,因为对于提高速度的几十毫秒,一般是感觉不到的。但是对于视频流则显得尤为重要,提高的几十毫秒能够影响到视频的流畅性。比如相机的光学畸变矫正(美颜等),电子变形等固定的映射环境下使用convertMaps函数转换映射到整数类型,然后在视频流中使用remap对帧图像进行变换。

小图片看不出来处理的延迟,视频流则能够感觉到convertMaps带来的好处,一般opencv的几何变换函数都自动调用convertMaps进行处理。

4、Mat cv::getAffineTransform (const Point2f src[], const Point2f dst[])

        ​​​​​​​        ​​​​​​​        Mat cv::getAffineTransform (InputArray src, InputArray dst)

仿射变换是对空间的投影平面进行旋转和平移的变换,可以将矩形转换成平行四边形,它可以将矩形的边压扁但必须保持边是平行的,也可以将矩形旋转或者按比例缩放。

根据给定的点建立仿射变换矩阵,可以在某个方向上拉伸或压缩。

5、void cv::invertAffineTransform (InputArray M, OutputArray iM)

一个变换的逆变换是恢复变换,如图:

左为源图,中为M([10,-10],[-10,-10],[-10,-10])的变换,右为M的逆变换。可以看出,恢复的源图有些差异,不是完全等同于源图。一个是变换的截断部分被丢弃,另一个是边缘有锯齿状。

6、Mat cv::getPerspectiveTransform (InputArray src, InputArray dst,

                                int solveMethod=DECOMP_LU)

      Mat cv::getPerspectiveTransform (const Point2f src[], const Point2f dst[],

                                int solveMethod=DECOMP_LU)

透射变换是对空间的投影平面进行旋转和平移的变换,是将一个矩形变换成梯形或四边形的变换。用于矫正光学系统的线性畸变。它用四个点对描述源目之间的畸变特征。如图:

7、Mat cv::getRotationMatrix2D (Point2f center, double angle, double scale)

      Mat cv::getRotationMatrix2D_ (Point2f center, double angle, double scale)

计算图像相对于指定的中心点和角度的旋转矩阵(2x3矩阵)。其中scale为缩放参数,scale<1为放大,scale>1位缩小。角度为度数单位。图像的左上角为坐标原点。求得旋转矩阵后,使用warpAffine函数变换图像。显示指针式仪表刻度,经常会用到图像的旋转操作,使用刻度值控制指针图像的旋转,然后透明贴到仪表盘上。

旋转仪表指针,然后贴图操作。

8、void cv::getRectSubPix (InputArray image, Size patchSize, Point2f center,

        ​​​​​​​        ​​​​​​​        ​​​​​​​        OutputArray patch, int patchType=-1)

从原图像中截取一块矩形补丁图像,这个矩形补丁的坐标是浮点精度的(亚像素级精度)。对于目标的跟踪、截取和识别操作,使用这个函数精确地截取部分图像进行识别。

在矩形边缘超出图像范围时,自动填补边缘像素。

9、cv::linearPolar (InputArray src, OutputArray dst,

        ​​​​​​​        ​​​​​​​        Point2f center, double maxRadius, int flags)

10、cv::logPolar (InputArray src, OutputArray dst,

        ​​​​​​​        ​​​​​​​        Point2f center, double M, int flags)

这是两个过时的极坐标变换函数,使用warpPolar函数替代。

11、void cv::warpAffine (InputArray src, OutputArray dst, InputArray M,

        ​​​​​​​        Size dsize, int flags=INTER_LINEARint borderMode=BORDER_CONSTANT,

                const Scalar &borderValue=Scalar())

执行仿射变换,使用指定的变换映射M变换图像(2x3映射矩阵)。可以指定使用的插值算法和边界替代形式。计算M可以使用getAffineTransform函数。

12、void cv::warpPerspective (InputArray src, OutputArray dst, InputArray M,

        ​​​​​​​        Size dsize, int flags=INTER_LINEARint borderMode=BORDER_CONSTANT,

                const Scalar &borderValue=Scalar())

执行透射变换,使用指定的变换映射M变换图像(3x3映射矩阵)。可以指定使用的插值算法和边界替代形式。计算M可以使用getPerspectiveTransform函数。

13、void cv::warpPolar (InputArray src, OutputArray dst,

        ​​​​​​​        ​​​​​​​        ​​​​​​​        Size dsize, Point2f center, double maxRadius, int flags)

执行极坐标变换。对图像指定中心点和半径的区域用极坐标展开。如图:

左图为源图,标记的圆范围内图像数据被极坐标变换展开如右图。展开点从红线半径开始顺时针方向。逆变换则是将图像的极坐标变换成直角坐标,如图:

注意,逆变换有一个水平方向上的偏移,因此上图被截断了一部分。适当调整中心的偏移位置,可获得逆变换图像:

​​​​​​​​

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

愚鬼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值