转自:https://blog.csdn.net/u010551600/article/details/78461142

柱面投影是图片拼接的前期的一部分工作,以下代码只是简单的实现了投影,还可以优化,

柱面半径设置位图片宽度的一半,即 R = width/2

代码运算流程是 对于dst图片上的每一个像素点,通过公式计算出src上对应的位置(hnum,wnum),把src上这个位置的像素值赋值给dst。

#include <iostream>
#include <opencv2/opencv.hpp>using namespace std;
using namespace cv;/*
实现一个简单的图像投影实例,
算法根据csdn博客http://blog.csdn.net/weixinhum/article/details/50611750
该代码对目录下的test图片进行柱面投影
*/
int main()
{Mat src = imread("test.jpg");Mat dst(src.rows,src.cols,src.type());int width = src.cols, height = src.rows;double x, y;double R = width / 2;int drcpoint;for (int hnum = 0; hnum < height;hnum++){for (int wnum = 0; wnum < width;wnum++){double k = R / sqrt(R*R + (wnum - width / 2)*(wnum - width / 2));x = (wnum - width / 2) / k + width / 2;y = (hnum - height / 2) / k + height / 2;if (0 < x && x < width && 0 < y &&y < height){dst.at<Vec3b>(hnum, wnum) = src.at<Vec3b>(int(y), int(x));}}}imshow("origin Image",src);imshow("柱面投影图",dst);waitKey(0);return 0;
}

运行结果:

算法思想参考:http://blog.csdn.net/weixinhum/article/details/50611750

图像的柱面投影算法,在360°环形全景应用中几乎一定会用到。而为何要用该算法,可以参考下图:

从图像中可以看到,該环形全景设备由八个摄像头环形排列而成(需注意环形全景的形态并不固定,摄像头的个数不一定是八个,甚至只有一个摄像头在一直匀速转圈也是可以的)。每个摄像头所拍摄的画面为其前方的实线段区域,为了之后能进行图像的拼接,相邻摄像头之间必须要有图像的重合区域,如上图的红色线段部分(如果能保证刚刚好相接也可以,不过结构难度太高)。

从不同摄像头的重合区域可以看到,由于摄像头的朝向不同,重合部分图像中的物体并不满足视觉一致性的要求,因此需要将图像进行投影,使其满足图像的一致性要求,为后面的拼接做准备(视觉一致性是全景应用最为关键的问题,无论是柱环形全景还是球形全景,都无法避免,只是所选的投影模型不同罢了)。在环形全景中,一般选择柱面投影算法,将图像分别投影到以 像素焦距+摄像头与圆心距离 为半径的圆柱上。投影后的图像为上图摄像头前方的圆弧。从圆弧上看,图像的重合部分已经满足视觉一致性的要求,可以做拼接。而如何去投影就是本文要介绍的。

柱面投影的数学模型相对比较简单,把观测点定在圆柱体的中心,图像的像素焦距+摄像头与圆心距离 为圆柱体的半径,则摄像头所拍摄的图像与圆柱体相切。图像上的一点Q与观测点连线,该连线与圆柱面的交点点Q'为图像点Q在柱面上的投影,我们需要做的就是求出点Q(x,y)与点Q'(x',y')之间的换算关系。先看看下图:

该图的实线部分为投影模型的俯视图,下方的线段a为待投影的图像,圆为圆柱切面,O为观测点。而虚线部分为Y轴方向上的辅助线。现在设A为图像上的任意一点,其坐标为(x,y,z),其中z=-R,则其在x-z坐标系上的投影A'的坐标为(x,-R)。B为我们要求的点A在圆柱面上的投影点,其坐标为(x',y',z'),则其在x-z坐标系上的投影点B'的坐标为(x',z')。

由于△0BB'与△OAA'相似,△0B'F与△OA'G相似

则有BB'=kAA',B'F=kA'G,OF=kR(k<1)

则kx=x',ky=y'

又OF²+B'F²=R²

故k²R²+k²x²=R²

又x'=kx,y'=ky

由于一般来说图像以左上角为坐标原点,而上面公式中的坐标系以图像的中心为坐标原点,所以在实际图像的计算中,上面的计算公式换为

有了上面的公式,便可计算出图像的柱面投影结果。这里需要注意的是我们把x和y写在了等式的左边而x',y'写在了右边,这样做是为了方便我们后面进行插值计算。为什么要这么做可以看下面两张图片

左边图像为待投影图像,右边为直接投影的结果,由于投影后的图像点坐标未必为整数,而图像的坐标需要为整数,所以必将造成误差。表现在右边图像上就是图像有很多显而易见的毛刺。而我们进行双线性插值之后的投影图像如下

可以看到,其毛刺得到了一定的抑制。上面的图像还说明了经过柱面投影的图像会比原来的图像宽度小,具体小多少跟R有关,由于比较简单,在这里不再给出推导的过程。以上投影过程的主要代码如下

void DealWithImgData(BYTE *srcdata, BYTE *drcdata,int width,int height)//参数一为原图像的数据区首指针,参数二为投影后图像的数据区首指针,参数三为图像的宽,参数四为图像的高
{//双线性插值算法int i_original_img_hnum, i_original_img_wnum;//目标点坐标double distance_to_a_y, distance_to_a_x;//在原图像中与a点的水平距离  int original_point_a, original_point_b, original_point_c, original_point_d;int l_width = WIDTHBYTES(width* 24);//计算位图的实际宽度并确保它为4byte的倍数int drcpoint;double R = 1200;//像素距离double x, y;for (int hnum = 0; hnum < height; hnum++){for (int wnum = 0; wnum < width; wnum++){drcpoint = l_width*hnum + wnum * 3;//数组位置偏移量,对应于图像的各像素点RGB的起点//柱面投影double k = R / sqrt(R*R + (wnum- width / 2) * (wnum - width / 2));x = (wnum - width / 2) / k + width / 2;y = (hnum - height / 2) / k + height / 2;if (x >= 0 && y >= 0 && x < width && y < height){/***********双线性插值算法***********/i_original_img_hnum = y;i_original_img_wnum = x;distance_to_a_y = y - i_original_img_hnum;distance_to_a_x = x - i_original_img_wnum;//在原图像中与a点的垂直距离  original_point_a = i_original_img_hnum*l_width + i_original_img_wnum * 3;//数组位置偏移量,对应于图像的各像素点RGB的起点,相当于点A    original_point_b = original_point_a + 3;//数组位置偏移量,对应于图像的各像素点RGB的起点,相当于点B  original_point_c = original_point_a + l_width;//数组位置偏移量,对应于图像的各像素点RGB的起点,相当于点C   original_point_d = original_point_c + 3;//数组位置偏移量,对应于图像的各像素点RGB的起点,相当于点D  if (i_original_img_hnum == height - 1){original_point_c = original_point_a;original_point_d = original_point_b;}if (i_original_img_wnum == width - 1){original_point_a = original_point_b;original_point_c = original_point_d;}drcdata[drcpoint + 0] =srcdata[original_point_a + 0] * (1 - distance_to_a_x)*(1 - distance_to_a_y) +srcdata[original_point_b + 0] * distance_to_a_x*(1 - distance_to_a_y) +srcdata[original_point_c + 0] * distance_to_a_y*(1 - distance_to_a_x) +srcdata[original_point_c + 0] * distance_to_a_y*distance_to_a_x;drcdata[drcpoint + 1] =srcdata[original_point_a + 1] * (1 - distance_to_a_x)*(1 - distance_to_a_y) +srcdata[original_point_b + 1] * distance_to_a_x*(1 - distance_to_a_y) +srcdata[original_point_c + 1] * distance_to_a_y*(1 - distance_to_a_x) +srcdata[original_point_c + 1] * distance_to_a_y*distance_to_a_x;drcdata[drcpoint + 2] =srcdata[original_point_a + 2] * (1 - distance_to_a_x)*(1 - distance_to_a_y) +srcdata[original_point_b + 2] * distance_to_a_x*(1 - distance_to_a_y) +srcdata[original_point_c + 2] * distance_to_a_y*(1 - distance_to_a_x) +srcdata[original_point_c + 2] * distance_to_a_y*distance_to_a_x;/***********双线性插值算法***********/}}}
}

完结。

图片柱面投影简单实现相关推荐

  1. 图像拼接---图片柱面投影简单实现

    算法思想参考:http://blog.csdn.net/weixinhum/article/details/50611750 柱面投影是图片拼接的前期的一部分工作,以下代码只是简单的实现了投影,还可以 ...

  2. 柱面投影matlab程序

    拼接之前要进行柱面.立方体面或者球面投影,<全景拼接的关键技术研究>选的是柱面投影,根据其理论有: %假设相机市场角为45度 %反投影到柱面时左右有缝隙了 A=imread('F:\fis ...

  3. matlab 柱面投影,图像拼接(不投影到柱面)(渐入渐出融合) matlab程序

    1,先拍摄一组图片,比如两幅图:A.B 我直接用网上的两幅图: 2,分别投影到柱面坐标系 就用自己写的柱面投影程序 matlab里 结果: 3,开始配准第一步:SIFT得到匹配对(直接用OpenCV里 ...

  4. 图像拼接(一):柱面投影+模板匹配+渐入渐出融合

    这种拼接方法的假设前提是:待拼接的两幅图像之间的变换模型是平移模型,即两幅图像同名点位置之间只相差两个未知量:ΔxΔx 和ΔyΔy,自由度为2,模型收得最紧.所以只有所有图像都是用同一水平线或者同一已 ...

  5. 柱面投影的C++实现(一)

    本文介绍柱面投影具体做法:若要实现柱面投影变换,除了需要获取源图像数据以外,还需要已知相机镜头的一些信息-- (信息A:相机焦距+目标距离) (信息B:图像变换尺度s,与相机焦距f成正比) (信息C: ...

  6. TensorFlow与OpenCV,读取图片,进行简单操作并显示

    本文是OpenCV  2 Computer Vision Application Programming Cookbook读书笔记的第一篇.在笔记中将以Python语言改写每章的代码. PythonO ...

  7. php 识别图片主色调,PHP 判断图片主色调的简单示例

    这篇文章主要为大家详细介绍了PHP 判断图片主色调的简单示例,具有一定的参考价值,可以用来参考一下. 这段代码可以帮助你判断任意图片的主色调,使用了简单的统计算法实现 ,感兴趣的小伙伴,下面一起跟随5 ...

  8. php中调整图片大小,php 调整图片尺寸的简单示例

    这篇文章主要为大家详细介绍了php 调整图片尺寸的简单示例,具有一定的参考价值,可以用来参考一下. 对php调整图片尺寸的代码感兴趣的小伙伴,下面一起跟随512笔记的小编两巴掌来看看吧! /** * ...

  9. C++ MFC打开图片并进行简单算法处理

    C++ MFC打开图片并进行简单算法处理 VC++中建立新项目 双击"打开图片"按钮进入消息映射函数,添加以下代码: 一.为按钮添加打开文件的功能,并默认打开.png格式的文件,并 ...

最新文章

  1. javascript 六种数据类型
  2. 用JavaScript实现函数重载
  3. ASUS华硕笔记本电脑的数字小键盘按什么健切换?
  4. 什么是光纤的波长?看看有哪些是你不知道的!
  5. 数据挖掘 pandas基础入门之查看数据
  6. Android-service
  7. 病的不轻?教你 2 招,拯救拖延症!
  8. Linux 下使用Java连接 mysql
  9. Pivotal冯雷:以数字化为核心竞争力的时代 自主可控是企业的“必然选择”
  10. Java为xml跟节点添加子节点_如何将xml节点作为第一个子节点插入Java中的另一个xml文档中?...
  11. cenyos7安装 yum不可用_centos7安装fabric
  12. 5 分钟掌握智联招聘网站爬取并保存到 MongoDB 数据库
  13. 硬件描述测试软件库中74138,杭电数电实验课内题设计答案.docx
  14. 自定义控件学习笔记(三)Paint详解
  15. 微信小程序及其兼容性
  16. Java项目:springboot ERP管理系统
  17. 1.学生党如何查找文献书籍
  18. cad标注样式快捷键_说说CAD尺寸精度设置的两种方法!
  19. 细数网易云音乐上那些适合开车时听的歌单。
  20. 2022Android各APP免费加固方案评估

热门文章

  1. Opengl Lesson 1 心形曲线
  2. JS + ES6 高频面试题合集
  3. abb机器人--示教器--基础认识
  4. ubuntu术后那些事儿
  5. Android开发资源(一)
  6. 树莓派wiringPi安装及交叉编译
  7. CATIA工程图转AUTO CAD设置详解
  8. 主机大师php5.6安装教程,护卫神主机大师
  9. webservice教程[转]
  10. 计算机辅助设计技术的应用研究,计算机辅助设计软件在室内设计中的应用研究...