【C++ OpenCV】图像变换:连接、尺寸、翻转、旋转、仿射变换

这篇具有很好参考价值的文章主要介绍了【C++ OpenCV】图像变换:连接、尺寸、翻转、旋转、仿射变换。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

图像缩放变换

图像翻转

图像拼接

纵向拼接

横向拼接

图像插值原理

作用

单线性插值

双线性插值的公式

双线性插值的例子

双线性插值的直观展示

意义

仿射变换

图像旋转

实操

一、实现图像旋转

二、根据定义的三个点实现仿射变换,并且求取仿射变换矩阵


图像缩放变换

源码

void cv::resize(Inputarry src,
                Outputarry dst,
                Size      dsize,
                double     fx=0,
                double     fy=0,
                int interpolation = INTER_LINEAR
)
  • src - 输入图像。

  • dst - 输出图像;它的大小为 dsize(当它非零时)或从 src.size()、fx 和 fy 计算的大小;dst 的类型与 src 的类型相同。

  • dsize - 输出图像大小;如果它等于零,则计算为:dsize = Size(round(fxsrc.cols), round(fysrc.rows))。dsize 或 fx 和 fy 必须为非零。

  • fx - 沿水平轴的比例因子;当它等于 0 时,它被计算为(double)dsize.width/src.cols

  • fy - 沿垂直轴的比例因子;当它等于 0 时,它被计算为(double)dsize.height/src.rows

  • 插值 - 插值方法,在选择插值方法时,需要根据具体的需求和应用场景进行权衡。例如:

    • 如果只是简单的缩小图像或者调整图像大小至相对较小的尺寸,最近邻插值 (cv2.INTER_NEAREST) 可能是一个不错的选择,因为它计算速度快,效果还可以接受。

    • 如果需要在图像的放大或缩小过程中保持较好的平滑性,双线性插值 (cv2.INTER_LINEAR) 是一个常用的选项。

    • 如果对图像的质量有更高的要求,并且可以承受更长的计算时间,双三次插值 (cv2.INTER_CUBIC) 或 Lanczos 插值 (cv2.INTER_LANCZOS4) 可能是更好的选择。

  • interpolation algorithm

    Enumerator
    INTER_NEAREST 最近邻插值,该方法选择最接近目标像素的原始像素值作为调整后像素的值。这种插值方法计算速度快,但可能会引入锯齿状边缘和失真。在像素级别的简单放大或缩小时使用。
    INTER_LINEAR 双线性插值,该方法使用相邻四个原始像素的加权平均值来计算调整后像素的值。它比最近邻插值提供了更平滑的结果,但可能会导致某些细节的模糊。在图像的放大或缩小过程中使用较多。
    INTER_CUBIC 双三次插值,该方法在双线性插值的基础上进一步考虑了相邻像素的颜色变化趋势,以产生更平滑的结果。它比双线性插值计算更复杂,但在放大图像时通常能提供更好的效果。
    INTER_AREA resampling using pixel area relation. It may be a preferred method for image decimation, as it gives moire'-free results. But when the image is zoomed, it is similar to the INTER_NEAREST method. 利用像素面积关系进行重采样。这可能是图像抽取的优选方法,因为它给出了无波纹的结果。但是当图像被缩放时,它类似于INTER_NEAREST方法。
    INTER_LANCZOS4 8×8邻域上的Lanczos插值,该方法使用Lanczos滤波器进行插值,可以获得更锐利的结果,但计算开销较大。适用于对图像进行较大比例的放大操作。
    INTER_LINEAR_EXACT Bit exact bilinear interpolation 比特精确双线性插值
    INTER_NEAREST_EXACT Bit exact nearest neighbor interpolation. This will produce same results as the nearest neighbor method in PIL, scikit-image or Matlab. 位精确最近邻插值。这将产生与PIL最近邻法、scikit-image或Matlab相同的结果。
    INTER_MAX mask for interpolation codes 插值代码的掩码
    WARP_FILL_OUTLIERS flag, fills all of the destination image pixels. If some of them correspond to outliers in the source image, they are set to zero 标志,填充目标图像的所有像素。如果它们中的一些对应于源图像中的异常值,则它们被设置为零
    WARP_INVERSE_MAP flag, inverse transformation ,逆变换 For example, linearPolar or logPolar transforms: flag is not set: dst(ρ,ϕ)=src(x,y) flag is set: dst(x,y)=src(ρ,ϕ)

值得注意的是:size和两个double的作用是相同的,fx和fy是指将图像坐标轴进行比例缩放(fx=2就是x轴放大两倍),所以函数使用时只要使用一类即可,两者冲突以dsize为准

dsize =Size( round(fx *src.cols),round(fy *src.rows) )

图像翻转

void cv::flip(InputArray src, 
            OutputArray dst, 
            int flipCode);

参数 src 输入矩阵.

参数 dst 输出矩阵,和输入矩阵一样大小。

参数 flipCode 一个标志,决定怎么翻转矩阵; = 0 是围绕着x轴翻转,正值是围绕着y轴翻转,负值是围绕着两个轴一起翻转。

参考 transpose , repeat , completeSymm

图像拼接

纵向拼接

void cv::vconcat    (   const Mat *     src,
                        size_t      nsrc,
                        OutputArray     dst 
                    )   
  void cv::vconcat  (   InputArray      src1,
                        InputArray      src2,
                        OutputArray     dst 
                    ) 

横向拼接

void cv::hconcat    (   const Mat *     src,
                        size_t      nsrc,
                        OutputArray     dst 
                    )   
void cv::hconcat    (   InputArray      src1,
                        InputArray      src2,
                        OutputArray     dst 
                    )   
  • 值得注意的是:横向拼接,那么两个图像的高度应该相同,纵向拼接两个图像的宽度应该相同

图像插值原理

图像经过一系列处理,其像素矩阵的尺寸、大小发生改变,那么我对应的其中的每个像素的像素值如何变化?如果变换后的像素矩阵比原矩阵行和列都大,或者都小,那么变换后的像素矩阵可能就多出来一些像素或者被压缩,这些像素位置的值怎么确定?

情况1:两个像素经过变换后对应同一个位置

c++opencv实现图像连接,opencv,c++,opencv,计算机视觉

情况2:两个相邻像素经过变换后变得不再相邻,中间的位置像素如何确定

c++opencv实现图像连接,opencv,c++,opencv,计算机视觉

插值简单来说就是用已知的像素值去推测未知的像素值,常见的插值方法有:最邻近法、线性插值法、双线性插值法。本文重点介绍双线性插值法,来源于博文

在两个方向分别进行一次线性插值(首先在一个方向上使用线性插值,然后再在另一个方向上使用线性插值执行双线性插值。尽管每个步骤在采样值和位置上都是线性的,但是插值总体上不是线性的,而是在采样位置上是二次的。)

作用

一般用于重新采样图像和纹理。 计算四个周围纹理像素的属性(颜色,透明度等)的加权平均值,并将其应用于屏幕像素。 (简单来说,我要求一个已知坐标的像素值,先去找他四个周围已知像素的坐标通常是最邻近的四个像素值,通过两次单线性插值,找到他的像素值是多少)

单线性插值

c++opencv实现图像连接,opencv,c++,opencv,计算机视觉

c++opencv实现图像连接,opencv,c++,opencv,计算机视觉

仔细看就是用x和x0,x1的距离作为一个权重,用于y0和y1的加权。双线性插值本质上就是在两个方向上做线性插值。

双线性插值的公式

c++opencv实现图像连接,opencv,c++,opencv,计算机视觉

如图所示,我们需要求P点的像素值。我们已知了Q11、Q21、Q12、Q22、P的坐标。也知道Q11、Q21、Q12、Q22的像素值。所以先用关于X的单线性插值去分别计算R1、R2的像素值

c++opencv实现图像连接,opencv,c++,opencv,计算机视觉

在等式中的字母f(Q11)、f(Q12)、f(Q21)、f(Q22)、x1、x2、x都是已知的,求出的f(x,y1)与f(x,y2)即为R1、R2的像素值。 再使用关于y方向的单线性插值计算P点的像素值 得出:

c++opencv实现图像连接,opencv,c++,opencv,计算机视觉

在右边的等式中的字母y1、y2、y都是已知的,f(x,y1)与f(x,y2)即为上一个式子中求出的R1、R2像素值。

双线性插值的例子

举个栗子:

c++opencv实现图像连接,opencv,c++,opencv,计算机视觉

如右侧示例所示,可以通过在第20行和第21行的第14列和第15列的值之间进行线性内插,来计算计算为在第20.2行第14.5列处的像素处的强度值.(这里也正好说明了一般使用最相邻的像素点)

c++opencv实现图像连接,opencv,c++,opencv,计算机视觉

双线性插值的直观展示

c++opencv实现图像连接,opencv,c++,opencv,计算机视觉 我们可以看出这里的是在一个平面的双线性插值(Bilinear)

意义

此算法减少了由于将图像调整大小为非整数缩放因子而导致的某些视觉失真

仿射变换

仿射变换是一种二维空间中的几何变换,仿射变换常用于对图像进行平移、旋转、缩放、错切等线性变换操作,也称三点变换。该变换能够保持图像的平直性和平行性。平直性是指图像经过仿射变换后,直线仍然是直线;平行性是指图像在完成仿射变换后,平行线仍然是平行线。

使用时机:

仿射变换在图像处理和计算机视觉领域中具有广泛的应用,常用于以下情况和目的:

  1. 平移和旋转校正:当图像需要进行平移或旋转校正时,可以使用仿射变换。例如,在图像拍摄过程中,可能由于相机姿态或运动造成图像倾斜或旋转,通过仿射变换可以将图像校正为水平或垂直方向。

  2. 图像缩放和裁剪:通过调整仿射变换矩阵中的缩放参数,可以实现图像的缩放和裁剪操作。缩放可用于调整图像的大小,而裁剪可用于提取感兴趣区域或改变图像的长宽比。

  3. 图像变形和纠正:仿射变换可用于对图像进行形状变换,例如错切变换。这在一些特殊应用中很有用,比如文档扫描中的透视校正,可以将扭曲的文档图像转换为矩形形状。

  4. 特征对齐和匹配:在计算机视觉中,对于特征点的定位和匹配,可以使用仿射变换将一组特征点对齐到另一组特征点,以实现图像配准、目标跟踪等任务。

  5. 图像合成和重构:通过应用仿射变换,可以将不同尺度、方向或形状的图像进行合成或重构。例如,在图像拼接中,可以使用仿射变换将多个图像进行对齐,以创建全景图像。

c++opencv实现图像连接,opencv,c++,opencv,计算机视觉

当变换前和变换后的三点坐标确定,则我的仿射变换矩阵M是唯一存在的。

仿射变换矩阵

c++opencv实现图像连接,opencv,c++,opencv,计算机视觉

矩阵A负责将像素点进行旋转,矩阵B负责平移

仿射变换原理

c++opencv实现图像连接,opencv,c++,opencv,计算机视觉

程序源码:

void::warpAffine( INputarry src,
                  Outputarry dst,
                  InputArry M,
                  size      dsize,
                  int  flags= INTER_LINEAR,
                  int   borderMode = BOARDER_CONSTANT,
                  CONST Scalar& borderValue = Scalar
)
Enumerator
BORDER_CONSTANT iiiiii|abcdefgh|iiiiiii with some specified i 特定值(用的多)
BORDER_REPLICATE aaaaaa|abcdefgh|hhhhhhh 两端复制
BORDER_REFLECT fedcba|abcdefgh|hgfedcb 倒叙填充
BORDER_WRAP cdefgh|abcdefgh|abcdefg 正序填充
BORDER_REFLECT_101 gfedcb|abcdefgh|gfedcba
BORDER_TRANSPARENT uvwxyz|abcdefgh|ijklmno
BORDER_REFLECT101 same as BORDER_REFLECT_101
BORDER_DEFAULT same as BORDER_REFLECT_101
BORDER_ISOLATED do not look outside of ROI

BORDER_CONSTANT使用的最多,因为设置特定值为0,填充区域为黑色,而我们通常不需要获取填充区域的图片信息,所以研究填充区的像素矩阵是没有什么意义的。

图像旋转

在opencv中并没有直接实现啊图像旋转的函数,而是通过getRotationMatriix2D()得到旋转矩阵后再调用仿射变换函数来实现图像旋转。

源码

Mat cv::getRotationMatrix2D(Point2f     center,
                            double      angle,
                            double      scale 
)
  • center 图像旋转中心位置,输入值,通常定义Point2f center1(img.rows/2.0 , img.cols/2.0)

  • angle 旋转角度

  • scale 两个轴的比例因子,可以实现旋转过程中的图像缩放

c++opencv实现图像连接,opencv,c++,opencv,计算机视觉

其中:

c++opencv实现图像连接,opencv,c++,opencv,计算机视觉

注意:该函数是有返回值的为Mat类型

定义一个Mat类型矩阵接受返回值后,将其作为仿射函数的M参数,便可以实现图像旋转。

获取仿射矩阵

Mat cv::getAffineTransform(const Point2f    src[],
                            const Point2f   dst[] 
                        )
  • src[] :原图像中的3个像素坐标,是一个数组,其内的数据类型是Point2f

  • dst[]:目标图像中的三个像素坐标,是一个数组,其内的数据类型是Point2f

实操

一、实现图像旋转

#include<opencv2/opencv.hpp>
#include<iostream>
#include<vector>
​
using namespace std;
using namespace cv;
​
​
int main()
{
    Mat img = imread("E://学习//OPEN-CV学习//lena.png");
    if (img.empty())
    {
        cout << "读取失败!" << endl;
        return -1;
    }
​
    //实现旋转操作
    Point2f center (img.rows / 2.0, img.cols / 2.0);
    double angle = 30;
    double scale = 0.5;
    Size dsize(img.rows, img.cols);
    Mat rotation,dst;
    rotation = getRotationMatrix2D(center, angle, scale);
​
    warpAffine(img, dst, rotation, dsize);
    imshow("dst", dst);
​
        waitKey(1);
        return 0;
}

得到旋转矩阵结果和旋转后的结果图

c++opencv实现图像连接,opencv,c++,opencv,计算机视觉

二、根据定义的三个点实现仿射变换,并且求取仿射变换矩阵

#include<opencv2/opencv.hpp>
#include<iostream>
#include<vector>
​
using namespace std;
using namespace cv;
​
​
int main()
{
    Mat img = imread("E://学习//OPEN-CV学习//lena.png");
    if (img.empty())
    {
        cout << "读取失败!" << endl;
        return -1;
    }
​
    //实现旋转操作
    Point2f center (img.rows / 2.0, img.cols / 2.0);
    double angle = 30;
    double scale = 0.5;
    Size dsize(img.rows, img.cols);
    Mat rotation,dst;
    rotation = getRotationMatrix2D(center, angle, scale);
​
    warpAffine(img, dst, rotation, dsize);
    imshow("dst", dst);
​
    Point2f ori[3];
    Point2f res[3];
    //原图像的三个边角点
    ori[0] = Point2f (0, 0);
    ori[1] = Point2f (0, (float)(img.cols-1));
    ori[2] = Point2f ((float)(img.rows-1), (float)(img.cols - 1));
    //想仿射变换的三个点
    res[0] = Point2f((float)(img.rows*0.10), (float)(img.cols*0.20));
    res[1] = Point2f((float)(img.rows * 0.15), (float)(img.cols * 0.70));
    res[2] = Point2f((float)(img.rows * 0.65), (float)(img.cols * 0.90));
    //获取仿射变换矩阵
    Mat rotation1, dst1;
    rotation1 = getAffineTransform(ori, res);
    warpAffine(img, dst1, rotation1, dsize);
    imshow("dst1", dst1);
​
​
        waitKey(1);
        return 0;
}
 

c++opencv实现图像连接,opencv,c++,opencv,计算机视觉

得到仿射矩阵和仿射变换后的结果图。文章来源地址https://www.toymoban.com/news/detail-801482.html

到了这里,关于【C++ OpenCV】图像变换:连接、尺寸、翻转、旋转、仿射变换的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • OpenCV图像的仿射变换、旋转和缩放

    以下是对代码的逐行解释:

    2024年02月13日
    浏览(52)
  • opencv006图像处理之仿射变换(旋转,缩放,平移)

    空间变换中的仿射变换对应着五种变换,平移,缩放,旋转,翻转,错切。而这五种变化由原图像转变到变换图像的过程,可以用仿射变换矩阵进行描述。而这个变换过程可以用一个2*3的矩阵与原图进行相乘得到。关键就是这个矩阵M:  平移,旋转   透视 M: 变换矩阵 desi

    2024年01月21日
    浏览(51)
  • 【OpenCV • c++】图像几何变换 | 图像仿射变换

    🚀 个人简介:CSDN「 博客新星 」TOP 10 , C/C++ 领域新星创作者 💟 作    者: 锡兰_CC ❣️ 📝 专    栏: 【OpenCV • c++】计算机视觉 🌈 若有帮助,还请 关注➕点赞➕收藏 ,不行的话我再努努力💪💪💪

    2024年02月16日
    浏览(52)
  • 【C++】【Opencv】cv::warpAffine()仿射变换函数详解,实现平移、缩放和旋转等功能

    仿射变换是一种二维变换,它可以将一个二维图形映射到另一个二维图形上,保持了图形的“形状”和“大小”不变,但可能会改变图形的方向和位置。仿射变换可以用一个线性变换矩阵来表示,该矩阵包含了六个参数,可以进行平移、缩放、旋转等操作。通过原理、函数和

    2024年02月05日
    浏览(62)
  • 图像尺寸、仿射、透视变换

      1.2.1 图像缩放  1.2.2 图像翻转 1.2.3 图像拼接    4个像素坐标,图有误  3.4 透视变换函数  

    2024年02月12日
    浏览(66)
  • 我在Vscode学OpenCV 几何变换(缩放、翻转、仿射变换、透视、重映射)

    几何变换指的是将一幅图像映射到另一幅图像内的操作。 cv2.warpAffine :使用仿射变换矩阵对图像进行变换,可以实现平移、缩放和旋转等操作。 cv2.warpPerspective :使用透视变换矩阵对图像进行透视变换,可以实现镜头校正、图像纠偏等操作。 cv2.getAffineTransform :计算仿射变换

    2024年02月05日
    浏览(66)
  • 【OpenCV • c++】图像几何变换 | 图像旋转

    🚀 个人简介:CSDN「 博客新星 」TOP 10 , C/C++ 领域新星创作者 💟 作    者: 锡兰_CC ❣️ 📝 专    栏: 【OpenCV • c++】计算机视觉 🌈 若有帮助,还请 关注➕点赞➕收藏 ,不行的话我再努努力💪💪💪   图像的几何变换是指在不改变图像像素值的前提下对图像像素进

    2024年02月16日
    浏览(50)
  • OpenCV(十一):图像仿射变换

    目录 1.图像仿射变换介绍  仿射变换: 仿射变换矩阵: 仿射变换公式: 2.仿射变换函数 仿射变换函数:warpAffine() 图像旋转:getRotationMatrix2D() 计算仿射变换矩阵:getAffineTransform()  3.demo 1.图像仿射变换介绍  仿射变换:        仿射变换是由平移、缩放、旋转、翻转和错切组

    2024年02月10日
    浏览(55)
  • opencv图像仿射变换,cv2.warpAffine

    目录 仿射变换原理介绍 cv2.warpAffine函数介绍 代码实例          仿射变换 ,又称 仿射映射 ,是指在几何中,一个向量空间进行一次线性变换并接上一个平移,变换为另一个向量空间。         在有限维的情况,每个仿射变换可以由一个矩阵A和一个向量b给出,它可以写

    2024年02月05日
    浏览(68)
  • 【Python图像处理篇】opencv中的仿射变换和透视变换

    仿射变换可以将矩形图片映射为平行四边形, 透视变换可以将矩形图片映射为任意四边形。 opencv提供了两个变换函数,cv2.warpAffine和cv2.warpPerspective, 使用这两个函数可以实现所有类型的变换。 cv2.warpAffine 接收的参数2x3的变换矩阵; 而 cv2.warpPerspective 接收的3x3的变换矩阵。

    2024年01月24日
    浏览(67)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包