在图像处理中,因为镜头角度等原因,容易导致图像出现倾斜、变形等情况,为了方便后续处理我们常常需要进行图像矫正,其中主要技术原理是两种变换类型--仿射变换(Affine Transformation)和透视变换(Perspective Transformation)。
仿射变换是二维坐标间的线性变换,故而变换后的图像仍然具有原图的一些性质,包括“平直性”以及“平行性”,常用于图像翻转(Flip)、旋转(Rotations)、平移(Translations)、缩放(Scale operations)等,具体到代码应用可以参见OpenCV官方介绍。
但是仿射变换不能矫正一些变形,如矩形区域的部分发生变化最终变成梯形,这时候矫正就需要用到透视变换。透视变换(Perspective Transformation),又称投影映射(Projective Mapping)、投射变换等,是三维空间上的非线性变换,即通过一个3x3的变换矩阵将原图投影到一个新的视平面,在视觉上的直观表现就是产生或消除了远近感。
1、首先第一步,先获取透视变换的变换矩阵,通过下面这个方法来获取:
Mat getPerspectiveTransform(const Point2f src[], const Point2f dst[])
输入原始图像和变换之后的图像的4组对应点,便可以得到变换矩阵。
2、透视变换。图像的透视变换由以下函数完成(该函数是针对图像的包装,其本质调用cv::perspectiveTransform进行向量坐标的变换):
void cv::warpPerspective (
InputArray src,
OutputArray dst,
InputArray M,
Size dsize,
int flags = INTER_LINEAR,
int borderMode = BORDER_CONSTANT,
const Scalar &borderValue = Scalar(0)
)
src是输入图像,dst是输出图像,M是3x3变换矩阵,dsize是输出图像的大小,flags指定像素插补方法以及矩阵倒置标志cv::WARP_INVERSE_MAP,CV_INTER_LINEAR填充所有目标图像的像素,如果部分图像落在边界外,那么它们的值将被设定为fillval
borderMode指定边沿像素的推算模式,其中BORDER_CONSTANT指边沿像素用borderValue替换,因为默认是0,所以我们变换后的图像边界可能会出现黑边,此时可以指定BORDER_REPLICATE对边界像素进行复制。
实例:
int TransforMatrix(vector screenPoints,vector wallPoints)
{
int screenPts_Len = screenPoints.size();
int wallPts_Len = wallPoints.size();
if (screenPts_Len != 4 || wallPts_Len != 4)
{
return PROJ_FAIL;
}
//原始图像四角点
cv::Point2f *pts_src;
//目标图像四角点
cv::Point2f *pts_dst;
//3 X 3变换矩阵
Mat m_MapMatrix;
//【0】映射对应点对
for (int k = 0; k < 4; k++)
{
pts_src[k] = wallPoints[k];
pts_dst[k] = screenPoints[k];
}
//【1】求得映射矩阵 m_MapMatrix 是3 x 3 变换矩阵
m_MapMatrix = getPerspectiveTransform(pts_src, pts_dst);
//【2】透视变换
//m_foreImg 与 screenImg大小相同
//m_dstWidth、m_dstHeight指目标函数宽、高
warpPerspective(m_foreImg, screenImg, m_MapMatrix, Size(m_dstWidth, m_dstHeight), CV_INTER_LINEAR , BORDER_REPLICATE);
//screenImg为转换后的图像
return PROJ_OK;
}
附两篇关于“透视变换”的博客:
https://blog.csdn.net/xiaowei_cqu/article/details/26471527
https://blog.csdn.net/u012590570/article/details/51355600