ARVR技術交流群:129340649
歡迎增加。
AR場景往往給別人留下的印象深刻,假設模型做的炫麗一點,效果將會更好。那么怎樣保存這一美好的情景呢?這篇文章將教你怎樣實現AR場景的拍攝以及永久保存。
1、AR虛實融合場景圖層的分析


一個簡單的AR場景,在不論什么系統下的布局方式都不外乎上圖所看到的的類型。本文以在Android系統下的增強現實為例。


虛實融合場景圖層都是這樣的架構,GLSurfaceView用於繪制三維虛擬模型。SurfaceView是顯示真實場景視頻幀畫面,假設使用OpenCV進行圖像獲取的話,就使用SurfaceView的子類CameraBridgeViewBase。這些布局類的作用應該分的比較清楚。
2、場景獲取思路
首先因為真實場景的視頻幀畫面和三維虛擬模型不在同一個圖層上。我們須要分別獲取不同圖層上的圖像,再將它們轉換成位圖。最后拼合成一張位圖圖片就能夠了。可是傳統的拍照方式僅僅能獲取真實的場景,無法獲取OpenGL渲染的畫面。這里就是用傳統的方式獲取視頻圖像就可以。主要要解決GLSurfaceView上的三維模型。怎么樣將三維虛擬模型轉化成一張圖片?
3、視頻幀圖像的獲取
在Android系統中。
①使用Camera的情況:
參見這里的方法:Android拍照的兩種方式http://blog.csdn.net/napolun007/article/details/6103307
或者參見官網:http://developer.android.com/training/camera/photobasics.html
②使用OpenCV的情況:
使用OpenCV中的Utils.matToBitmap(Mat mat, Bitmap bmp),將獲取的視頻幀轉換成Bitmap就能夠了。
4、OpenGL渲染模型轉化成位圖
主要是將OpenGL繪制的圖像轉化成像素數據。了解下glReadPixels參數的含義:
void glReadPixels( GLint x, GLint y, GLsizei width,GLsizei height, GLenum format, GLenum type, GLvoid *pixels) ;
前面幾個參數指定讀取的位置尺寸以及格式, 最后一個參數用來返回結果, 所以像素數據自然是讀到pixels中。最后的方法代碼例如以下圖所看到的:
// 保存GL繪制的圖形 public static Bitmap saveGLBitmap(int width_surface, int height_surface) { // isSave = false; int w = width_surface; int h = height_surface; Log.i("hari", "w:" + w + "-----h:" + h); int b[] = new int[(int) (w * h)]; int bt[] = new int[(int) (w * h)]; IntBuffer buffer = IntBuffer.wrap(b); buffer.position(0); GLES20.glReadPixels(0, 0, w, h, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buffer); for (int i = 0; i < h; i++) { /** * 因為OpenGL與Android的Bitmap不兼容,這里須要進行一些校正 */ for (int j = 0; j < w; j++) { int pix = b[i * w + j]; int pb = (pix >> 16) & 0xff; int pr = (pix << 16) & 0x00ff0000; int pix1 = (pix & 0xff00ff00) | pr | pb; bt[(h - i - 1) * w + j] = pix1; } } Bitmap inBitmap = null; if (inBitmap == null || !inBitmap.isMutable() || inBitmap.getWidth() != w || inBitmap.getHeight() != h) { inBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); } // Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); inBitmap.copyPixelsFromBuffer(buffer); // return inBitmap ; // return Bitmap.createBitmap(bt, w, h, // Bitmap.Config.ARGB_8888); inBitmap = Bitmap.createBitmap(bt, w, h, Bitmap.Config.ARGB_8888); ByteArrayOutputStream bos = new ByteArrayOutputStream(); inBitmap.compress(CompressFormat.PNG, 90, bos); byte[] bitmapdata = bos.toByteArray(); ByteArrayInputStream fis = new ByteArrayInputStream(bitmapdata); // final Calendar c=Calendar.getInstance(); // long mytimestamp=c.getTimeInMillis(); // String timeStamp=String.valueOf(mytimestamp); // String myfile="hari"+timeStamp+".jpeg"; File dir_image = new File(Environment.getExternalStorageDirectory() + File.separator + "printerscreenshots"); dir_image.mkdirs(); try { File tmpFile = new File(dir_image + "/" + System.currentTimeMillis() + ".png"); FileOutputStream fos = new FileOutputStream(tmpFile); byte[] buf = new byte[1024]; int len; while ((len = fis.read(buf)) > 0) { fos.write(buf, 0, len); } fis.close(); fos.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return inBitmap; }
5、圖像的拼合
這個比較簡單,就是將兩個位圖拼合成一幅位圖,能夠使用Canvas畫圖板進行繪制。
public static Bitmap combineBitmap(Bitmap background, Bitmap foreground) { if (background == null) { return null; } int bgWidth = background.getWidth(); int bgHeight = background.getHeight(); int fgWidth = foreground.getWidth(); int fgHeight = foreground.getHeight(); Bitmap newmap = Bitmap .createBitmap(bgWidth, bgHeight, Config.ARGB_8888); Canvas canvas = new Canvas(newmap); canvas.drawBitmap(background, 0, 0, null); canvas.drawBitmap(foreground, (bgWidth - fgWidth) / 2, (bgHeight - fgHeight) / 2, null); canvas.save(Canvas.ALL_SAVE_FLAG); canvas.restore(); return newmap; }
6、增強現實場景圖像的保存
這個使用傳統的文件保存方法就可以。
展示幾幅我做出來的效果:



