OpenCV的图像直角坐标系转极坐标系的函数warpPolar()详解,并附自己写的实现直角坐标系转极坐标系的MATLAB代码

Posted 昊虹图像算法

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV的图像直角坐标系转极坐标系的函数warpPolar()详解,并附自己写的实现直角坐标系转极坐标系的MATLAB代码相关的知识,希望对你有一定的参考价值。

有些时候我们需要把图像或矩阵从直角坐标系(笛卡尔坐标系)转换到极坐标,这个过程通常称为图像的极坐标变换。

图像的极坐标变换一个常见的作用是可以将将一圆形图像变换成一个矩形图像,类似于把圆剪开铺平。这样可以方便我们处理钟表、圆盘等图像。图形上的圆形排列文字经过及坐标变换后可以垂直的排列在新图像上,便于对文字的识别和检测。示意图如下:

OpenCV4中新增加了函数warpPolar()用于将图像或矩阵从直角坐标系(笛卡尔坐标系)转换到极坐标。

其C++函数原型如下:

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

其Python原型如下:

dst	=	cv.warpPolar(	src, dsize, center, maxRadius, flags[, dst]	)

参数意义如下:
src—源图像,对通道数无要求,所以可以是灰度图像或者彩色图像。
dst—输出图像,它和源图像具有相同的数据类型和通道数,注意没有说尺寸相同哈。
dsize—目标图像大小,如图不填这个值或其中的某个值,那么按下面的规则计算:

center—极坐标变换时原点坐标。
maxRadius—极半径坐标系的极半径最大值,具体它的意义请看我在下面提示的示意图。
flags— 插值方法与极坐标映射方法标志。两个方法之间通过“+”或者“|”号进行连接。
插值方式如下表所示:

这里说下为什么要涉及到插值?因为我们的变换本质上是在离散序列中进行的,而不是连续的,这就导致我们的两个坐标系的点与点之间并不能一一对应。此时为了尽可能保证目标极坐标矩阵中的每个点的值的准确性,我们就要进行插值处理。如果想对这个问题作更深入的了解,那么看本文最后给的利用MATLAB实现的直角坐标系转极坐标系的代码就能很清楚这个问题的来龙去脉了。

映射方法如下表所示:

可以使用上面的第三个参数实现逆变换,示例代码如下:

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

为了各好的理解上面各参数的意义,特别是参数dsize和参数maxRadius的意义,请仔细看下面这张示意图(建议放大看 ):
下边这张图上半部分是变换前的原图,下半部分是变换后的图像。左下部分是线性极坐标变换,右下部分是半对数极坐标变换。

相关的计算式如下:

注意: I ⃗ \\vecI I 是二维直角坐标系中的一个向量,它是某点距离极坐标原点的位置向量。
也许您会觉得上面的示意图和计算公式看着挺难,但实际上一点也不复杂,只要你静下心来仔细看一看,就能很快理解明白的。

另外,如果已知一个点的极坐标(rho, phi),可以用下面的代码进行计算得到其直角系的坐标(x, y):

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

接下来,上第一个示例代码。
在这个示例代码中,我们绘制一个半径为100的圆,并且把它映射到极坐标中。
代码如下:

# 博主微信/QQ 2487872782
# 有问题可以联系博主交流
# 有图像处理需求也可联系博主
# 图像处理技术交流QQ群 271891601

# !/usr/bin/env python
# -*- coding: utf-8 -*-
# OpenCV的版本为4.1

import numpy as np
import cv2 as cv

Src_size = 101
Dst_size = Src_size

A = np.zeros((Src_size, Src_size), dtype='uint8')

cv.circle(A, (Src_size//2, Src_size//2), Src_size//2, 255, 1)

cv.imshow('A', A)

C = cv.warpPolar(A, (Dst_size, 360), (Src_size//2, Src_size//2), Src_size//2, cv.INTER_LINEAR + cv.WARP_POLAR_LINEAR)

cv.waitKey()

运行结果如下图所示:

下面这张图是图像A。

图像A的部分数据如下:



从上面这张C矩阵的图来看,我们图A中半径为100的圆被映射到了极坐标中极半径为98,99,100的列中,并且角的度数为从0度到359度。

接下来,上第二个示例代码:
第二个示例代码我们对钟表图进行极坐标变换,大家看下效果。

# 博主微信/QQ 2487872782
# 有问题可以联系博主交流
# 有图像处理需求也可联系博主
# 图像处理技术交流QQ群 271891601

# !/usr/bin/env python
# -*- coding: utf-8 -*-
# OpenCV的版本为4.1

import numpy as np
import cv2 as cv
import sys

img_src = cv.imread('F:/material/images/P0048-clock_dial.jpg')
if img_src is None:
    print('Error:Failed to read img')
    sys.exit()
cv.imshow('img_src', img_src)

# 源图像的尺寸是338×338,所以就懒得去调属性了
img_polar = cv.warpPolar(img_src, (338, 360), (338//2, 338//2), 338//2, cv.INTER_LINEAR + cv.WARP_POLAR_LINEAR)
cv.imshow('img_polar', img_polar)

cv.waitKey()

运行结果如下图所示:

从上图可以看出,得到了我们想要的结果。

有些同学是用MATLAB做图像处理算法,所以博主还用MATLAB写了矩阵(图像)从直角坐标系转换到极坐系的函数。
其原型和说明如下:

function [Rmax,polarv]=topolar(v,x0,y0,np)
%本函数实现将单通道的图像或矩阵v从直角坐标系转化为极坐标
%(x0,y0)为要指定的极坐标原点
%np为一周等间距相位数
%插值方式为双线性插值

另外,博主还写了下面这个函数实现将极坐标转换到直角坐标,即已知极坐标(p_i,r_j),求直角坐标(x,y)

function [x,y] = polartorect(p_i,r_j,x0,y0)
%该函数实现将极坐标转换到直角坐标

测试代码如下:

clc
close all
clear all

%读取图像
ImageData=imread('F:/material/images/P0049-A_101_circle.bmp');

f1=figure(1);
set(f1,'name','原图','Numbertitle','off')
imshow(ImageData);

[rows,columns]=size(ImageData);

x0 = floor(rows/2);
y0 = floor(columns/2);
np = 360;

[Rmax, Rpolar_img] = topolar(ImageData,x0,y0,np);

f2=figure(2);
set(f2,'name','原图的极坐标图','Numbertitle','off')
imshow(Rpolar_img);

运行结果如下图所示:


从上面的运行结果可以看出,原图中的圆形被投射到极坐系后是一条垂直的直线。

由于上面的代码是博主花时间和精力书写的,所以请大家花费1.9元购买下载,下载链接:
https://download.csdn.net/download/wenhao_ir/85405476

以上是关于OpenCV的图像直角坐标系转极坐标系的函数warpPolar()详解,并附自己写的实现直角坐标系转极坐标系的MATLAB代码的主要内容,如果未能解决你的问题,请参考以下文章

地理坐标系和球面极坐标系的区别和联系

在OpenCV打开的图像上,已知图像上的某点坐标,如何获取该点像素值

opencv 图像rowcol坐标对应关系

用MATLAB怎么画直角坐标系的坐标轴

椭球面上经纬度坐标转空间直角坐标

大地坐标系和空间直角坐标系的转换