在PS、画图板等工具里,我们常常用到放大、缩小、扭曲、旋转等等的一些图像变换,那么这一次,我们使用openCV来实现以下图像常用的几种变换方法。
一、重映射
什么是重映射?
名字听上去是比较高端,但是实际上,它的原理很简单,就是将原图像通过一定的数学公式映射到另一幅图像中去,通俗点讲就是把一幅图像中某位置的元素放置到另一幅图像中的指定位置的这么一个方法。
重映射中的差值过程:
因为重映射中x,y计算后可以为double类型,这意味着计算后需要四舍五入,很有可能造成目标图像某些点没有像素,那么此时就需要插值,openCV重映射函数提供了四种插值方法:
1.最近邻插值
2.双线性(默认)
3.像素区域重新采样
4.双三次插值
openCV中提供的重映射函数:
void cvRemap(
const CvArr* src,
CvArr* dst,
const CvArr* mapx,
const CvArr* mapy,
int flag = CV_INTER_LINEAR | CV_WARP_FILL_OUTLIERS
CvScalar fillval = cvScalarAll(0)
);
我们讨论如下四种映射:
(1)图像缩小并显示在窗口中心位置:
映射关系:dst.x = 2 * scr.x -0.5 * width
dst.y = 2 * scr.y -0.5 * height
(推的时候反推比较好,就是从scr向dst推导)
(2)图像上下颠倒:
映射关系:
dst.x = scr.x
dst.y = height - scr.y
(3)图像左右颠倒:
映射关系:
dst.x = width - scr.x
dst.y = scr.y
(4)图像上下左右均颠倒:
映射关系:
dst.x = width - scr.x
dst.y = height - scr.y
编程关键函数如下:
IplImage* MyRemap(IplImage* img, int choose)
{
IplImage* dst = cvCreateImage(cvGetSize(img), 8, 3);
CvMat* matx = cvCreateMat(img->height, img->width, CV_32FC1);
CvMat* maty = cvCreateMat(img->height, img->width, CV_32FC1);
for (int i = 0; i < img->height; i++)
{
for (int j = 0; j < img->width; j++)
{
switch (choose)
{
case 1://缩小并显示在最中心
if (j > img->width*0.25 && j < img->width*0.75 && i > img->height*0.25 && i < img->height*0.75)
{
*((float*)CV_MAT_ELEM_PTR(*matx, i, j)) = 2 * (j - img->width*0.25);
*((float*)CV_MAT_ELEM_PTR(*maty, i, j)) = 2 * (i - img->height*0.25);
}
else
{
*((float*)CV_MAT_ELEM_PTR(*matx, i, j)) = 0;
*((float*)CV_MAT_ELEM_PTR(*maty, i, j)) = 0;
}
break;
case 2:
*((float*)CV_MAT_ELEM_PTR(*matx, i, j)) = j;
*((float*)CV_MAT_ELEM_PTR(*maty, i, j)) = img->height - i;
break;
case 3:
*((float*)CV_MAT_ELEM_PTR(*matx, i, j)) = img->width - j;
*((float*)CV_MAT_ELEM_PTR(*maty, i, j)) = i;
break;
case 4:
*((float*)CV_MAT_ELEM_PTR(*matx, i, j)) = img->width - j;
*((float*)CV_MAT_ELEM_PTR(*maty, i, j)) = img->height - i;
break;
default:
break;
}
}
}
cvRemap(img, dst, matx, maty, CV_INTER_LINEAR);
return dst;
}
结果分别:
原图:
图像缩小并居中显示 图像上下颠倒
图像左右颠倒 图像上下左右颠倒
二、仿射变换
对平面图像进行几何变换,有两种转换方式:一种是基于2*3矩阵进行的变换,称为仿射变换;另一种是基于3*3矩阵进行的变换,称作透视变换。那么这里先讨论仿射变换,以下两种情况我们将使用到仿射变换:第一种是有一幅想要转换的图像,我们使用稠密仿射转换;第二种是我们有一个点序列并向以此进行转换,我们使用稀疏仿射变换,这里我们着重介绍稠密仿射变换。
过多的理论知识这里我不作解释,因为解释太过空洞,我想用通俗易懂,简单直接的方式来介绍到底什么是仿射变换。
仿射变换到底是用来干什么的?
实际上,仿射变换的作用可以说是将图像中一个平行四边形通过数学方法变换到另一个平行四边形,图像内容没有变换但是所承载的区域位置发生的变换,给人最直观的感觉就是旋转,缩放。
仿射如何变换,也就是我们要输入什么,输出什么?
上述解释道仿射变换实际上就是平行四边形的变换,那么有两种方法进行这种变换:
(1)坐标确定法:三个点将确定一个平行四边形,那么原图确定一个平行四边形,目标图确定指定的平行四边形,即可变换;
(2)旋转角变换法:目标图的平行四边形可以看做是原图的平行四边形缩放、旋转得到的,那么确定这个旋转中心、旋转角、缩放比例,即可变换。
openCV函数如何实现该变换?
实现稠密仿射变换的函数是 void cvWarpAffine(
const CvArr* scr,
CvArr* dst,
const CvMat* map_matirx,
int flags = CV_INTEAR | CV_WARP_FILL_OUTLIERS,
CvScalar fillval = cvScalarAll(0)
);
这里map_matrix是变换的关键,也就是上述所说的2*3的变换矩阵,关键是要得到这个变换矩阵,openCV根据我说的两种变换方法,提供了两种得到变换矩阵的方法:
(1)坐标确定法: CvMat* cvGetAffineTransform(
const CvPoint2D32f* pts_src,
const CvPoint2D32f* pts_dst,
CvMat* map_matrix
);
这里的pts_src、pts_dst分别是原图和目标图的三个二维坐标点。
(2)旋转确定法 CvMat* cv2DRotationMatrix(
CvPoint2D32f center,
double angle,
double scale,
CvMat* map_matrix
);
这里的center、angle、scale分别是旋转中心、旋转角(度数)、缩放比例系数。
关键函数代码实现:
IplImage* MyWarpAffine1(IplImage* img)
{//使用坐标点确定平行四边形的方法
IplImage* dst = cvCreateImage(cvGetSize(img), 8, 3);
CvMat* mymat = cvCreateMat(2, 3, CV_32FC1);
CvPoint2D32f scrTri[3], dstTri[3];
//设置scr和dst的平行四边形的点
scrTri[0].x = 0;
scrTri[0].y = 0;//原图左上角
scrTri[2].x = 0;
scrTri[2].y = img->height;//原图左下角
scrTri[1].x = img->width;
scrTri[1].y = 0;//原图右上角
dstTri[0].x = img->width * 0.0;
dstTri[0].y = img->height * 0.33;
dstTri[1].x = img->width * 0.85;
dstTri[1].y = img->height * 0.25;
dstTri[2].x = img->width * 0.15;
dstTri[2].y = img->height * 0.7;
cvGetAffineTransform(scrTri, dstTri, mymat);
cvWarpAffine(img, dst, mymat);
return dst;
}
IplImage* MyWarpAffine2(IplImage* img)
{//使用旋转角确定平行四边形的方法
IplImage* dst = cvCreateImage(cvGetSize(img), 8, 3);
CvMat* mymat = cvCreateMat(2, 3, CV_32FC1);
CvPoint2D32f center;
center.x = img->width / 2;
center.y = img->height / 2;
double angle = 45;
double scale = 0.5;
cv2DRotationMatrix(center, angle, scale, mymat);
cvWarpAffine(img, dst, mymat);
return dst;
}
注意:对于坐标确定法,坐标的顺序要是相互对应的,比如说src是左上、左下、右上则dst的顺序也必须是左上、左下、右上!!!
实验结果:
原图:
坐标确定法 旋转角确定法
从《Learning openCV》一书了解到,因为开销问题,有一个更佳的仿射函数:
void cvGetQuadranglesubpix(
const CvArr* scr,
CvArr* dst,
const CvMat* map_matirx,
);
使用方法与上述函数类似,直接替代即可,这里不再赘述。
对于稀疏仿射变换,可以使用cvTransform(
const CvArr* scr,
CvArr* dst,
const CvMat* transmat,
const CvMat* shiftvec = NULL
);
函数
三、透视变换
和仿射变换相类似,不同的是,透视变换可以将一个平行四边形变成任意的梯形。这使得变换更加的灵活。因为很多参数及其使用都与仿射变换相同,这里只会简单介绍,并标明需要注意与仿射的区别。
openCV函数:
变换函数: void cvWarpPerspective(
const CvArr* scr,
CvArr* dst,
const CvMat* map_matirx,
int flags = CV_INTEAR | CV_WARP_FILL_OUTLIERS,
CvScalar fillval = cvScalarAll(0)
);
这里的变换矩阵维数是3*3的。
矩阵计算函数: CvMat* cvGetPerspectiveTransform(
const CvPoint2D32f* pts_src,
const CvPoint2D32f* pts_dst,
CvMat* map_matrix
);
这里与仿射不同的是,pts_src、pts_dst都是四个二维坐标点而不是三个!
关键函数编程如下:
IplImage* mywarpperspectiv(IplImage* img)
{
IplImage* dst = cvCreateImage(cvGetSize(img), 8, 3);
CvMat* mymat = cvCreateMat(3, 3, CV_32FC1);
CvPoint2D32f srcQuad[4], dstQuad[4];
srcQuad[0].x = 0;
srcQuad[0].y = 0;
srcQuad[1].x = img->width;
srcQuad[1].y = 0;
srcQuad[2].x = 0;
srcQuad[2].y = img->height;
srcQuad[3].x = img->width;
srcQuad[3].y = img->height;
dstQuad[0].x = img->width * 0.05;
dstQuad[0].y = img->height * 0.33;
dstQuad[1].x = img->width * 0.9;
dstQuad[1].y = img->height * 0.25;
dstQuad[2].x = img->width * 0.2;
dstQuad[2].y = img->height * 0.7;
dstQuad[3].x = img->width * 0.8;
dstQuad[3].y = img->height * 0.9;
cvGetPerspectiveTransform(srcQuad, dstQuad, mymat);
cvWarpPerspective(img, dst, mymat);
return dst;
}
效果:
同仿射,上述说明的是稠密透视变换的变换方法!
相关推荐
由于Python的简洁性和易学性,即使是编程初学者也能在几小时内快速入门,并借助Numpy和matplotlib库提升数据分析的能力。Python被称作是胶水语言,可以将不同的软件组合在一起,构建出功能强大的工作流。例如,在...
图像处理基础部分介绍了几种基本的图像类型: - **二值图像**:只有黑白两色,用0表示黑色,1表示白色。 - **灰度图像**:使用256级灰度,数值范围从0(黑色)到255(白色)。 - **彩色图像**:通常使用RGB色彩空间...
最后,教程详细讲解了OpenCV中的数学工具以及图像处理技术,包括颜色空间转换、物体跟踪以及各种几何变换,如图像的缩放、平移、旋转和仿射变换。其中特别提到了如何在HSV颜色空间下找到跟踪对象的值。 整体来看,...
首先,opencv入门需要学习一些基础的计算机视觉概念,如图像处理、特征检测、物体识别等。在学习过程中,实践是非常重要的。通过编写代码来实现图像处理和分析的功能,可以帮助我们更好地理解理论知识。 在opencv的...
OpenCV提供了几种核心数据类型,如`cv::Mat`用于表示图像,`Point`, `Rect`, `Size`等结构体用于描述几何形状。理解这些类型是进行图像处理的基础。 **4. 图像读取与显示** 使用`imread()`函数可以从文件中加载图像...
面向初学者的OpenCV-Python教程教程地址:本仓库为教程中所用到的源码、图片和音视频素材等目录入门篇标题简介了解和安装OpenCV-Python度量运行时间/提升效率的几种方式图片的载入/显示和保存高保真保存图片、...
【OpenCV入门教程之十一】 形态学图像处理(二):开运算、闭运算、形态学梯度、顶帽、黑帽合辑 在计算机视觉和图像处理领域,OpenCV是一个强大的库,用于处理各种图像数据。形态学图像处理是其中的一个重要组成...
【OpenCV入门教程之十七】OpenCV重映射 & SURF特征点检测合辑 本文主要介绍了OpenCV库中的两个重要概念:重映射(Remapping)和SURF(Speeded Up Robust Features)特征点检测。这两个工具在图像处理和计算机视觉...
- **边缘检测**:介绍几种常用的边缘检测算法,如Sobel算子、Laplacian算子等。 - **轮廓提取**:如何从二值图像中提取轮廓。 - **形状识别**:基于轮廓特征识别特定形状的方法。 **第七章:图像分割与直方图** - ...
OpenCV(Open Source Computer Vision Library)是开源计算机视觉库,它包含了几百种计算机视觉算法,广泛应用于图像处理、视频分析、模式识别等领域。本书作为OpenCV学习的基础指南,将引领读者深入理解OpenCV的...
色彩空间变换则是将图像从一种颜色模型转换为另一种颜色模型,比如从RGB转换到HSV或YUV等。这些变换有助于后续的图像处理和分析工作。 ### 几何变换 几何变换是指在不改变像素值的情况下改变图像的形状和位置。...
OpenCV(开源计算机视觉库)是一个强大的跨平台计算机视觉库,它包含了大量的图像处理和计算机视觉功能。在标题“opencv4.1.1扩展包”中提到的是OpenCV的一个特定版本——4.1.1,这通常意味着包含了该版本的所有功能...
本章介绍了几种常用的图像平滑技术,如均值滤波、高斯滤波等,这些技术能够有效减少图像噪声。 **3.2 腐蚀和膨胀** 腐蚀和膨胀是两种常见的形态学操作,用于改变图像中的结构特征。本章详细解释了这两种操作的原理...
- 模板匹配是一种简单的图像匹配方法。 2. **直方图匹配**: - 直方图匹配用于调整图像的亮度分布。 3. **相关性匹配**: - 相关性匹配用于评估两个图像之间的相似度。 4. **KNN**: - K近邻算法(KNN)是一种基于...
根据提供的文件信息,我们可以将内容组织成以下几个主要的知识点: ### 1. 基础结构 ...OpenCV2作为一个强大的计算机视觉库,涵盖了广泛的图像处理和分析功能,适用于从入门级项目到高级研究的各种场景。