首页 > 编程知识 正文

仿射变换和透视变换(仿射变换矩阵)

时间:2023-05-03 18:19:51 阅读:85864 作者:800

的几何操作,即来自三维几何和投影几何的变换。 此操作包括调整均匀和不均匀的大小。 后者被称为扭曲。 这些操作有很多原因。 例如,扭曲或旋转图像,以便可以将图像重叠到现有场景中,或者人为放大一系列用于对象识别的训练图像。 拉伸、压缩、扭曲、旋转图像等功能称为几何变换。 平面区域包括两种类型的几何变换:使用23矩阵的变换(称为仿射变换)和仿射变换。 基于33矩阵进行变换,这称为透视变换。

仿射变换是可以用矩阵乘法和矢量加法的形式表现的变换。 在OpenCV中,表示该变换的标准样式是23矩阵。 定义:

可以容易看出仿射变换AXB的效果等同于将向量x扩展到向量x’并将x’简单地左乘t。

仿射变换可以表示如下。 平面上的任意平行四边形ABCD可以通过几个仿射变换映射到其他任意平行四边形A'B'C'D '。 如果这些平行四边形的面积不为零,则隐式仿射变换由两个平行四边形的“三个顶点”唯一定义。 想象一下仿射变换。 在较大的橡胶片上描绘图像,通过变形可以形成不同种类的平行四边形。

如果多个图像是同一对象的不同视图,则需要计算与不同视图相关联的实际变换。 在这种情况下,经常使用仿射变换而不是透视变换来对视图建模。 这是因为参数少,容易解决。 缺点是,由于只能以单应性模拟现实视角的失真,因此基于仿射变换的显示无法满足视图之间的所有可能的关系。

仿射变换可以将矩形变换为平行四边形。 虽然可以挤出形状,但必须使两侧保持平行; 可以旋转或缩放。 透视变换提高了灵活性。透视变换可以将矩形变为任意四边形

仿射变换有两种情况。 在第一种情况下,有想要转换的图像; 在第二种情况下,有想要计算转换结果的点的列表。 这些情况在概念上非常相似,但实际上非常不同。 因此,OpenCV有两个不同的功能。

在第一种情况下,导入和导出的格式是图像,隐含的要求是假设像素是底层图像的密集表示。 也就是说,为了使输出图像看起来平滑自然,图像变形需要进行插值处理。 OpenCV提供的用于高密度变换的仿射变换函数是warpAffine (。

void cv :扭曲仿射(

cv :输入阵列存储器,

cv :输出阵列磁盘,

cv :输入阵列m、

cv :大小尺寸,

int flags=cv :3360互联网。

intbordermode=cv :3360边框_常数、

const cv :3360 scalarbordervalue=cv :3360 scalar () ) ) ) ) ) ) ) ) )。

);

其中,src和dst分别是源和目标的图像。 输入m是前面介绍的23矩阵,用于量化所需的变换。 目标图像的每个元素都根据原始图进行计算,如下所示:

但是,一般来说,该方程式右边所指的位置不是整数像素。 在这种情况下,必须使用插值为dst(x,y )找到适当的值。 另一个选择是WARP_INVERSE_MAP 此选项允许从dst到src的反向扭曲,而不是从src到dst的反向扭曲。 最后一个参数用于边界,其含义与图像卷积的参数相同。

OpenCV提供了两个帮助生成矩阵m的函数。 第一个是在已经有两个图像的情况下使用的,我们知道它们通过仿射变换相关或类似。

cv : matcv :3360 getaffinetransform (

const cv :点2f * src,

常数cv :点2f * DST

);

其中,src和dst是包含三个二维点的数组。 返回值是数组,是根据这些点计算的仿射变换。

示例1显示了使用这些函数的代码。 本示例首先构建两个三分量点,然后使用getAffineTransform ()将其转换为实际的变换矩阵,从而获取warpAffine ) )矩阵参数。 然后进行仿射变形,旋转图像。 对于源图像的典型点阵列,取(0,0 )、) 0、height-1 )和) width-1,0,0 )三个点。 然后,指定这些点映射到相应数组中的位置。

例1仿射变换的示意图

# #包括opencv2/opencv.HPP

# #包含iostream

单一名称空间固态硬盘;

单一名称空间光碟;

int main (英特尔航空(英特尔航空* *航空) ) ) ) ) ) ) ) ) ) ) )。

{

mat src=im读取(e : /仿射变换. jpg ),1 );

命名窗口(“原图”,0

);     imshow("原图", src);     Point2f srcTri[] =     {          Point2f(0,0),                Point2f(src.cols - 1, 0),           Point2f(0, src.rows - 1)      };     Point2f dstTri[] = {          Point2f(src.cols*0.f, src.rows*0.33f),            Point2f(src.cols*0.85f, src.rows*0.25f),           Point2f(src.cols*0.15f, src.rows*0.7f)        };     // 计算仿射矩阵     Mat warp_mat = cv::getAffineTransform(srcTri, dstTri);     Mat dst, dst2;     warpAffine(          src,          dst,          warp_mat,          src.size(),          INTER_LINEAR,          BORDER_CONSTANT,          Scalar()     );     for (int i = 0; i < 3; ++i)          circle(dst, dstTri[i], 5, cv::Scalar(255, 0, 255), -1);     namedWindow("仿射变换", 0);     imshow("仿射变换", dst);     waitKey();     for (int frame = 0;; ++frame)     {          Point2f center(src.cols*0.5f, src.rows*0.5f);          double angle = frame * 3 % 360, scale = (cos((angle - 60)* CV_PI / 180) + 1.05)*0.8;          Mat rot_mat = getRotationMatrix2D(center, angle, scale);          warpAffine(              src,              dst2,              rot_mat,              src.size(),              INTER_LINEAR,              BORDER_CONSTANT,              Scalar()          );          namedWindow("仿射变换图像", 0);          imshow("仿射变换图像", dst2);          if (waitKey(30) >= 0)              break;     }     waitKey(0);     return 0; }

计算映射矩阵的第二种方法是使用cv :: getRotationMatrix2D(),它可以计算围绕某个任意点的旋转的映射矩阵,并结合可选的缩放比例。

cv::Mat cv::getRotationMatrix2D(

cv::Point2f center,

double angle,

double scale

);

第一个参数center是旋转的中心点。 接下来的两个参数给出了旋转的大小和缩放比例。 该函数返回映射矩阵M,它是浮点数的2×3矩阵。

warpAffine()是处理密集映射,对于稀疏映射,最好使用transform()。

void cv::transform(

cv::InputArray src,

cv::OutputArray dst,

cv::InputArray mtx

);

通常,src是具有Ds通道的N×1阵列,其中N是要变换的点的数量,Ds是这些源点的维度。 输出数组dst将具有相同的大小,但可能具有不同数量的通道Dd。 变换矩阵mtx是一个Ds×Dd矩阵,然后将其应用于src的每个元素,之后将结果放入dst。

给定以2×3矩阵表示的仿射变换,通常希望能够计算逆变换,其可用于将所有变换点“放回”到它们来自的地方。这是用invertAffineTransform()实现的:

void cv::invertAffineTransform(

cv::InputArray M,

cv::OutputArray iM

);

这个函数需要一个2×3的数组M,并返回另一个2×3的数组iM,它反转M。注意,cv :: invertAffineTransform()实际上不作用于任何图像,它只提供逆变换。一旦有了iM,就可以像使用M一样使用它,可以使用cv :: warpAffine()或cv :: transform()。

在实际应用中,可以利用仿射变换将倾斜的图像旋正。如下图所示,如果对于识别的字符是倾斜的,要进行字符分割可能不准确,尤其是分割算法要适应在线检测的大量图像的时候,这时,可以采用仿射变换将字符区域旋转到水平位置,这时再利用分割算法就可以适应大规模的图像分割。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。