这一节介绍的函数执行2D图像上的各种几何变换。它们并不改变图像本身的内容,而是对变形的像素栅格进行校正并映射变形栅格到目的图像。事实上,为了避免采样空点痕迹,映射是逆序进行的(避免小数坐标位置点的空白),即,对于每一个目的图像的像素点(x,y),函数计算对应源图象的坐标,并拷贝这一点的值:
在指定了向前映射后 〈gx,gy〉:src→dst,openCV函数首先计算逆映射〈fx,fy〉:dst→src ,然后再使用上面公式。
几何变换的实际实现,从最普通的remap到最简单和快速的resize,都需要解决上面公式中的两个主要问题:
注
几何变换不能操作CV_8S或CV_32S类型的图像。
(1)、cv::remap (InputArray src, OutputArray dst, InputArray map1, InputArray map2,
int interpolation, int borderMode=BORDER_CONSTANT, const Scalar &borderValue=Scalar())
对图像执行普通几何变换。这个函数使用指定的映射对图像进行再映射变换:
其中对于非整数坐标的像素使用合适的插值算法进行计算。mapx 和 mapy可以分别使用浮点映射map1 和 map2,或map1中(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
小结:目的图像是根据map1和map2的映射给出的,当map1指定为(x,y)形式时,说明映射已经由map1指定(两通道的浮点值),其中的(x,y)表明了源图像对应的坐标(两通道分别是x,y),对于map1 = mapx,map2=mapy的情况(分别是单通道图像),二者分别表示对应点在原图像中的坐标(mx,my)à源图坐标。因此可以生成相关的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
map_y.at
}else {
map_x.at
map_y.at
}
//左右翻转
map_x.at
map_y.at
//旋转180度
map_x.at
map_y.at
(2)、cv::resize (InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0,
int interpolation=INTER_LINEAR)
改变图像尺寸。函数resize放大或缩小原图像到指定的尺寸。注意,初始的dst图像类型和尺寸是不再考虑范围内的。相反,其尺寸和类型是从src,dsize,fx和fy导出的。如果想要改变原图像使其适合预设立的dst,可如下使用resize函数:
//显式指定dsize=dst.size();fx和fy则被指定如下
resize(src, dst, dst.size(), 0, 0, interpolation);
如果想要缩减图像使用2倍因子在每一个方向,则如下调用函数:
// 指定fx和fy 以及让函数计算目的图像的尺寸
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 |
参见
warpAffine, warpPerspective, remap
(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()))支持下面的选择:
参数
map1 |
头一个输入的映射,类型为CV_16SC2,CV_32FC1,或 CV_32FC2 |
map2 |
第二个输入的映射,类型为CV_16UC1,CV_32FC1,或空矩阵 |
dstmap1 |
头一个输出的映射,其类型有dstmap1type的类型并与src有相同尺寸 |
dstmap2 |
第二个输出的映射 |
dstmap1type |
头一个输出映射的类型,应该是CV_16SC2,CV_32FC1,或CV_32FC2 |
nninterpolation |
标志,表示定点映射是用于最近邻域算法还是较复杂插值算法。 |
参见
remap, undistort, initUndistortRectifyMap
(4)、cv::getAffineTransform (const Point2f src[], const Point2f dst[])
cv::getAffineTransform (InputArray src, InputArray dst)
用三个对应的点对计算一个仿射变换。这个函数计算仿射变换的2×3矩阵,如下:
其中
注:该函数返回2×3映射矩阵。
参数
src |
源图像的三角形顶点坐标 |
dst |
在目的图像中的对应三角形顶点坐标 |
参见
warpAffine, transform
(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)的算法 |
参见
findHomography, warpPerspective, perspectiveTransform
(7)、cv::getRotationMatrix2D (Point2f center, double angle, double scale)
cv::getRotationMatrix2D_ (Point2f center, double angle, double scale)
计算2D旋转的仿射矩阵。这个函数计算下面的矩阵:
其中
这个变换映射旋转中心到它自身。如果不对,可以调节偏移参量。
参数
center |
原图象的旋转中心 |
angle |
度数为单位的旋转角度。正值表示逆时针旋转(坐标原点设定为左上角) |
scale |
各向同性的比例因子 |
参见
getAffineTransform, warpAffine, transform
(8)、cv::getRectSubPix (InputArray image, Size patchSize, Point2f center,
OutputArray patch, int patchType=-1)
以亚像素级精度重新定位一个图像的矩形。函数getRectSubPix从原图像中提取像素:
此时在非整数坐标点的像素值使用插值获得。多通道图像的每一个通道都单独处理。当然,图像应该是单通道或三通道的。而矩形的中心必须落在图像内,部分矩形可以落在图像外。
参数
image |
源图像 |
patchSize |
提取的补丁尺寸 |
center |
源图像内提取矩形的中心浮点坐标,这个中心必须在图像内 |
patch |
提取的补丁图像,有patchSize尺寸和与源图像相同的通道数。 |
patchType |
提取像素的深度。默认与源图像有相同的深度 |
See also
warpAffine, warpPerspective
(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_LINEAR, int 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
warpPerspective, resize, remap, getRectSubPix, transform
(12)、cv::warpPerspective (InputArray src, OutputArray dst, InputArray M,
Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT,
const Scalar &borderValue=Scalar())
对图像进行透射变换。函数warpPerspective使用指定的矩阵变换源图像:
在标志设置为WARP_INVERSE_MAP 时直接使用上面公式,否则,先进行逆变换映射M,然后再使用获得的逆映射矩阵代替M使用上面公式。这个函数不能源图像直接操作。
参数
src |
输入图像 |
dst |
有dsize尺寸的输出图像,与源图像同类型 |
M |
3×3 变换矩阵 |
dsize |
输出图像尺寸 |
flags |
插值算法(INTER_LINEAR或INTER_NEAREST) 与选择标志WARP_INVERSE_MAP的组合,这个标志可以设置M作为逆变换(dst→src) |
borderMode |
像素外推算法(BORDER_CONSTANT 或 BORDER_REPLICATE) |
borderValue |
常量边框使用的像素值;默认为0 |
参见
warpAffine, resize, remap, getRectSubPix, perspectiveTransform
(13)、cv::warpPolar (InputArray src, OutputArray dst,
Size dsize, Point2f center, double maxRadius, int flags)
映射图像到极坐标或半对数极坐标空间。
极坐标映射参照系
使用下面的变换转换源图像:
其中
且
线性或半对数映射。
极坐标映射可以是线性的或半对数的。附加一个WarpPolarMode 到flags
来指定特殊的极坐标映射模式。
线性是默认模式。半对数映射仿真了人类的“视网膜曲面”的视觉,对视线中心有非常高的灵敏度,而对视线外围灵敏度较低。
关于dsize的选择:
dsize <=0
(默认),则目的图像几乎与源图象的外接圆有相同的面积: 如果仅是dsize.height <= 0
,则目的图像的面积将是Kx * Kx
因子等比例的外接圆面积:
dsize > 0
,则,目的图像有给定的尺寸,因而外接圆的面积等比例于dsize。反向映射
附加WARP_INVERSE_MAP到flag,可以获得反向映射(逆映射)
//直接变换
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的标志
|
注意
参见
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做对角线翻转操作的例子,根据映射要求,先计算出mapx,mapy,然后使用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%左右,到整数类型映射则可提高2x。convertMaps是图像变换的中间处理函数,它转变映射的类型,无论是(x,y)形式的映射还是mapx,mapy形式的映射,都可以通过该函数进行映射类型的转换,然后通过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_LINEAR, int 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_LINEAR, int 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)
执行极坐标变换。对图像指定中心点和半径的区域用极坐标展开。如图:
左图为源图,标记的圆范围内图像数据被极坐标变换展开如右图。展开点从红线半径开始顺时针方向。逆变换则是将图像的极坐标变换成直角坐标,如图:
注意,逆变换有一个水平方向上的偏移,因此上图被截断了一部分。适当调整中心的偏移位置,可获得逆变换图像: