OpenCV每日函数 几何图像变换模块 (7) linearPolar函数/logPolar函数/warpPolar函数

一、概述

        linearPolar函数将图像重新映射到极坐标空间,不过此函数已经废弃(实际在源码中也是调用了warpPolar函数),可以使用warpPolar函数替代。

        logPolar函数将图像重新映射到半对数极坐标空间。不过此函数已经废弃(实际在源码中也是调用了warpPolar函数),可以使用warpPolar函数替代。

        warpPolar函数将图像重新映射到极坐标或半对数极坐标空间。

图片来自OpenCV官方,极地重映射参考

        使用以下变换变换源图像:

        dst(\rho, \phi)=src(x,y)

        其中

 二、warpPolar函数

1、函数原型

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

2、参数详解

src 源图像。
dst 目标图像。 它将与 src 具有相同的类型。
dsize 目标图像大小(有关有效选项,请参阅说明)。
center 转换中心。
maxRadius 要变换的边界圆的半径。 它也确定了反幅值比例参数。
flags

插值方法的组合,InterpolationFlags + WarpPolarMode。

添加 WARP_POLAR_LINEAR 以选择线性极坐标映射(默认)
添加 WARP_POLAR_LOG 以选择半对数极坐标映射
添加 WARP_INVERSE_MAP 以进行反向映射。

3、dsize 选项

        如果 dsize <=0(默认)中的两个值,则目标图像将具有(几乎)相同的源边界圆区域:

         如果只有 dsize.height <= 0,则目标图像区域将与边界圆区域成比例,但按 Kx * Kx 缩放:

         如果 dsize 中的两个值 > 0,则目标图像将具有给定的大小,因此边界圆的区域将缩放为 dsize。

4、其它限制

        该功能无法就地运行。

        为了计算以度为单位的幅度和角度,cartToPolar 在内部使用,因此角度的测量范围为 0 到 360,精度约为 0.3 度。

        此函数使用重映射。 由于当前的实施限制,输入和输出图像的大小应小于 32767x32767。

三、OpenCV源码 

1、源码路径

opencv\modules\imgproc\src\imgwarp.cpp

2、源码代码 

void cv::warpPolar(InputArray _src, OutputArray _dst, Size dsize,
                   Point2f center, double maxRadius, int flags)
{
    // if dest size is empty given than calculate using proportional setting
    // thus we calculate needed angles to keep same area as bounding circle
    if ((dsize.width <= 0) && (dsize.height <= 0))
    {
        dsize.width = cvRound(maxRadius);
        dsize.height = cvRound(maxRadius * CV_PI);
    }
    else if (dsize.height <= 0)
    {
        dsize.height = cvRound(dsize.width * CV_PI);
    }

    Mat mapx, mapy;
    mapx.create(dsize, CV_32F);
    mapy.create(dsize, CV_32F);
    bool semiLog = (flags & WARP_POLAR_LOG) != 0;

    if (!(flags & CV_WARP_INVERSE_MAP))
    {
        CV_Assert(!dsize.empty());
        double Kangle = CV_2PI / dsize.height;
        int phi, rho;

        // precalculate scaled rho
        Mat rhos = Mat(1, dsize.width, CV_32F);
        float* bufRhos = (float*)(rhos.data);
        if (semiLog)
        {
            double Kmag = std::log(maxRadius) / dsize.width;
            for (rho = 0; rho < dsize.width; rho++)
                bufRhos[rho] = (float)(std::exp(rho * Kmag) - 1.0);

        }
        else
        {
            double Kmag = maxRadius / dsize.width;
            for (rho = 0; rho < dsize.width; rho++)
                bufRhos[rho] = (float)(rho * Kmag);
        }

        for (phi = 0; phi < dsize.height; phi++)
        {
            double KKy = Kangle * phi;
            double cp = std::cos(KKy);
            double sp = std::sin(KKy);
            float* mx = (float*)(mapx.data + phi*mapx.step);
            float* my = (float*)(mapy.data + phi*mapy.step);

            for (rho = 0; rho < dsize.width; rho++)
            {
                double x = bufRhos[rho] * cp + center.x;
                double y = bufRhos[rho] * sp + center.y;

                mx[rho] = (float)x;
                my[rho] = (float)y;
            }
        }
        remap(_src, _dst, mapx, mapy, flags & cv::INTER_MAX, (flags & CV_WARP_FILL_OUTLIERS) ? cv::BORDER_CONSTANT : cv::BORDER_TRANSPARENT);
    }
    else
    {
        const int ANGLE_BORDER = 1;
        cv::copyMakeBorder(_src, _dst, ANGLE_BORDER, ANGLE_BORDER, 0, 0, BORDER_WRAP);
        Mat src = _dst.getMat();
        Size ssize = _dst.size();
        ssize.height -= 2 * ANGLE_BORDER;
        CV_Assert(!ssize.empty());
        const double Kangle = CV_2PI / ssize.height;
        double Kmag;
        if (semiLog)
            Kmag = std::log(maxRadius) / ssize.width;
        else
            Kmag = maxRadius / ssize.width;

        int x, y;
        Mat bufx, bufy, bufp, bufa;

        bufx = Mat(1, dsize.width, CV_32F);
        bufy = Mat(1, dsize.width, CV_32F);
        bufp = Mat(1, dsize.width, CV_32F);
        bufa = Mat(1, dsize.width, CV_32F);

        for (x = 0; x < dsize.width; x++)
            bufx.at<float>(0, x) = (float)x - center.x;

        for (y = 0; y < dsize.height; y++)
        {
            float* mx = (float*)(mapx.data + y*mapx.step);
            float* my = (float*)(mapy.data + y*mapy.step);

            for (x = 0; x < dsize.width; x++)
                bufy.at<float>(0, x) = (float)y - center.y;

            cartToPolar(bufx, bufy, bufp, bufa, 0);

            if (semiLog)
            {
                bufp += 1.f;
                log(bufp, bufp);
            }

            for (x = 0; x < dsize.width; x++)
            {
                double rho = bufp.at<float>(0, x) / Kmag;
                double phi = bufa.at<float>(0, x) / Kangle;
                mx[x] = (float)rho;
                my[x] = (float)phi + ANGLE_BORDER;
            }
        }
        remap(src, _dst, mapx, mapy, flags & cv::INTER_MAX,
              (flags & CV_WARP_FILL_OUTLIERS) ? cv::BORDER_CONSTANT : cv::BORDER_TRANSPARENT);
    }
}

四、效果图像示例

原图
极坐标空间
半对数极坐标

五、一些参考示例 

Opencv学习笔记 - 仿射变换/透视变换/对数极坐标变换_坐望云起的博客-CSDN博客_对数极坐标变换Opencv学习笔记 - 仿射变换/透视变换/对数极坐标变换https://skydance.blog.csdn.net/article/details/109705939

猜你喜欢

转载自blog.csdn.net/bashendixie5/article/details/125261307
今日推荐