图像处理旅行·在路上摄影

【图像处理】OpenCV系列十八 --- 几何图像变换函数详解(

2019-05-01  本文已影响38人  307656af5a04

一、linearPolar()函数

1、函数原型

void linearPolar(InputArray src, 
    OutputArray dst,
    Point2f center, 
    double maxRadius, 
    int flags);

2、函数功能
将一幅图像映射到极坐标空间中。

3、参数详解

Note:该函数不支持就地操作。

二、logPolar()函数

1、函数原型

void logPolar(InputArray src, 
    OutputArray dst,
    Point2f center, 
    double M, 
    int flags);

2、函数功能
将图像映射到半极坐标空间;

3、参数详解

Note:该函数不支持就地操作。

三、warpPolar()函数

1、函数原型

void warpPolar(InputArray src, 
    OutputArray dst, 
    Size dsize,
    Point2f center, 
    double maxRadius, 
    int flags);

2、函数功能
将一幅图像映射到极坐标或者半极坐标空间中;

极坐标的映射参考

具体应用的公式如下:

极坐标映射

其中,

极坐标映射 极坐标映射

极坐标映射与半极坐标映射的比较:

warpPolar函数的映射模式可以是极坐标映射,也可以是半极坐标映射,通过flags参数来进行指定映射的模式!系统默认的模式是极坐标映射模式。半极坐标映射用来模仿人类的中心视觉,在视觉聚焦的地方可以看的很清晰,非聚焦的地方会比较模糊,通过弱化聚焦以外的区域,来简化图像,方便对图像进行处理。

3、参数详解

Note:
(1)该函数不支持就地操作;
(2)为了计算角的大小和角度,内部采用了cartToPolar函数,测量角度在0到360之间,精度约为0.3度;
(3)在实现过程中,该函数使用了remap函数,因为当前的实现限制,图像的大小应小于32767x32767。

综合实例
对于linearPolar()函数与logPolar()以及warpPolar()函数的使用

#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>

using namespace cv;

int main(int argc, char** argv)
{
    // 半极坐标转换图像
    Mat log_polar_img, 
        // 极坐标转换图像
        lin_polar_img,  
        // 逆半极坐标转换图像
        recovered_log_polar,
        // 逆极坐标转换图像
        recovered_lin_polar_img; 
    
    // 创建窗体
    namedWindow("Linear-Polar", WINDOW_AUTOSIZE);

    namedWindow("Log-Polar", WINDOW_AUTOSIZE);

    namedWindow("Recovered Linear-Polar", WINDOW_AUTOSIZE);

    namedWindow("Recovered Log-Polar", WINDOW_AUTOSIZE);

    // 移动窗口的显示位置
    moveWindow("Linear-Polar", 20, 20);
    moveWindow("Log-Polar", 700, 20);

    moveWindow("Recovered Linear-Polar", 20, 350);
    moveWindow("Recovered Log-Polar", 700, 350);

    // INTER_LINEAR 线性插值
    // WARP_FILL_OUTLIERS 填充所有目标图像像素。
    // 如果其中一些对应于源图像中的异常值,
    // 则将其设置为零。
    int flags = INTER_LINEAR + 
        WARP_FILL_OUTLIERS;

    // 加载图像
    Mat src = imread("lena.png");
    
    if (src.empty()) 
    {
        printf("image error!");
        return 0;
    }
        
    // 原图像的中心坐标
    Point2f center((float)src.cols / 2, 
        (float)src.rows / 2);

    // 最大的半径
    double maxRadius = 0.7*min(center.y, center.x);

    // direct transform
    // linear Polar
    warpPolar(src, 
        lin_polar_img, 
        Size(), 
        center, 
        maxRadius, 
        flags);  

    // semilog Polar
    warpPolar(src, 
        log_polar_img, 
        Size(), 
        center, 
        maxRadius, 
        flags + WARP_POLAR_LOG);    
                
    // inverse transform
    warpPolar(lin_polar_img, 
        recovered_lin_polar_img, 
        src.size(), 
        center, 
        maxRadius, 
        flags + WARP_INVERSE_MAP);

    // inverse transform
    warpPolar(log_polar_img, 
        recovered_log_polar, 
        src.size(), 
        center, 
        maxRadius, 
        flags + WARP_POLAR_LOG + WARP_INVERSE_MAP);
    
    // 从极坐标系到直角坐标系

    Mat dst;
    if (flags & WARP_POLAR_LOG)
        dst = log_polar_img;
    else
        dst = lin_polar_img;

    //get a point from the polar image
    int rho = cvRound(dst.cols * 0.75);
    int phi = cvRound(dst.rows / 2.0);

    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));

    drawMarker(src, Point(x, y), Scalar(0, 255, 0));
    drawMarker(dst, Point(rho, phi), Scalar(0, 255, 0));

    imshow("Src image", src);

    imshow("Log-Polar", log_polar_img);
    imshow("Linear-Polar", lin_polar_img);

    imshow("Recovered Linear-Polar", recovered_lin_polar_img);
    imshow("Recovered Log-Polar", recovered_log_polar);

    waitKey(0);
    return 0;
}

实验结果:

原图 极坐标变换(左)与半极坐标变换(右) 逆极坐标变换(左)与逆半极坐标变换(右)

四、resize()函数

1、函数原型

void resize(InputArray src, 
    OutputArray dst,
    Size dsize, 
    double fx = 0, 
    double fy = 0,
    int interpolation = 
    INTER_LINEAR);

2、函数功能
对图像的尺寸进行调整,使其缩小或放大为指定的大小;
Note:
(1)如果没有考虑目标图像(dst)初始化的大小和类型,则目标图像的大小和类型由原图像(src),dsize,fx,fy等参数决定,例如:

// 指定fx,fy的值,
//由函数自动计算目标图像的大小
resize(src, dst, 
    Size(), 0.5, 0.5, 
    interpolation);

(2)预先创建dst图像的大小与类型,例如:

// 创建一个800x600的8位单通道的图像
Mat dst(800, 600, CV_8UC1); 
resize(src, dst, dst.size(), 0, 0, interpolation);

3、参数详解

dsize

需要满足dsize或者fx,fy都不为0;

fx,水平方向的尺寸因子,如果fx=0,则通过下面的公式计算fx:

fx

fy,垂直方向的尺寸因子,如果fy=0,则通过下面的公式计算fy:

fy

常见的插值方式:

常见的插值方式

五、remap()函数

1、函数原型

void remap(InputArray src, 
    OutputArray dst,
    InputArray map1, 
    InputArray map2,
    int interpolation, 
    int borderMode = BORDER_CONSTANT,
    const Scalar& borderValue = Scalar());

2、函数功能
对图像进行几何变换;

3、参数详解

六、warpAffine()函数

1、函数原型

void warpAffine(InputArray src, 
    OutputArray dst,
    InputArray M, 
    Size dsize,
    int flags = INTER_LINEAR,
    int borderMode = BORDER_CONSTANT,
    const Scalar& borderValue = Scalar());

2、函数功能
用指定的卷积核对图像进行仿射变换;
当flag为WARP_INVERSE_MAP时,使用的公式如下:

指定的卷积矩阵

否则,使用invertAffineTransform函数先进性逆仿射变换,然后用上面的公式代替M;并且该函数不支持就地操作!

3、参数详解

七、warpPerspective()函数

1、函数原型

void warpPerspective(InputArray src, 
    OutputArray dst,
    InputArray M, 
    Size dsize,
    int flags = INTER_LINEAR,
    int borderMode = BORDER_CONSTANT,
    const Scalar& borderValue = Scalar());

2、函数功能
用指定的卷积核对图像进行透视变换;

当flags设置为WARP_INVERSE_MAP时,使用以下的卷积对图像进行透视变换,

透视变换

否则,先使用逆变换进行转置,然后用上面的公式代替M,并且此函数不支持就地操作;

3、参数详解

我是奕双,现在已经毕业将近两年了,从大学开始学编程,期间学习了C需要编程,C++需要编程,Win32编程,MFC编程,毕业之后进入一家图像处理相关领域的公司,掌握了用OpenCV对图像进行处理,如果大家对相关领域感兴趣的话,可以关注我,我这边会为大家进行解答哦!如果大家需要相关学习资料的话,可以私聊我哦!

上一篇下一篇

猜你喜欢

热点阅读