1. 程式人生 > >【OpenGL】Android端Camera與OpenGL融合顯示(AR技術基礎)

【OpenGL】Android端Camera與OpenGL融合顯示(AR技術基礎)

Android端Camera與OpenGL融合顯示(AR技術基礎)

import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ConfigurationInfo;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.opengl.GLSurfaceView;
import android.util.Log;
import android.view.Display;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;

import android.hardware.Camera.Parameters;
import android.provider.Settings.System;
import android.app.Activity;
import android.view.Display;
import android.view.Menu;
import android.view.Surface;

import android.view.SurfaceHolder.Callback;
import android.view.ViewGroup.LayoutParams;


import java.io.IOException;

public class MainActivity extends AppCompatActivity {

    private final int CONTEXT_CLIENT_VERSION = 1;

    private PreView mPreView;
    private GLSurfaceView mGLSurfaceView;

    FrameLayout frameLayout;

    private int mWidth = 0;
    private int mHeight = 0;
    private FrontCamera mFrontCamera = new FrontCamera();
    private SurfaceView mSurface;
    private SurfaceHolder mHolder;
    private Context mContext;

    //private PreView preview;

    GLSurfaceView surfaceView;
    MyRendererPNG render;

    int width,height;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = this;

        //mPreView = (PreView)findViewById(R.id.surfaceView);
        //mGLSurfaceView = new GLSurfaceView ( this );

        //requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        WindowManager wManager = (WindowManager)getSystemService(WINDOW_SERVICE);
        Display display = wManager.getDefaultDisplay();
        width = display.getWidth();
        height = display.getHeight();
        setContentView(R.layout.activity_main);
        frameLayout = (FrameLayout)findViewById(R.id.frameView);

        /**
         * 先新增GLSurfaceView
         */
        surfaceView = new GLSurfaceView(this);
        surfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
        /**
         * Set the desired PixelFormat of the surface. The default is OPAQUE. When working with a SurfaceView,
         * this must be called from the same thread running the SurfaceView's window.
         */
        surfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
        render = new MyRendererPNG();
        surfaceView.setRenderer(render);
        frameLayout.addView(surfaceView, new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));

        /**
         * 再新增SurfaceView圖層
         */
        mSurface = new SurfaceView(this);
        mHolder = mSurface.getHolder();
        mHolder.addCallback(new Callback()
        {
            @Override
            public void surfaceDestroyed(SurfaceHolder holder)
            {
                mFrontCamera.stopCamera();
            }

            @Override
            public void surfaceCreated(SurfaceHolder holder)
            {
                //初始化前置攝像頭
                mFrontCamera.openCam(holder ,mContext);
                mFrontCamera.everyTime();
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
            {
                mFrontCamera.pingMuChange();
            }
        });
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        frameLayout.addView(mSurface, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));

    }

    @Override
    protected void onResume()
    {
        // Ideally a game should implement onResume() and onPause()
        // to take appropriate action when the activity looses focus
        super.onResume();
    }


    @Override
    protected void onPause()
    {
        // Ideally a game should implement onResume() and onPause()
        // to take appropriate action when the activity looses focus
        super.onPause();
    }
}
import android.app.Activity;
import android.content.Context;
import android.hardware.Camera;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;

import java.io.IOException;

public class FrontCamera{
    static final String TAG = "CameraTag";
    public Camera mCamera;
    public byte[] mData = null;
    public int w = 0;
    public int h =0;
    int mCurrentCamIndex = 0;
    Context mContext;

    //初始化相機
    public Camera initCamera() {
        int cameraCount = 0;
        Camera cam = null;
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        cameraCount = Camera.getNumberOfCameras();

        for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
            Camera.getCameraInfo(camIdx, cameraInfo);

            //在這裡開啟的是前置攝像頭,可修改開啟後置OR前置
            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                try {
                    Log.i(TAG, "初始化相機 CameraIndex " + camIdx);
                    cam = Camera.open(camIdx);
                    mCurrentCamIndex = camIdx;
                } catch (RuntimeException e) {
                    Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage());
                }
            }
        }
        return cam;
    }

    /**
     * 停止相機
     *
     * */
    public void stopCamera() {
        if (mCamera != null) {
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview();
            mCamera.release();
            Log.i(TAG, "StopCamera: 停止預覽並釋放資源");
            mCamera = null;
        }
    }

    /**
     * 旋轉屏幕後自動適配(若只用到豎的,也可不要)
     * 已經在manifests中讓此Activity只能豎屏了
     * @param activity 相機顯示在的Activity
     * @param cameraId 相機的ID
     * @param camera 相機物件
     */
    public static void setCameraDisplayOrientation(Activity activity, int cameraId, Camera camera)
    {
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(cameraId, info);
        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
        int degrees = 0;
        switch (rotation)
        {
            case Surface.ROTATION_0: degrees = 0; break;
            case Surface.ROTATION_90: degrees = 90; break;
            case Surface.ROTATION_180: degrees = 180; break;
            case Surface.ROTATION_270: degrees = 270; break;
        }
        int result;
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
        {
            result = (info.orientation + degrees) % 360;
            result = (360 - result) % 360;  // compensate the mirror
        }
        else
        {
            // back-facing
            result = (info.orientation - degrees + 360) % 360;
        }
        camera.setDisplayOrientation(result);
    }

    public void everyTime()
    {
        mCamera.setPreviewCallback(new Camera.PreviewCallback() {
            @Override
            public void onPreviewFrame(byte[] data, Camera camera) {
               
                mData = data;
                Camera.Size size = camera.getParameters().getPreviewSize();
                w = size.width;
                h = size.height;

            }
        });
    }

    public void openCam(SurfaceHolder holder, Context mContext)
    {
        this.mContext = mContext;
        if (mCamera == null)
        {
            mCamera = initCamera();
            Log.i(TAG, "mCamera: " + mCamera.toString());
        }

        try {
            //適配豎排固定角度
            Log.i(TAG, "mCamera: " + mCamera.toString());
            setCameraDisplayOrientation((Activity) mContext, mCurrentCamIndex, mCamera);
            mCamera.setPreviewDisplay(holder);
            Log.i(TAG, "開始預覽");


        } catch (IOException e) {
            mCamera.release();
            mCamera = null;
        }
    }

   public void pingMuChange()
   {
       Camera.Parameters parameters = mCamera.getParameters();
       parameters.setPreviewSize(320,240);
       parameters.setPreviewFrameRate(15);
       parameters.setSceneMode(Camera.Parameters.SCENE_MODE_NIGHT);
       parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
       //mCamera.setParameters(parameters);
       mCamera.startPreview();
   }

}
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.opengl.GLSurfaceView.Renderer;

public class MyRendererPNG implements Renderer
{
    float[] verteices = new float[]
            {
                    0.1f,0.6f,0.0f,
                    -0.3f,0.0f,0.0f,
                    0.3f,0.1f,0.0f
            };
    int[] colors = new int[]
            {
                    65535,0,0,0,
                    0,65535,0,0,
                    0,0,65535,0
            };

    FloatBuffer vBuffer = MemUtil.makeFloatBuffer(verteices);
    IntBuffer cBuffer = MemUtil.makeIntBuffer(colors);

    public MyRendererPNG ()
    {
    }
    @Override
    public void onDrawFrame(GL10 gl)
    {
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT|GL10.GL_DEPTH_BUFFER_BIT);
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity();
        gl.glTranslatef(0.0f, 0.0f, -1.0f);
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vBuffer);
        gl.glColorPointer(4, GL10.GL_FIXED, 0, cBuffer);
        gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
        gl.glFinish();
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height)
    {
        gl.glViewport(0, 0, width, height);
        gl.glMatrixMode(GL10.GL_PROJECTION);
        gl.glLoadIdentity();
        float ratio = (float)width/height;
        gl.glFrustumf(-ratio, ratio, -1, 1, 1, 9);
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config)
    {
        gl.glDisable(GL10.GL_DITHER);
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
        gl.glClearColor(0, 0, 0, 0);
        gl.glShadeModel(GL10.GL_SMOOTH);
        gl.glEnable(GL10.GL_DEPTH_TEST);
        gl.glDepthFunc(GL10.GL_LEQUAL);
    }

}
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

/**
 * Created by duan on 2017.
 */

public class MemUtil {

    public static FloatBuffer makeFloatBuffer(float[] arr){
        ByteBuffer bb = ByteBuffer.allocateDirect(arr.length * 4);
        bb.order(ByteOrder.nativeOrder());
        FloatBuffer fb = bb.asFloatBuffer();
        fb.put(arr);
        fb.position(0);
        return fb;
    }

    public static IntBuffer makeIntBuffer(int[] arr){
        ByteBuffer bb = ByteBuffer.allocateDirect(arr.length * 4);
        bb.order(ByteOrder.nativeOrder());
        IntBuffer fb = bb.asIntBuffer();
        fb.put(arr);
        fb.position(0);
        return fb;
    }
}

Taily老段的微信公眾號,歡迎交流學習

相關推薦

OpenGLAndroidCameraOpenGL融合顯示AR技術基礎

Android端Camera與OpenGL融合顯示(AR技術基礎) import android.app.ActivityManager; import android.content.Context; import android.content.pm.Confi

乾貨Android studio教程問題彙總

The LogCat window no longer switches to a different process when the current process dies (issue 161145 ) Prevent "StartupAbortedException" for the IDE wh

Java 大話資料結構(18) 排序演算法(5) 直接插入排序 資料結構演算法合集 資料結構演算法合集

本文根據《大話資料結構》一書,實現了Java版的直接插入排序。 更多:資料結構與演算法合集 基本概念   直接插入排序思路:類似撲克牌的排序過程,從左到右依次遍歷,如果遇到一個數小於前一個數,則將該數插入到左邊所有比自己大的數之前,也就是說,將該數前面的所有更大的數字都後移一位,空出來的位置放入該數。

JNI Android呼叫JNI的進階例項攝像頭預覽資料轉碼RGB播放

這裡要說下,儘量不要用Java寫編解碼的東西,就算你是大神,你寫的出來,但那也是不實用的,就像切西瓜一樣,拿一把削水果刀去切西瓜,肯定比不上用西瓜刀方便吧,還是老老實實寫個JNI呼叫得了,也不復雜C/C++方便的很,當然,這裡不是說Java不行,語言只是工具,做什

2017秋-軟件工程第七次作業1-探路者貪吃蛇阿爾法發布展示視頻展示

軟件工程 lin 使用 .html -1 target 背景音樂 targe 核心 Part One 【探路者】選題展示視頻鏈接: http://www.iqiyi.com/w_19ruzx6xud.html Part Two 【貪吃蛇】阿爾法發布視頻截圖 1視頻的前半部

PHP中的後期靜態綁定Late Static Bindings

mbo 代碼 當前 test num ngs color public name php5.3版本新增的靜態綁定的靜態綁定語法,也成為PHP的後期靜態綁定,如下 class A{ public static function func1(){ e

金蝶EAS BOS工作流開發附帶JAVA指令碼

目錄(?)[+] 流程配置基本知識及示例 重要概念 流程變數 任務輸入輸出 注意事項 基本流程的配置示例

轉載vscode佔滿cpu的解決方法rg.exe佔用

【轉載】VScode佔用cup100% – 作者:zhengrong__ 百度搜到的,真的太有用了。 最近遇到的問題,vscode一開電腦就開始卡,明明是新電腦。。。開啟工作管理員發現cpu佔用率幾乎100%,是3個rg.exe佔用的。百度了一下才找到方法。 在VScode中檔

精華PhalApi 2.x 新版本釋出流程歡迎來開源

當前,2.x新版本釋出的流程,主要如下。   重要的資訊 PhalApi 2.x Kernal核心包(底層程式碼在這裡):https://github.com/phalapi/kernal PhalApi 2.x 專案(直接可用於開發的專案):https://github.com/phalapi/p

心得Lattice和Xilinx工具關鍵特性對比Diamond、ISE

【根索引】 【索引】FPGA相關 背景 由於FPGA器件選型為Lattice的,所以由之前熟悉的ISE切換到Diamond,目前還在不斷適應中,有些過程體會,記錄下來供參考。按開發流程,講一些常用的特性進行對比,列舉如下: IP Core管理 Diamond初次見面的坑 內建邏輯分析儀(俗

FPGA FIR 濾波器之濾波器的係數資料Filter Coefficient Data

Filter Coefficient Data 濾波器係數使用副檔名為.coe的係數檔案提供給FIR編譯器。 這是一個ASCII文字檔案,帶有單行標題,用於定義用於係數資料的數字表示的基數,後跟係數值本身。 對於N抽頭濾波器,如圖3-36所示。 濾波器係數可以以整數的

STM32SPI的基本原理、庫函式SPI一般步驟

《STM32中文參考手冊V10》-第23章 序列外設介面SPI SPI的基本介紹 SPI的簡介 SPI,是英語Serial Peripheral interface的縮寫,顧名思義就是序列外圍裝置介面,是Motorola首先在其MC68HCXX系列處理器上定義

解決Centos7 離線安裝gcc-4.8.5利用rpm包

最近需要在Centos7 安裝gcc-4.8.5,但很不幸,環境沒有網路,因此只能手動下載回所有依賴,並依次安裝。 一開始我是不知道gcc-4.8.5有什麼依賴的,就到網上去找gcc-4.8.0等其他版本的依賴(因為找不到有講gcc-4.8.5的版本),然後再自己揣摩,但這樣效率很低

Excel五種方法新增打勾方框其他符號差不多

【Excel】五種方法新增打勾方框(其他符號差不多) office2013 方法一 ALT+9745 對應效果圖 按住ALT鍵不放,輸入9745四個數字,鬆開ALT鍵,即可。 這是一種符號輸入系統,不同的數字對應不同的符號 對應對映關係(連結來源:百

WPF後臺傳資料給前臺ListBox顯示實時顯示

因為需要實時接受資料並顯示到前臺ListBox中,所有使用下面這個方法。因為WPF前臺的樣式可以做的很炫,就用到style去寫樣式。 前臺: <Window.Resources> <

動畫簡易製作貝塞爾曲線動畫JS+css3+canvas

一些廢話(直接看程式碼的可跳過) 貝塞爾曲線:什麼是貝塞爾曲線?用過PS的就知道,那破鋼筆工具就是,什麼,沒用過?自行百度用法。 需要的工具 ctrl+c、ctrl+v 直接上程式碼 <!DOCTYPE html>

題解洛谷各種字串問題合集持續更新中

洛谷 P1449 字尾表示式 這道題需要手動模擬棧的操作。讀入字元,當字元不為終止字元@時,如果讀入的是數字就用now記錄下它的值,如果讀入的是 . 就將得到的數字值放到棧頂,並清空now。當讀到運算子時,就拿棧頂元素下面的第一個元素和棧頂元素進行加減乘除的操作,並將棧頂清

IonicIonic實現iOSAndroid程式碼『熱更新』Android升級下載功能 v1.3.x版本

熱更新的好處 通常ionic原始碼可包括(HTML,JavaScript,CSS檔案和其他資源),往常我們必須通過提交程式到應用市場,經過漫長的稽核後才可讓使用者更新,每改動一個小地方都需要重新打新版本。 現在ionic通過使用cordova外掛cordov

筆記移動H5數字鍵盤input type=number的處理IOS和Android

!= 字符串 文檔 代碼 || clear tcl rfi 導致 在Vue中的項目,基於VUX-UI開發,一個常見的需求: 1、金額輸入框 2、彈出數字鍵盤 3、僅支持輸入兩位小數,限制最大11位數,不允許0開頭   第一,首先想到額就是在VUX-UI中制定ty

文件下載之斷點續傳客戶服務的實現

http協議 當前時間 end box [] ada demo 服務端 sem 【轉】文件下載之斷點續傳(客戶端與服務端的實現) 【轉】文件下載之斷點續傳(客戶端與服務端的實現) 前面講了文件的上傳,今天來聊聊文件的下載。 老規矩,還是從最簡單粗暴的開始。那麽多簡單算簡單