图像极坐标变换的研究

做图像配准的时候,发现图像进行旋转的情况下的配准有一些特殊。于是想到可以用极坐标进行配准。查了一下资料,发现大家用的更多的是对数极坐标Log Polar。

笛卡尔坐标系和极坐标系

先来说一下我们常用的笛卡尔坐标。X轴水平向右是正方向,y轴垂直于x轴,竖直向上是正方向。但是在计算机中图像的原点在左上方,所以如果是在笛卡尔坐标中进行旋转,需要三个矩阵相乘,分别实现从计算机坐标到笛卡尔坐标,旋转角度theta,笛卡尔坐标转换为计算机坐标系。

如果将笛卡尔坐标系换为极坐标系,两个坐标轴分别是角度theta和长轴,点的位置的表示方式用与原点水平方向的夹角和到原点的距离表示。而对数极坐标,是在极坐标的基础上,对长轴的长度取对数,这样把到原点距离的线性变换变成非线性变换,当距离成倍增长时对数极坐标下的距离小幅变化,起到了数据压缩的作用,减少了计算量。就像是通信脉冲采样中的谬率和a率,还有信道中的信噪比。参考资料中提到的极坐标和对数坐标都是对人眼的仿生模拟,因为人眼的中心凸起有聚焦的作用,极坐标下的像素都环绕在原点周围,但考虑到半径越来越大,越远离中心点的地方空间分辨率越低。所以可以将这么一次变换看作是图像通过了如下的滤波器:

极坐标在OpenCV中的函数

OpenCV中集成了对数极坐标的实现。参数也都很简单:

cvLogPolar(

         const CvArr* src, CvArr* dst,

         CvPoint2D32f center, //极坐标变换的原点

         double M,//缩放系数

         int flagsCV_DEFAULT(CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS)//插值方式

           );

在计算机图像处理中,看似目标图像是原图像经过某种变换直接得到的,其实我们不能一次性得到目标图像,而是在已知目标图像大小和位深的基础上,根据变换关系将目标图像的像素一个个映射回原图像,由原图像的已知像素求出目标图像的未知像素。而具体求解的算法就是插值法。这里cvLogPolar中默认的插值算法是双线性插值,策略是当目标图像的像素映射到原图边界之外时置0.具体关于函数的细节可以参考opencv手册https://docs.opencv.org/2.4/index.html


除了cvLogPolar函数,opencv还有一个函数cvLinerPolar,这个函数没有对距离取对数,所以叫线性极坐标。有的博客说是对半径做了log变换模拟人眼看到中间分辨率高,边缘分辨率低的效果,在机器学习中线性极坐标变换更加常用。下面是使用线性极坐标变换的例子,可以看到与对数极坐标相比,差距不大,都达到了人眼的效果,只是取了对数之后效果更加突出。


对极坐标变换结果的解释

因为在对数极坐标下两个坐标轴分别是角度和到中心点的距离的对数,所以原图中以中心点为圆心的圆在极坐标下映射为一条直线,通过中心点的直线被映射为平行于极轴坐标的直线(角度不变),原图边界处的点到中心点的距离在一个闭区间内有规律地波动,角度分量则在0~360度均匀分布。

相关代码

#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
IplImage* rotateImage1(IplImage* img, int degree);int main()
{IplImage *src = cvLoadImage("beaver.png");// , -1);cvLogPolar要求必须是三通道的IplImage *dst = cvCreateImage(cvGetSize(src), 8, 3);IplImage *dstLiner = cvCreateImage(cvGetSize(src), 8, 3);IplImage* src2 = cvCreateImage(cvGetSize(src), 8, 3);IplImage* src2Liner = cvCreateImage(cvGetSize(src), 8, 3);CvPoint2D32f center = cvPoint2D32f(src->width/2, src->height/2);//旋转中心为图像中心  //CvPoint2D32f center;//center.x = float(img->width / 2.0 + 0.5);//center.y = float(img->height / 2.0 + 0.5);这里为什么要加0.5?double m = 50.0;cvLogPolar(src, dst, center, m, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS);cvLogPolar(dst, src2, center, m, CV_INTER_LINEAR + CV_WARP_INVERSE_MAP);//CV_WARP_INVERSE_MAP - 表示矩阵由输出图像到输入图像的逆变换,并且因此可以直接用于像素插值。否则,函数从map_matrix中寻找逆变换。cvLogPolar(src, dstLiner, center, m, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS);cvLogPolar(dstLiner, src2Liner, center, m, CV_INTER_LINEAR + CV_WARP_INVERSE_MAP);//对原图旋转IplImage *RotateImage = rotateImage1(src, 20);cvNamedWindow("旋转图", CV_WINDOW_AUTOSIZE);cvShowImage("旋转图", RotateImage);//对旋转图极坐标变换IplImage *dstR = cvCreateImage(cvGetSize(src), 8, 3);cvLogPolar(RotateImage, dstR, center, m, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS);cvNamedWindow("旋转图极坐标", CV_WINDOW_AUTOSIZE);cvShowImage("旋转图极坐标", dstR);cvNamedWindow("原图", CV_WINDOW_AUTOSIZE);cvShowImage("原图", src);cvNamedWindow("变换后的图", CV_WINDOW_AUTOSIZE);cvShowImage("变换后的图", dst);cvNamedWindow("线性极坐标变换后的图", CV_WINDOW_AUTOSIZE);cvShowImage("线性极坐标变换后的图", dstLiner);cvNamedWindow("反变换后的图", CV_WINDOW_AUTOSIZE);cvShowImage("反变换后的图", src2);cvNamedWindow("线性反变换后的图", CV_WINDOW_AUTOSIZE);cvShowImage("线性反变换后的图", src2Liner);cvWaitKey();cvReleaseImage(&src);cvReleaseImage(&dst);cvReleaseImage(&dstLiner);cvReleaseImage(&src2Liner);cvReleaseImage(&RotateImage);cvReleaseImage(&dstR);cvDestroyWindow("原图");cvDestroyWindow("变换后的图");cvDestroyWindow("线性极坐标变换后的图");cvDestroyWindow("线性反变换后的图");cvDestroyWindow("旋转图");cvDestroyWindow("旋转图极坐标");return 0;
}
//旋转图像内容不变,尺寸相应变大  https://blog.csdn.net/qingzai_/article/details/51095297
IplImage* rotateImage1(IplImage* img, int degree){double angle = degree  * CV_PI / 180.; // 弧度    double a = sin(angle), b = cos(angle);int width = img->width;int height = img->height;int width_rotate = int(height * fabs(a) + width * fabs(b));int height_rotate = int(width * fabs(a) + height * fabs(b));//旋转数组map  // [ m0  m1  m2 ] ===>  [ A11  A12   b1 ]  // [ m3  m4  m5 ] ===>  [ A21  A22   b2 ]  float map[6];CvMat map_matrix = cvMat(2, 3, CV_32F, map);// 旋转中心  CvPoint2D32f center = cvPoint2D32f(width / 2, height / 2);cv2DRotationMatrix(center, degree, 1.0, &map_matrix);map[2] += (width_rotate - width) / 2;map[5] += (height_rotate - height) / 2;IplImage* img_rotate = cvCreateImage(cvSize(width_rotate, height_rotate), 8, 3);//对图像做仿射变换  //CV_WARP_FILL_OUTLIERS - 填充所有输出图像的象素。  //如果部分象素落在输入图像的边界外,那么它们的值设定为 fillval.  //CV_WARP_INVERSE_MAP - 指定 map_matrix 是输出图像到输入图像的反变换,  cvWarpAffine(img, img_rotate, &map_matrix, CV_INTER_LINEAR | CV_WARP_FILL_OUTLIERS, cvScalarAll(0));return img_rotate;
}
需要注意的几个问题

1.Cvloadimage问题

在参考的代码中,因为要返回指向CvArr的指针,所以使用cvLoadImage读入图像,但是使用的是CV_LOAD_IMAGE_UNCHANGED参数,会中断。一个解释是:如果输入有冲突的标志,将采用较小的数字值。CV_LOAD_IMAGE_ANYCOLOR有着可以和CV_LOAD_IMAGE_ANYDEPTH同时使用的优点,CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR可以载入最真实的图像,所以CV_LOAD_IMAGE_UNCHANGED不再使用了。但是将cvLoadImage的参数换成CV_LOAD_IMAGE_ANYDEPTH| CV_LOAD_IMAGE_ANYCOLOR也依然中断。后来经过调试发现,中断发生在cvLogPolar阶段,源图像只要是单通道即灰度图就会中断。而我选择的原图就是单通道的,所以按照原图载入就会发生错误。三通道的图可以被读取成单通道的,而之前我不知道的是单通道的图也可以读取成三通道的。。

cvLoadImage和imread都调用的是imread_函数,只不过参数一个是LOAD_IMAGE,一个是LOAD_MAT。

enum
{
/* 8bit, color or not */CV_LOAD_IMAGE_UNCHANGED  =-1,
/* 8bit, gray */CV_LOAD_IMAGE_GRAYSCALE  =0,
/* ?, color 缺省值,三通道*/CV_LOAD_IMAGE_COLOR      =1,
/* any depth, 任意深度,保持不变? */CV_LOAD_IMAGE_ANYDEPTH   =2,
/* ?, any color 任意颜色,保持不变?*/CV_LOAD_IMAGE_ANYCOLOR   =4
};

2.反变换问题

cvLogPolar的CV_WARP_INVERSE_MAP参数可以实现反变换,但是链接5的代码中把反变换的输入图像写成笛卡尔坐标系下的原图了。

Reference:

1.      https://blog.csdn.net/liyuan02/article/details/6750828

2.      https://blog.csdn.net/xieyan0811/article/details/71106496

3.      https://blog.csdn.net/jjrfjyfjyfjdfjrujdjd/article/details/40268573

4.      Opencv代码cvloadimage:https://blog.csdn.net/w12345_ww/article/details/45362843

5.      https://blog.csdn.net/hitwengqi/article/details/6895215

6.      Unchanged:https://blog.csdn.net/smf0504/article/details/51384023





本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/493687.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

刚刚、Gartner发布物联网技术十大战略和趋势

来源&#xff1a;网络大数据Gartner的研究副总裁尼克•琼斯(Nick Jones)说&#xff1a;“物联网将在未来十年继续为数字化业务创新带来新的机遇&#xff0c;而许多新机遇有赖于新的或经过改进的技术。洞察创新物联网趋势的CIO们有机会领导本企业的数字化创新。”此外&#xff0…

图像的旋转和尺度缩放在对数极坐标系下的研究

首先来看一张特殊的同心圆图像及其极坐标变换&#xff1a;这是我自己在opencv下用cvLogPolar函数做的实验&#xff1a;极坐标原点选择在同心圆圆心时&#xff0c;同一个圆上的点到圆心的距离相等&#xff0c;所以映射在极坐标中应该是一组垂直于极轴的平行线。在自己的实验中因…

李航《统计学习方法》-----支持向量机

书中第七章才是支持向量机SVM&#xff0c;但在SVM与感知机有相似的地方&#xff0c;看了感知机的知识之后趁热先看看SVM。 首先回顾一下感知机。感知机的模型是线性分类模型&#xff0c;将两种类别标记为正负1&#xff0c;将新的样本输入线性函数&#xff0c;再将线性函数代入符…

乌镇互联网大会发布15项世界领先科技成果

来源&#xff1a;中央广电总台央视新闻客户端11月7日下午&#xff0c;第五届世界互联网大会“世界互联网领先科技成果发布活动”在乌镇互联网国际会展中心举行。大会共现场发布了15项世界互联网领域领先的“黑科技”&#xff0c;引得观众阵阵惊叹。15项世界互联网领先科技成果&…

OpenCV中的傅里叶的门道

接触到傅里叶-梅林算法&#xff0c;需要用到傅里叶变换&#xff0c;于是去查了一下OpenCV中的实现方法&#xff0c;没想到习以为常的傅里叶变换之中的门道还不少。 //傅里叶变换https://blog.csdn.net/keith_bb/article/details/53389819Mat I imread("Lena.jpg", I…

Science:人类迎来目前最为全面的癌症染色质可及性图谱

来源&#xff1a;吴晓波频道摘要&#xff1a;肿瘤在世界范围内导致人类死亡的首要原因之一&#xff0c;尤其是随着医疗水平的发展&#xff0c;人类的寿命的不断延长&#xff0c;癌症逐渐成为威胁人类健康的首要因素。肿瘤在世界范围内导致人类死亡的首要原因之一&#xff0c;尤…

傅里叶变换频谱的可视化保存

在上一篇关于傅里叶变换的博客中&#xff0c;知道了imshow的一个小trick&#xff1a;对normalize得到的0~1之间的浮点数构成的矩阵会进行放大255的操作&#xff0c;得到可视化的灰度图。即便是在python中也是如此操作的&#xff0c;只不过python中的函数封装得更加严密&#xf…

她取代马斯克成特斯拉新董事长 究竟什么来头?

来源&#xff1a;智车科技摘要&#xff1a;就如乔布斯之于苹果&#xff0c;对很多人来说&#xff0c;马斯克对特斯拉而言也有非凡的意义。甚至可以说&#xff0c;特斯拉的品牌吸引力很大程度上来自于“钢铁侠”本人。但由于当初任性发布“私有化”消息&#xff0c;被美国证交会…

十二天深入理解计算机系统(一)

计算机系统漫游 1 信息就是位上下文 系统中所有的信息都是由一串位表示的&#xff0c;在不同的上下文中&#xff0c;一个同样的字节序列可能表示一个整数、浮点数、字符串或者机器指令。 2 文本文件和二进制文件 有ASCII字符构成的文件称为文本文件&#xff0c;所有其他文件都是…

李航《统计学习方法》-----朴素贝叶斯

朴素贝叶斯法nave Bayes&#xff0c;在nave的中间字母上其实有两个点&#xff0c;查了一下才发现是法语中的分音符&#xff0c;在发音过程中发挥作用。但这不是重要的&#xff0c;重要的是在这种学习方法中贝叶斯承担了什么样的角色。 首先简单证明一下贝叶斯公式。联合概率Joi…

IEEE专访李开复:人类已打开潘多拉盒子,封堵AI变革只会徒劳

来源&#xff1a;《IEEE Spectrum》摘要&#xff1a;近期&#xff0c;李开复新书《AI未来》在美国同样反响不俗。在荣登多个排行榜后&#xff0c;IEEE旗下《IEEE Spectrum》&#xff0c;对李开复进行了专访&#xff0c;谈到了众多当前AI领域最受关注的话题。而且从《IEEE Spect…

Rand函数使用和对补码的理解

下面是在牛客网看到的一道题; //假设这n个数的序号依次为0,1,2,...,n-1,数组名为num void knuth1(int* pNum, int m, int n){srand((unsigned int)time(0));for (int i0; i<n; i){if (rand()%(n-i) < m)//rand()%(n-i)的取值范围是[0, n-i&#xff09;{cout << p…

深度学习巨头Yoshua Bengio清华演讲: 深度学习通往人类水平人工智能的挑战

来源&#xff1a;专知摘要&#xff1a;2018年11月7日晚&#xff0c;被称为“深度学习三巨头”之一的蒙特利尔大学计算机科学与运算研究系教授Yoshua Bengio在清华大学做了《深度学习抵达人类水平人工智能所面临的挑战&#xff08;Challenges for Deep Learning towards Human-L…

了解GAN网络

GAN网络&#xff0c;第一次听说它就不明觉厉。其他网络都是对输入图像进行某种处理&#xff0c;得到某种特定的输出。而GAN网络居然可以“无中生有”&#xff0c;无论是去除马赛克&#xff0c;还是换脸&#xff0c;还是对灰度图像上色&#xff0c;都显得不可思议&#xff0c;怎…

新能源汽车:大变革催生十万亿市场空间

来源&#xff1a;新时代证券&#xff08;开文明&#xff09;新能源汽车发展空间巨大&#xff0c;随着新能源汽车性能提升以及痛点的改善&#xff0c;新能源汽车带来的冲击越来越大&#xff0c;渗透率随之提升。根据BNEF预测&#xff0c;到2025年全球新能源汽车的销量将达到1100…

dlib+vs2013+opencv实现人脸特征点检测

刷知乎的时候发现dlib做特征点检测和人脸识别的效果都好于OpenCV&#xff0c;就想着动手玩一下。没想到也是遇坑重重。 首先&#xff0c;在官网 install命令和setup.py文件进行安装时报错&#xff0c;先是报错cmake没有找到&#xff0c;添加了环境变量之后仍然报错c11需要在vs…

对号入座,看看未来几年机器人是否会取代你的工作

来源&#xff1a;资本实验室摘要&#xff1a;面对未来&#xff0c;你是否准备好了&#xff1f;“机器是否会取代人类的工作”是当前讨论最多的话题之一。这主要源自于近几年以人工智能为代表的新技术的快速发展与商业化。尽管各研究机构的预测数据有所不同&#xff0c;但相同的…

冈萨雷斯《数字图像处理》读书笔记(十一)——表示和描述

虽然不是专门研究图像分割的&#xff08;峰兄才是&#xff09;&#xff0c;但多少接触了一点&#xff0c;并且图像分割是图像处理中的最为复杂的&#xff0c;通过图像分割可以很好地认识图像处理的好多方法。今天看的是边界追踪和链码的表示。网易计算机视觉工程师的第一道选择…

细胞内钾多钠少——原初生物的第三大遗迹?

来源&#xff1a;科学网在我们每日的饮食中&#xff0c;食盐&#xff08;氯化钠&#xff09;是少不了的&#xff0c;难以想象我们怎么能够每天吃完全没有盐味的食物。不仅人类如此&#xff0c;许多动物&#xff0c;例如食草的动物如牛和羊&#xff0c;也会主动寻找土表盐粒。我…

冈萨雷斯《数字图像处理》读书笔记(九)——形态学图像处理

形态学来自于生物学&#xff0c;研究动植物的形态和结构。运用在图像中可提取如边界、骨架和凸壳。初学形态学都是在二值化的图像上研究&#xff0c;之后可以扩展到灰度图像。 膨胀和腐蚀 数学形态学与集合论分不开&#xff0c;因为形态学中的操作是基于两个集合的&#xff0…