将双鱼眼视频转换为全景视频

6

我使用了开源框架来将双鱼眼视频(从Ricoh Theta S相机接收)转换为全景图格式(用于iOS应用)。

双鱼眼图像示例: 输入图像描述

全景图示例: 输入图像描述

我使用以下着色器:

equirectangular.frag

  // based on ThetaShaderPack_20150926 (http://stereoarts.jp/) written by Nora.
#ifdef GL_ES
// define default precision for float, vec, mat.
precision highp float;
#endif

#define PI 3.14159265358979
#define _THETA_S_Y_SCALE    (640.0 / 720.0)

uniform sampler2D mainTex;
uniform float radius;
uniform vec4 uvOffset;

varying vec2 texCoordVarying;

void main (void) {
    vec2 revUV = texCoordVarying.st;
    if (texCoordVarying.x <= 0.5) {
        revUV.x = revUV.x * 2.0;
    } else {
        revUV.x = (revUV.x - 0.5) * 2.0;
    }

    revUV *= PI;

    vec3 p = vec3(cos(revUV.x), cos(revUV.y), sin(revUV.x));
    p.xz *= sqrt(1.0 - p.y * p.y);

    float r = 1.0 - asin(p.z) / (PI / 2.0);
    vec2 st = vec2(p.y, p.x);

    st *= r / sqrt(1.0 - p.z * p.z);
    st *= radius;
    st += 0.5;

    if (texCoordVarying.x <= 0.5) {
        st.x *= 0.5;
        st.x += 0.5;
        st.y = 1.0 - st.y;
        st.xy += uvOffset.wz;
    } else {
        st.x = 1.0 - st.x;
        st.x *= 0.5;
        st.xy += uvOffset.yx;
    }

    st.y = st.y * _THETA_S_Y_SCALE;

    gl_FragColor = texture2D(mainTex, st);
}

equirectanguler.vert

uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 textureMatrix;
uniform mat4 modelViewProjectionMatrix;

attribute vec4  position;
attribute vec4  color;
attribute vec3  normal;
attribute vec2  texcoord;

varying vec2 texCoordVarying;

void main() {
    texCoordVarying = texcoord;
    gl_Position = modelViewProjectionMatrix * position;
}

使用以下代码: main.mm
#include "ofApp.h"

int main() {

    //  here are the most commonly used iOS window settings.
    //------------------------------------------------------
    ofiOSWindowSettings settings;
    settings.enableRetina = false; // enables retina resolution if the device supports it.
    settings.enableDepth = false; // enables depth buffer for 3d drawing.
    settings.enableAntiAliasing = false; // enables anti-aliasing which smooths out graphics on the screen.
    settings.numOfAntiAliasingSamples = 0; // number of samples used for anti-aliasing.
    settings.enableHardwareOrientation = false; // enables native view orientation.
    settings.enableHardwareOrientationAnimation = false; // enables native orientation changes to be animated.
    settings.glesVersion = OFXIOS_RENDERER_ES2; // type of renderer to use, ES1, ES2, ES3
    settings.windowMode = OF_FULLSCREEN;
    ofCreateWindow(settings);

    return ofRunApp(new ofApp);
}

```

`offApp.mm`

```
#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){    
    ofDisableArbTex();

    devices = theta.listDevices();
    bool isDeviceConnected = false;
    for(int i = 0; i < devices.size(); i++){
        if(devices[i].deviceName == "RICOH THETA S"){
            theta.setDeviceID(devices[i].id);
            isDeviceConnected = true;
        }
    }
    if(!isDeviceConnected){
        ofLog(OF_LOG_ERROR, "RICOH THETA S is not found.");
    }
    theta.initGrabber(360, 568);

    shader.load("shaders/equirectanguler");

    fbo.allocate(320, 568);

    sphere = ofSpherePrimitive(568, 64).getMesh();
    for(int i=0;i<sphere.getNumTexCoords();i++){
        sphere.setTexCoord(i, ofVec2f(1.0) - sphere.getTexCoord(i));
    }
    for(int i=0;i<sphere.getNumNormals();i++){
        sphere.setNormal(i, sphere.getNormal(i) * ofVec3f(-1));
    }

    offset.set("uvOffset", ofVec4f(0,0.0,0,0.0), ofVec4f(-0.1), ofVec4f(0.1));
    radius.set("radius", 0.445, 0.0, 1.0);
    showSphere.set("showSphere", false);
    thetaParams.add(offset);
    thetaParams.add(radius);
    gui.setup(thetaParams);
    gui.add(showSphere);

    cam.setAutoDistance(false);
    cam.setDistance(0);
}

//--------------------------------------------------------------
void ofApp::update(){
    theta.update();
}

//--------------------------------------------------------------
void ofApp::draw(){
    if(theta.isFrameNew()){

        fbo.begin();
        ofClear(0);
        shader.begin();
        shader.setUniformTexture("mainTex", theta.getTexture(), 0);
        shader.setUniforms(thetaParams);
        theta.draw(0, 0, 320, 568);
        shader.end();
        fbo.end();

    }

    if(!showSphere){

        fbo.draw(0, 0, 320, 568);

    }else{

        ofEnableDepthTest();
        cam.begin();
        fbo.getTexture().bind();
        sphere.draw();
        fbo.getTexture().unbind();
        cam.end();

    }

    ofDisableDepthTest();
    gui.draw();
}

//--------------------------------------------------------------
void ofApp::exit(){

}

//--------------------------------------------------------------
void ofApp::touchDown(ofTouchEventArgs & touch){

}

//--------------------------------------------------------------
void ofApp::touchMoved(ofTouchEventArgs & touch){

}

//--------------------------------------------------------------
void ofApp::touchUp(ofTouchEventArgs & touch){

}

//--------------------------------------------------------------
void ofApp::touchDoubleTap(ofTouchEventArgs & touch){

}

//--------------------------------------------------------------
void ofApp::touchCancelled(ofTouchEventArgs & touch){

}

//--------------------------------------------------------------
void ofApp::lostFocus(){

}

//--------------------------------------------------------------
void ofApp::gotFocus(){

}

//--------------------------------------------------------------
void ofApp::gotMemoryWarning(){

}

//--------------------------------------------------------------
void ofApp::deviceOrientationChanged(int newOrientation){

}

offApp.h

#pragma once

#include "ofxiOS.h"
#include "ofxGui.h"

class ofApp : public ofxiOSApp {

    public:
        void setup();
        void update();
        void draw();
        void exit();

        void touchDown(ofTouchEventArgs & touch);
        void touchMoved(ofTouchEventArgs & touch);
        void touchUp(ofTouchEventArgs & touch);
        void touchDoubleTap(ofTouchEventArgs & touch);
        void touchCancelled(ofTouchEventArgs & touch);

        void lostFocus();
        void gotFocus();
        void gotMemoryWarning();
        void deviceOrientationChanged(int newOrientation);

    ofVideoGrabber theta;
    vector<ofVideoDevice> devices;
    ofShader shader;
    ofFbo fbo;
    ofEasyCam cam;
    ofVboMesh sphere;

    ofParameter<ofVec4f> offset;
    ofParameter<float> radius;
    ofParameter<bool> showSphere;
    ofParameterGroup thetaParams;
    ofxPanel gui;
};

在这里是结果: 在iPhone5s上 输入图像描述 请指出我错过了什么。
1个回答

1
我从OpenFrameworks转到GPUImage,并能够在iOS设备上成功地将双鱼眼视频转换为等距矩形格式。 使用了相同的着色器程序。 查看我的存储库

你能告诉我在GPUImage框架中,你用了哪个函数来展开单个鱼眼图像吗? - mm24
我使用了一个 mp4 双鱼眼电影作为输入。输出是一个等距圆柱投影电影文件。 我编写了一个自定义滤镜来完成这个过程。 我使用 GPUImage 从电影中获取纹理,并使用上述自定义着色器将其转换为等距圆柱投影格式。(着色器程序参考:https://github.com/yasuhirohoshino/thetaRealtimeEquirectangular) - Nhat Dinh
我尝试了这个应用程序,它可以很好地处理小视频,但如果视频的大小达到300MB之类的话,它就无法工作了。会不会有什么原因呢? - ΩlostA
可能是内存问题。那只是一个模拟项目。 - Nhat Dinh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接