基于OpenCV的全景图剪切程序

来源:互联网 发布:神州专车价格算法 编辑:程序博客网 时间:2024/05/16 10:54

去年实习的时候,接到一个任务将公司软件生成的一张全景图扭曲切割成六个正常的面,然后动态生成一个3D网页。忙活了2天后完成代码。但最终因为某些原因未被采用。
首先配置OpenCV。
找寻了众多资料,找了一个算是我觉得最靠谱的:http://tieba.baidu.com/p/3931605400

安装好OpenCV以后我们来看原始图片
目标图片

全景图的剪切原理我也不一一叙述了,贴出详细的原理解释:
http://paulbourke.net/geometry/transformationprojection/
接下来我们就po出源码:

 #include <opencv2/imgproc/imgproc.hpp>    #include <opencv2/core/core.hpp>          #include <opencv2/highgui/highgui.hpp>   #include<math.h>#include <iostream>using namespace cv;using namespace std;float M_PI = 3.14159265358979323846f;float faceTransform[6][2] ={    {0, 0},    {M_PI /2,0},    {M_PI,0},    {-M_PI /2,0},    {0,-M_PI/2},    {0,M_PI/2}      };inline void createCubeMapFace(const Mat &in, Mat &face, int faceId = 0, const int width = -1,const int height = -1){    float inWidth = in.cols;                                                     float inHeight = in.rows;     // 获取图片的行列数量//  cout << in.cols;//  cout << in.rows;//  system("pause");    // Allocate map    Mat mapx(height, width, CV_32F);    Mat mapy(height, width, CV_32F);                                         //分配图的x,y轴    // Calculate adjacent (ak) and opposite (an) of the    // triangle that is spanned from the sphere center     //to our cube face.    const float an = sin(M_PI / 4);    const float ak = cos(M_PI / 4);                                          //计算相邻ak和相反an的三角形张成球体中心//  cout << ak;//  cout << an;//  system("pause");    const float ftu = faceTransform[faceId][0];    const float ftv = faceTransform[faceId][1];    // For each point in the target image,     // calculate the corresponding source coordinates.                      对于每个图像计算相应的源坐标    for (int y = 0; y < height; y++) {        for (int x = 0; x < width; x++) {                       // Map face pixel coordinates to [-1, 1] on plane               将坐标映射在平面上            float nx = (float)y / (float)height - 0.5f;            float ny = (float)x / (float)width - 0.5f;            nx *= 2;            ny *= 2;            // Map [-1, 1] plane coord to [-an, an]                                      // thats the coordinates in respect to a unit sphere             // that contains our box.             nx *= an;            ny *= an;            float u, v;            // Project from plane to sphere surface.            if (ftv == 0) {                // Center faces                u = atan2(nx, ak);                v = atan2(ny * cos(u), ak);                u += ftu;            }            else if (ftv > 0) {                // Bottom face                 float d = sqrt(nx * nx + ny * ny);                v = M_PI / 2 - atan2(d, ak);                u = atan2(ny, nx);            }            else {                // Top face                //cout << "aaa";                float d = sqrt(nx * nx + ny * ny);                v = -M_PI / 2 + atan2(d, ak);                u = atan2(-ny, nx);            }            // Map from angular coordinates to [-1, 1], respectively.            u = u / (M_PI);            v = v / (M_PI / 2);            // Warp around, if our coordinates are out of bounds.             while (v < -1) {                v += 2;                u += 1;            }            while (v > 1) {                v -= 2;                u += 1;            }            while (u < -1) {                u += 2;            }            while (u > 1) {                u -= 2;            }            // Map from [-1, 1] to in texture space            u = u / 2.0f + 0.5f;            v = v / 2.0f + 0.5f;            u = u*(inWidth-1);            v = v*(inHeight-1);            mapx.at<float>(x, y) = u;            mapy.at<float>(x, y) = v;        }    }    // Recreate output image if it has wrong size or type.     if (face.cols != width || face.rows != height ||        face.type() != in.type()) {        face = Mat(width, height, in.type());    /*  system("pause");*/    }    // Do actual  using OpenCV's remap    remap(in, face, mapx, mapy, CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));    //  imshow("123", in);    //  imshow("456", face);    if (faceId == 0)    {        imwrite("F:\\cube0000.png", face);    }    else if (faceId == 1)    {        imwrite("F:\\cube0001.png", face);    }    else if (faceId == 2)    {        imwrite("F:\\cube0002.png", face);    }    else if (faceId == 3)    {        imwrite("F:\\cube0003.png", face);    }    else if (faceId == 4)    {        imwrite("F:\\cube0004.png", face);    }    else if (faceId == 5)    {        imwrite("F:\\cube0005.png", face);    }/*  waitKey(10000);*/}int main(){    int faceId = 0;    int width = 1296    ;    int height = 1296;    cv::Mat srcimage = cv::imread("F:\\wmz9(1).hdr");//  namedWindow("游戏原画");//  imshow("游戏原画", srcimage);//  waitKey(6000);    cv::Mat resultImage;  //resultImage= srcimage(Rect(800, 350, srcimage.cols, srcimage.rows));     for (int i = 0; i < 6; i++) {        createCubeMapFace(srcimage, resultImage, i, width, height);    }}

该代码在国内应该找不到实际可用的,至少楼主在找的时候没找到。太多骗积分和过于驳杂的代码,以上代码都是我经过自己的理解,精简到可以利用的最佳形式,希望对大家有所帮助。

然后我们就可以看到六张图:
结果图
接下来要做的就是把它变成一个3D网页
哦,对,我在程序中生成的是png格式的图片,但我最后网页中显示的jpg,其实只用在程序中的后缀改成.jpg即可,但我太懒了,干脆写了一个.bat文件

ren *.png *.jpg

这是一个改后缀的代码。前面是要改的后缀名(可以为空),后面是最后的后缀名。

由于只用做一个简单的展示效果,我就在这里给大家Po一个最简单的Web网页源码

<!DOCTYPE html><html lang="en">    <head>        <title>css transform 3d cube panorama demo</title>        <meta charset="utf-8">        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">        <style>            @-webkit-keyframes spin {                from { -webkit-transform: rotateY(0); }                to   { -webkit-transform: rotateY(-360deg); }            }            @keyframes spin {                from { transform: rotateY(0); }                to   { transform: rotateY(-360deg); }            }            html, body {                background-color: #000000;                margin: 0px;                overflow: hidden;                width: 100%;                height: 100%;            }            #container, #viewer {                width: 100%;                height: 100%;            }            #container {            }            #viewer {                position: absolute;                left: 50%;                top: 100px;                margin-left: -320px;                width: 640px;                height: 360px;                overflow: hidden;                -webkit-transition: -webkit-transform 3s;                transition: transform 3s;                -webkit-perspective: 600px;                perspective: 600px;                -webkit-transform-style: preserve-3d;                transform-style: preserve-3d;            }            #cube {                width: 100%;                height: 100%;                position: relative;                -webkit-transform-style: preserve-3d;                transform-style: preserve-3d;                -webkit-transform-origin: 50% 50% 750px;                //-webkit-animation: spin 12s infinite linear;                //animation: spin 12s infinite linear;                -webkit-transform: translateZ(-150px);                transform: translateZ(-150px);            }            #cube img {                position: absolute;                width: 1500px;                height: 1500px;                top: 50%;                left: 50%;                margin-top: -750px;                margin-left: -750px;                opacity: 0.8;                -webkit-transition: -webkit-transform 3s;                transition: transform 3s;                -webkit-transform-style: preserve-3d;                transform-style: preserve-3d;                -webkit-backface-visibility: hidden;                backface-visibility: hidden;            }            .front {                -webkit-transform: translateZ(750px) translateZ(-750px);                transform: translateZ(750px) translateZ(-750px);            }            .right {                -webkit-transform: translateZ(750px) rotateY(-90deg) translateZ(-750px);                transform: translateZ(750px) rotateY(-90deg) translateZ(-750px);            }            .left {                -webkit-transform: translateZ(750px) rotateY(90deg) translateZ(-750px);                transform: translateZ(750px) rotateY(90deg) translateZ(-750px);            }            .rear {                -webkit-transform: translateZ(750px) translateZ(750px) rotateY( 180deg );                transform: translateZ(750px) translateZ(750px) rotateY( 180deg );            }            .roof {                -webkit-transform: translateZ(750px) rotateX(-90deg) translateZ(-750px);                transform: translateZ(750px) rotateX(-90deg) translateZ(-750px);            }            .floor {                -webkit-transform: translateZ(750px) rotateX(90deg) translateZ(-750px);                transform: translateZ(750px) rotateX(90deg) translateZ(-750px);            }        </style>    </head>    <body>        <div id="container">            <div id="viewer">                <div id="cube">                    <img class="front" src="texture/cube0000.jpg" alt="" />                    <img class="right" src="texture/cube0001.jpg" alt="" />                    <img class="rear" src="texture/cube0002.jpg" alt="" />                    <img class="left" src="texture/cube0003.jpg" alt="" />                    <img class="roof" src="texture/cube0004.jpg" alt="" />                    <img class="floor" src="texture/cube0005.jpg" alt="" />                </div>            </div>        </div>        <script src="jquery-2.0.2.min.js"></script>        <script>(function() {  var x1,      y1,      moving = false,      $viewer = $('#viewer'),      $cube = $('#cube'),      w_v = $viewer.width(), // width of viewer      h_v = $viewer.height(), // height of viewer      c_yaw = 0, // current x      c_pitch = 0,      perspective = 525; // current y  $(document).on('mousedown', function(e) {    x1 = e.pageX;    y1 = e.pageY;    moving = true;    e.preventDefault();  });  $(document).on('mousemove', function(e) {    if( moving === true ) {      x2 = e.pageX;      y2 = e.pageY;      var dist_x = x2 - x1,          dist_y = y2 - y1,          perc_x = dist_x / w_v,          perc_y = dist_y / h_v,          yaw = Math.atan2(dist_y, perspective) / Math.PI * 180,          pitch = -Math.atan2(dist_x, perspective) / Math.PI * 180,          i,          vendors = ['-webkit-', '-moz-', ''];      c_yaw += yaw;      c_pitch += pitch;      c_yaw = Math.min(90, c_yaw);      c_yaw = Math.max(-90, c_yaw);      c_pitch %= 360;      yaw = c_yaw;      pitch = c_pitch;      for(i in vendors) {        $cube.css(vendors[i] + 'transform', 'translateZ(-150px) rotateX(' + yaw + 'deg) rotateY(' + pitch + 'deg)');      }      x1 = x2;      y1 = y2;    }    e.preventDefault();  }).on('mouseup', function(e) {    moving = false;    e.preventDefault();  });})();        </script>    </body></html>

附上JS的链接:http://pan.baidu.com/s/1bpNwWeb

至于你网页的相对位置:
各个元素的相对位置

最后打开html就成功了,用鼠标就可以上下左右的看~~~。

3 0