1. Giriş
ARCore, mobil cihazlarda artırılmış gerçeklik (AR) uygulamaları oluşturmaya yönelik bir platformdur. Google'ın ARCore Depth API, ARCore oturumundaki her kare için derinlik görüntüsüne erişim sağlar. Derinlik görüntüsündeki her piksel, kameradan ortama olan mesafeyi ölçer.
Raw Depth API, sonuçları düzeltmek ve enterpolasyon yapmak için tasarlanmış ekran alanı filtreleme işlemlerinden geçirilmemiş derinlik görüntüleri sağlar. Bu değerler geometrik olarak daha doğrudur ancak eksik veriler içerebilir ve ilişkili kamera görüntüsüyle daha az uyumlu olabilir.
Bu codelab'de, sahnenin 3D geometri analizini yapmak için Raw Depth API'nin nasıl kullanılacağı gösterilmektedir. Dünyanın geometrisini algılamak ve görselleştirmek için ham derinlik verilerini kullanan basit bir AR özellikli uygulama oluşturacaksınız.
Derinlik ve Ham Derinlik API'leri yalnızca ARCore'un etkinleştirildiği cihazların bir alt kümesinde desteklenir. Depth API yalnızca Android'de kullanılabilir.
Ne oluşturacaksınız?
Bu codelab'de, çevrenizdeki dünyanın geometrik analizini yapmak için her karede ham derinlik görüntülerini kullanan bir uygulama oluşturacaksınız. Bu uygulama:
- Hedef cihazın Derinlik özelliğini destekleyip desteklemediğini kontrol edin.
- Her kamera karesi için ham derinlik görüntüsünü alın.
- Ham derinlik görüntülerini 3D noktalara yeniden yansıtın ve bu noktaları güvene ve geometriye göre filtreleyin.
- İlgili 3D nesneleri segmentlere ayırmak için ham derinlik nokta bulutunu kullanın.
|
Oluşturacağınız öğenin önizlemesi. |
Not: İşlemler sırasında sorun yaşarsanız sorun giderme ipuçları için son bölüme gidin.
2. Ön koşullar
Bu codelab'i tamamlamak için belirli donanım ve yazılımlara ihtiyacınız vardır.
Donanım gereksinimleri
- USB üzerinden hata ayıklama özelliği etkinleştirilmiş, USB kablosuyla geliştirme makinenize bağlı bir ARCore destekli cihaz. Bu cihazın Depth API'yi de desteklemesi gerekir.
Yazılım gereksinimleri
- ARCore SDK'sı 1.31.0 veya sonraki sürümler
- Android Studio'nun (4.0.1 veya sonraki sürümler) yüklü olduğu bir geliştirme makinesi.
3. Kur
Geliştirme makinesini ayarlama
ARCore cihazınızı USB kablosuyla bilgisayarınıza bağlayın. Cihazınızın USB üzerinden hata ayıklamaya izin verdiğinden emin olun. Bir terminal açıp aşağıdaki şekilde adb devices komutunu çalıştırın:
adb devices List of devices attached <DEVICE_SERIAL_NUMBER> device
<DEVICE_SERIAL_NUMBER>, cihazınıza özgü bir dize olur. Devam etmeden önce tam olarak bir cihaz gördüğünüzden emin olun.
Kodu indirip yükleme
Depoyu klonlayabilirsiniz:
git clone https://github.com/googlecodelabs/arcore-rawdepthapi
Alternatif olarak, bir ZIP dosyası indirip ayıklayabilirsiniz:
Kodla çalışmaya başlamak için aşağıdaki adımları uygulayın.
- Android Studio'yu başlatın ve Open an existing Android Studio project'i (Mevcut bir Android Studio projesini aç) seçin.
- Raw Depth ZIP dosyasını depoladığınız yerel dizine gidin.
arcore_rawdepthapi_codelabdizinini çift tıklayın.
arcore_rawdepthapi_codelab dizini, birden fazla modül içeren tek bir Gradle projesidir. Android Studio'nun sol üst kısmındaki Proje bölmesi henüz Proje bölmesinde gösterilmiyorsa açılır menüden Projeler'i tıklayın.
Sonuç şu şekilde görünmelidir:
| Bu proje aşağıdaki modülleri içerir:
|
part0_work modülünde çalışacaksınız. Ayrıca, codelab'in her bölümü için eksiksiz çözümler de vardır. Her modül, oluşturulabilir bir uygulamadır.
4. Başlangıç uygulamasını çalıştırma
Raw Depth başlangıç uygulamasını çalıştırmak için aşağıdaki adımları uygulayın.
- Çalıştır > Çalıştır...'a gidin. > ‘part0_work'.
- Select Deployment Target (Dağıtım Hedefini Seç) iletişim kutusunda, Connected Devices (Bağlı Cihazlar) listesinden cihazınızı seçip OK'u (Tamam) tıklayın.
Android Studio, ilk uygulamayı oluşturup cihazınızda çalıştırır.
| Uygulamayı ilk kez çalıştırdığınızda KAMERA izni istenir. Devam etmek için İzin ver'e dokunun. |
| Uygulama şu anda hiçbir şey yapmıyor. Bu, en temel AR uygulamasıdır. Sahnenizin kamera görünümünü gösterir ancak başka bir işlem yapmaz. Mevcut kod, ARCore SDK ile yayınlanan Hello AR örneğine benzer. |
Ardından, etrafınızdaki sahnenin geometrisini almak için Raw Depth API'yi kullanacaksınız.
5. Raw Depth API'yi ayarlama (1. Bölüm)
Hedef cihazın Derinlik özelliğini desteklediğinden emin olun.
ARCore'un desteklendiği cihazların tümünde Depth API çalıştırılamaz. Yeni bir oturumun oluşturulduğu RawDepthCodelabActivity.java işlevinin onResume() işlevine uygulamanızda işlev eklemeden önce hedef cihazın derinliği desteklediğinden emin olun.
Mevcut kodu bulun:
// Create the ARCore session.
session = new Session(/* context= */ this);
Uygulamanın yalnızca Depth API'yi destekleyebilen cihazlarda çalışmasını sağlamak için güncelleyin.
// Create the ARCore session.
session = new Session(/* context= */ this);
if (!session.isDepthModeSupported(Config.DepthMode.RAW_DEPTH_ONLY)) {
message =
"This device does not support the ARCore Raw Depth API. See" +
"https://developers.google.com/ar/devices for
a list of devices that do.";
}
Ham derinliği etkinleştirme
Raw Depth API, düzeltilmemiş bir derinlik görüntüsü ve ham derinlik görüntüsündeki her piksel için derinlik güvenini içeren karşılık gelen bir güven görüntüsü sağlar. Şimdi değiştirdiğiniz try-catch ifadesinin altındaki aşağıdaki kodu güncelleyerek Raw Depth'i etkinleştirin.
try {
// ************ New code to add ***************
// Enable raw depth estimation and auto focus mode while ARCore is running.
Config config = session.getConfig();
config.setDepthMode(Config.DepthMode.RAW_DEPTH_ONLY);
config.setFocusMode(Config.FocusMode.AUTO);
session.configure(config);
// ************ End new code to add ***************
session.resume();
} catch (CameraNotAvailableException e) {
messageSnackbarHelper.showError(this, "Camera not available. Try restarting the app.");
session = null;
return;
}
Artık AR oturumu uygun şekilde yapılandırıldı ve uygulama, derinliğe dayalı özellikleri kullanabilir.
Depth API'yi çağırma
Ardından, her kare için derinlik görüntülerini almak üzere Depth API'yi çağırın. Yeni bir dosya oluşturarak derinlik verilerini yeni bir sınıfa kapsülleyin. rawdepth klasörünü sağ tıklayın ve New > Java Class seçeneğini belirleyin. Bu işlem, boş bir dosya oluşturur. Bu sınıfa aşağıdakileri ekleyin:
src/main/java/com/google/ar/core/codelab/rawdepth/DepthData.java
package com.google.ar.core.codelab.rawdepth;
import android.media.Image;
import android.opengl.Matrix;
import com.google.ar.core.Anchor;
import com.google.ar.core.CameraIntrinsics;
import com.google.ar.core.Frame;
import com.google.ar.core.exceptions.NotYetAvailableException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
/**
* Convert depth data from ARCore depth images to 3D pointclouds. Points are added by calling the
* Raw Depth API, and reprojected into 3D space.
*/
public class DepthData {
public static final int FLOATS_PER_POINT = 4; // X,Y,Z,confidence.
}
Bu sınıf, derinlik görüntülerini nokta bulutlarına dönüştürmek için kullanılır. Nokta bulutları, her biri 3D koordinata (x, y, z) ve 0-1 aralığında bir güven değerine sahip olan bir nokta listesiyle sahne geometrisini temsil eder.
Sınıfın en altına bir create()yöntemi ekleyerek Raw Depth API'yi kullanarak bu değerleri dolduracak çağrılar ekleyin. Bu yöntemde, en son derinlik ve güven görüntüleri sorgulanır ve sonuçta elde edilen nokta bulutu depolanır. Derinlik ve güven görüntüleri eşleşen verilere sahip olur.
public static FloatBuffer create(Frame frame, Anchor cameraPoseAnchor) {
try {
Image depthImage = frame.acquireRawDepthImage16Bits();
Image confidenceImage = frame.acquireRawDepthConfidenceImage();
// Retrieve the intrinsic camera parameters corresponding to the depth image to
// transform 2D depth pixels into 3D points. See more information about the depth values
// at
// https://developers.google.com/ar/develop/java/depth/overview#understand-depth-values.
final CameraIntrinsics intrinsics = frame.getCamera().getTextureIntrinsics();
float[] modelMatrix = new float[16];
cameraPoseAnchor.getPose().toMatrix(modelMatrix, 0);
final FloatBuffer points = convertRawDepthImagesTo3dPointBuffer(
depthImage, confidenceImage, intrinsics, modelMatrix);
depthImage.close();
confidenceImage.close();
return points;
} catch (NotYetAvailableException e) {
// This normally means that depth data is not available yet.
// This is normal, so you don't have to spam the logcat with this.
}
return null;
}
|
|
|
|
|
|
|
|
Kod, bu sırada kamera tutturucuyu da depolar. Böylece, yardımcı bir yöntem convertRawDepthImagesTo3dPointBuffer() çağrılarak derinlik bilgileri dünya koordinatlarına dönüştürülebilir. Bu yardımcı yöntem, derinlik görüntüsündeki her pikseli alır ve derinliği kameraya göre 3D noktaya yansıtmak için kamera içsel parametrelerini kullanır. Ardından, noktanın konumunu dünya koordinatlarına dönüştürmek için kamera sabitleme noktası kullanılır. Mevcut her piksel, 3D noktaya (metre biriminde) dönüştürülür ve güven düzeyiyle birlikte depolanır.
DepthData.java dosyasına aşağıdaki yardımcı yöntemi ekleyin:
/** Apply camera intrinsics to convert depth image into a 3D pointcloud. */
private static FloatBuffer convertRawDepthImagesTo3dPointBuffer(
Image depth, Image confidence, CameraIntrinsics cameraTextureIntrinsics, float[] modelMatrix) {
// Java uses big endian so change the endianness to ensure
// that the depth data is in the correct byte order.
final Image.Plane depthImagePlane = depth.getPlanes()[0];
ByteBuffer depthByteBufferOriginal = depthImagePlane.getBuffer();
ByteBuffer depthByteBuffer = ByteBuffer.allocate(depthByteBufferOriginal.capacity());
depthByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
while (depthByteBufferOriginal.hasRemaining()) {
depthByteBuffer.put(depthByteBufferOriginal.get());
}
depthByteBuffer.rewind();
ShortBuffer depthBuffer = depthByteBuffer.asShortBuffer();
final Image.Plane confidenceImagePlane = confidence.getPlanes()[0];
ByteBuffer confidenceBufferOriginal = confidenceImagePlane.getBuffer();
ByteBuffer confidenceBuffer = ByteBuffer.allocate(confidenceBufferOriginal.capacity());
confidenceBuffer.order(ByteOrder.LITTLE_ENDIAN);
while (confidenceBufferOriginal.hasRemaining()) {
confidenceBuffer.put(confidenceBufferOriginal.get());
}
confidenceBuffer.rewind();
// To transform 2D depth pixels into 3D points, retrieve the intrinsic camera parameters
// corresponding to the depth image. See more information about the depth values at
// https://developers.google.com/ar/develop/java/depth/overview#understand-depth-values.
final int[] intrinsicsDimensions = cameraTextureIntrinsics.getImageDimensions();
final int depthWidth = depth.getWidth();
final int depthHeight = depth.getHeight();
final float fx =
cameraTextureIntrinsics.getFocalLength()[0] * depthWidth / intrinsicsDimensions[0];
final float fy =
cameraTextureIntrinsics.getFocalLength()[1] * depthHeight / intrinsicsDimensions[1];
final float cx =
cameraTextureIntrinsics.getPrincipalPoint()[0] * depthWidth / intrinsicsDimensions[0];
final float cy =
cameraTextureIntrinsics.getPrincipalPoint()[1] * depthHeight / intrinsicsDimensions[1];
// Allocate the destination point buffer. If the number of depth pixels is larger than
// `maxNumberOfPointsToRender` we uniformly subsample. The raw depth image may have
// different resolutions on different devices.
final float maxNumberOfPointsToRender = 20000;
int step = (int) Math.ceil(Math.sqrt(depthWidth * depthHeight / maxNumberOfPointsToRender));
FloatBuffer points = FloatBuffer.allocate(depthWidth / step * depthHeight / step * FLOATS_PER_POINT);
float[] pointCamera = new float[4];
float[] pointWorld = new float[4];
for (int y = 0; y < depthHeight; y += step) {
for (int x = 0; x < depthWidth; x += step) {
// Depth images are tightly packed, so it's OK to not use row and pixel strides.
int depthMillimeters = depthBuffer.get(y * depthWidth + x); // Depth image pixels are in mm.
if (depthMillimeters == 0) {
// Pixels with value zero are invalid, meaning depth estimates are missing from
// this location.
continue;
}
final float depthMeters = depthMillimeters / 1000.0f; // Depth image pixels are in mm.
// Retrieve the confidence value for this pixel.
final byte confidencePixelValue =
confidenceBuffer.get(
y * confidenceImagePlane.getRowStride()
+ x * confidenceImagePlane.getPixelStride());
final float confidenceNormalized = ((float) (confidencePixelValue & 0xff)) / 255.0f;
// Unproject the depth into a 3D point in camera coordinates.
pointCamera[0] = depthMeters * (x - cx) / fx;
pointCamera[1] = depthMeters * (cy - y) / fy;
pointCamera[2] = -depthMeters;
pointCamera[3] = 1;
// Apply model matrix to transform point into world coordinates.
Matrix.multiplyMV(pointWorld, 0, modelMatrix, 0, pointCamera, 0);
points.put(pointWorld[0]); // X.
points.put(pointWorld[1]); // Y.
points.put(pointWorld[2]); // Z.
points.put(confidenceNormalized);
}
}
points.rewind();
return points;
}
Her kare için en son Ham Derinlik verilerini alma
Uygulamayı, derinlik bilgilerini alacak ve her poz için dünya koordinatlarıyla eşleşecek şekilde değiştirin.
RawDepthCodelabActivity.java içinde, onDrawFrame() yönteminde mevcut satırları bulun:
Frame frame = session.update();
Camera camera = frame.getCamera();
// If the frame is ready, render the camera preview image to the GL surface.
backgroundRenderer.draw(frame);
Hemen altına aşağıdaki satırları ekleyin:
// Retrieve the depth data for this frame.
FloatBuffer points = DepthData.create(frame, session.createAnchor(camera.getPose()));
if (points == null) {
return;
}
if (messageSnackbarHelper.isShowing() && points != null) {
messageSnackbarHelper.hide(this);
}
6. Derinlik verilerini oluşturma (2. Bölüm)
Artık üzerinde çalışabileceğiniz bir derinlik nokta bulutunuz olduğuna göre, verilerin ekranda nasıl göründüğünü görme zamanı geldi.
Derinlik noktalarını görselleştirmek için oluşturucu ekleme
Derinlik noktalarını görselleştirmek için bir oluşturucu ekleyin.
İlk olarak, oluşturma mantığını içerecek yeni bir sınıf ekleyin. Bu sınıf, derinlik nokta bulutunu görselleştirmek için gölgelendiricileri başlatmak üzere OpenGL işlemlerini gerçekleştirir.
| DepthRenderer sınıfını ekleme
|
Bu sınıfı aşağıdaki kodla doldurun:
src/main/java/com/google/ar/core/codelab/common/rendering/DepthRenderer.java
package com.google.ar.core.codelab.common.rendering;
import android.content.Context;
import android.opengl.GLES20;
import android.opengl.Matrix;
import com.google.ar.core.Camera;
import com.google.ar.core.codelab.rawdepth.DepthData;
import java.io.IOException;
import java.nio.FloatBuffer;
public class DepthRenderer {
private static final String TAG = DepthRenderer.class.getSimpleName();
// Shader names.
private static final String VERTEX_SHADER_NAME = "shaders/depth_point_cloud.vert";
private static final String FRAGMENT_SHADER_NAME = "shaders/depth_point_cloud.frag";
public static final int BYTES_PER_FLOAT = Float.SIZE / 8;
private static final int BYTES_PER_POINT = BYTES_PER_FLOAT * DepthData.FLOATS_PER_POINT;
private static final int INITIAL_BUFFER_POINTS = 1000;
private int arrayBuffer;
private int arrayBufferSize;
private int programName;
private int positionAttribute;
private int modelViewProjectionUniform;
private int pointSizeUniform;
private int numPoints = 0;
public DepthRenderer() {}
public void createOnGlThread(Context context) throws IOException {
ShaderUtil.checkGLError(TAG, "Bind");
int[] buffers = new int[1];
GLES20.glGenBuffers(1, buffers, 0);
arrayBuffer = buffers[0];
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, arrayBuffer);
arrayBufferSize = INITIAL_BUFFER_POINTS * BYTES_PER_POINT;
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, arrayBufferSize, null, GLES20.GL_DYNAMIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
ShaderUtil.checkGLError(TAG, "Create");
int vertexShader =
ShaderUtil.loadGLShader(TAG, context, GLES20.GL_VERTEX_SHADER, VERTEX_SHADER_NAME);
int fragmentShader =
ShaderUtil.loadGLShader(TAG, context, GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER_NAME);
programName = GLES20.glCreateProgram();
GLES20.glAttachShader(programName, vertexShader);
GLES20.glAttachShader(programName, fragmentShader);
GLES20.glLinkProgram(programName);
GLES20.glUseProgram(programName);
ShaderUtil.checkGLError(TAG, "Program");
positionAttribute = GLES20.glGetAttribLocation(programName, "a_Position");
modelViewProjectionUniform = GLES20.glGetUniformLocation(programName, "u_ModelViewProjection");
// Sets the point size, in pixels.
pointSizeUniform = GLES20.glGetUniformLocation(programName, "u_PointSize");
ShaderUtil.checkGLError(TAG, "Init complete");
}
}
Derinlik verilerini oluşturma
Ardından, oluşturma gölgelendiricilerinin kaynağını belirtin. Aşağıdaki update()yöntemini DepthRenderer sınıfının en altına ekleyin. Bu yöntemde, en son derinlik bilgileri giriş olarak alınır ve nokta bulutu verileri GPU'ya kopyalanır.
/**
* Update the OpenGL buffer contents to the provided point. Repeated calls with the same point
* cloud will be ignored.
*/
public void update(FloatBuffer points) {
ShaderUtil.checkGLError(TAG, "Update");
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, arrayBuffer);
// If the array buffer is not large enough to fit the new point cloud, resize it.
points.rewind();
numPoints = points.remaining() / DepthData.FLOATS_PER_POINT;
if (numPoints * BYTES_PER_POINT > arrayBufferSize) {
while (numPoints * BYTES_PER_POINT > arrayBufferSize) {
arrayBufferSize *= 2;
}
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, arrayBufferSize, null, GLES20.GL_DYNAMIC_DRAW);
}
GLES20.glBufferSubData(
GLES20.GL_ARRAY_BUFFER, 0, numPoints * BYTES_PER_POINT, points);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
ShaderUtil.checkGLError(TAG, "Update complete");
}
DepthRenderer sınıfının en altına bir draw() yöntemi ekleyerek en son verileri ekrana çizin. Bu yöntemde, 3D nokta bulutu bilgileri alınır ve ekranda oluşturulabilmesi için kamera görünümüne geri yansıtılır.
/** Render the point cloud. The ARCore point cloud is given in world space. */
public void draw(Camera camera) {
float[] projectionMatrix = new float[16];
camera.getProjectionMatrix(projectionMatrix, 0, 0.1f, 100.0f);
float[] viewMatrix = new float[16];
camera.getViewMatrix(viewMatrix, 0);
float[] viewProjection = new float[16];
Matrix.multiplyMM(viewProjection, 0, projectionMatrix, 0, viewMatrix, 0);
ShaderUtil.checkGLError(TAG, "Draw");
GLES20.glUseProgram(programName);
GLES20.glEnableVertexAttribArray(positionAttribute);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, arrayBuffer);
GLES20.glVertexAttribPointer(positionAttribute, 4, GLES20.GL_FLOAT, false, BYTES_PER_POINT, 0);
GLES20.glUniformMatrix4fv(modelViewProjectionUniform, 1, false, viewProjection, 0);
// Set point size to 5 pixels.
GLES20.glUniform1f(pointSizeUniform, 5.0f);
GLES20.glDrawArrays(GLES20.GL_POINTS, 0, numPoints);
GLES20.glDisableVertexAttribArray(positionAttribute);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
ShaderUtil.checkGLError(TAG, "Draw complete");
}
pointSizeUniform değişkenini kullanarak nokta boyutunu piksel cinsinden farklı boyutlara ayarlayabilirsiniz. Örnek uygulamada pointSizeUniform 5 piksel olarak ayarlanmıştır.
Yeni gölgelendiriciler ekleme
Uygulamanızda derinliği görüntülemenin ve derinlik verilerini göstermenin birçok yolu vardır. Burada birkaç gölgelendirici ekleyip basit bir renk eşleme görselleştirmesi oluşturacaksınız.
src/main/assets/shaders/ dizinine yeni .vert ve .frag gölgelendiricileri ekleyin.
| Yeni .vert gölgelendirici eklemeAndroid Studio'da:
|
Yeni .vert dosyasına aşağıdaki kodu ekleyin:
src/main/assets/shaders/depth_point_cloud.vert
uniform mat4 u_ModelViewProjection;
uniform float u_PointSize;
attribute vec4 a_Position;
varying vec4 v_Color;
// Return an interpolated color in a 6 degree polynomial interpolation.
vec3 GetPolynomialColor(in float x,
in vec4 kRedVec4, in vec4 kGreenVec4, in vec4 kBlueVec4,
in vec2 kRedVec2, in vec2 kGreenVec2, in vec2 kBlueVec2) {
// Moves the color space a little bit to avoid pure red.
// Removes this line for more contrast.
x = clamp(x * 0.9 + 0.03, 0.0, 1.0);
vec4 v4 = vec4(1.0, x, x * x, x * x * x);
vec2 v2 = v4.zw * v4.z;
return vec3(
dot(v4, kRedVec4) + dot(v2, kRedVec2),
dot(v4, kGreenVec4) + dot(v2, kGreenVec2),
dot(v4, kBlueVec4) + dot(v2, kBlueVec2)
);
}
// Return a smooth Percept colormap based upon the Turbo colormap.
vec3 PerceptColormap(in float x) {
const vec4 kRedVec4 = vec4(0.55305649, 3.00913185, -5.46192616, -11.11819092);
const vec4 kGreenVec4 = vec4(0.16207513, 0.17712472, 15.24091500, -36.50657960);
const vec4 kBlueVec4 = vec4(-0.05195877, 5.18000081, -30.94853351, 81.96403246);
const vec2 kRedVec2 = vec2(27.81927491, -14.87899417);
const vec2 kGreenVec2 = vec2(25.95549545, -5.02738237);
const vec2 kBlueVec2 = vec2(-86.53476570, 30.23299484);
const float kInvalidDepthThreshold = 0.01;
return step(kInvalidDepthThreshold, x) *
GetPolynomialColor(x, kRedVec4, kGreenVec4, kBlueVec4,
kRedVec2, kGreenVec2, kBlueVec2);
}
void main() {
// Color the pointcloud by height.
float kMinHeightMeters = -2.0f;
float kMaxHeightMeters = 2.0f;
float normalizedHeight = clamp((a_Position.y - kMinHeightMeters) / (kMaxHeightMeters - kMinHeightMeters), 0.0, 1.0);
v_Color = vec4(PerceptColormap(normalizedHeight), 1.0);
gl_Position = u_ModelViewProjection * vec4(a_Position.xyz, 1.0);
gl_PointSize = u_PointSize;
}
Bu gölgelendirici, daha iyi görselleştirme için Turbo renk haritasını kullanır. Aşağıdaki adımları gerçekleştirir:
- Her noktanın yüksekliğini (dünya koordinatlarındaki y ekseni) alır.
- Bu yüksekliğe karşılık gelen bir renk hesaplar (kırmızı=düşük, mavi=yüksek).
- Her noktanın ekran konumunu hesaplar.
DepthRenderer.update()yönteminde tanımlandığı şekilde her noktanın boyutunu (piksel cinsinden) ayarlar.
Aynı dizinde bir parça gölgelendirici oluşturun ve bu bölümdeki adımları tekrarlayarak depth_point_cloud.frag olarak adlandırın.
Ardından, her noktayı köşe gölgelendiricide tanımlandığı gibi tek bir tek renkli köşe olarak oluşturmak için bu yeni dosyaya aşağıdaki kodu ekleyin.
src/main/assets/shaders/depth_point_cloud.frag
precision mediump float;
varying vec4 v_Color;
void main() {
gl_FragColor = v_Color;
}
Bu oluşturmayı uygulamak için RawDepthCodelabActivity içindeki DepthRenderer sınıfına çağrı ekleyin.
src/main/java/com/google/ar/core/codelab/common/rendering/RawDepthCodelabActivity.java
import com.google.ar.core.codelab.common.rendering.DepthRenderer;
Sınıfın üst kısmında, backgroundRenderer simgesinin yanına özel bir üye ekleyin.
private final DepthRenderer depthRenderer = new DepthRenderer();
depthRenderer, mevcut backgroundRenderer gibi RawDepthCodelabActivity.onSurfaceCreated() içinde başlatılmalıdır.
depthRenderer.createOnGlThread(/*context=*/ this);
Mevcut karenin en son derinliğini göstermek için onDrawFrame içindeki try-catch bloğunun sonuna aşağıdaki kodu ekleyin.
// Visualize depth points.
depthRenderer.update(points);
depthRenderer.draw(camera);
Bu değişikliklerle birlikte uygulama artık başarıyla oluşturulmalı ve derinlik nokta bulutunu göstermelidir.
| Örnek ham derinlik noktası bulutu görselleştirme
|
7. 3B nokta bulutlarını analiz etme (3. bölüm)
Bir AR oturumunda derinlik verilerinin bulunduğunu doğruladıktan sonra bu verileri analiz edebilirsiniz. Derinliği analiz etmek için önemli bir araç, her pikselin güven değeridir. 3D nokta bulutlarını analiz etmek için güven değerlerini kullanın.
Düşük güven düzeyine sahip pikselleri geçersiz kılma
Her derinlik pikseli için güven değerini aldınız ve DepthData içindeki her noktanın yanına kaydettiniz ancak henüz kullanmadınız.
confidenceNormalized değerleri 0 ile 1 arasında değişir. 0 değeri düşük güveni, 1 değeri ise tam güveni gösterir. convertRawDepthImagesTo3dPointBuffer() yöntemini DepthData sınıfında değiştirerek güven düzeyi, kullanılabilecek kadar yüksek olmayan piksellerin kaydedilmesini önleyin.
final float confidenceNormalized = ((float) (confidencePixelValue & 0xff)) / 255.0f;
// ******** New code to add ************
if (confidenceNormalized < 0.3) {
// Ignores "low-confidence" pixels.
continue;
}
// ******** End of new code to add *********
Her seviyede kaç derinlik noktasının korunduğunu görmek için güven seviyesiyle ilgili farklı eşikler deneyin.
|
|
|
|
|
Güven >= 0,1 | Güven >= 0,3 | Güven >= 0,5 | Güven >= 0,7 | Güven >= 0,9 |
Pikselleri mesafeye göre filtreleme
Derinlik piksellerini mesafeye göre de filtreleyebilirsiniz. Sonraki adımlar, kameraya yakın geometriyle ilgilidir. Performans optimizasyonu için çok uzakta olan noktaları yoksayabilirsiniz.
Yeni eklediğiniz güven kontrolü kodunu aşağıdaki şekilde güncelleyin:
src/main/java/com/google/ar/core/codelab/rawdepth/DepthData.java
if (confidenceNormalized < 0.3 || depthMeters > 1.5) {
// Ignore "low-confidence" pixels or depth that is too far away.
continue;
}
Artık yalnızca yüksek güvenilirlik düzeyine sahip ve yakın noktaları görürsünüz.
| Uzaklık filtresiNokta bulutunun kameradan 1,5 metre uzaklıkta olmasını sağlar. |
3D noktaları ve düzlemleri karşılaştırma
Geometri 3D noktalarını ve düzlemlerini karşılaştırabilir, bunları birbirini filtrelemek için kullanabilirsiniz (ör. gözlemlenen AR düzlemlerine yakın noktaları kaldırma).
Bu adımda, yalnızca ortamdaki nesnelerin yüzeylerini temsil etme eğiliminde olan "düzlemsel olmayan" noktalar kalır. filterUsingPlanes() yöntemini DepthData sınıfının en altına ekleyin. Bu yöntemde mevcut noktalar arasında yineleme yapılır, her nokta her düzleme göre kontrol edilir ve bir AR düzlemine çok yakın olan noktalar geçersiz kılınır. Böylece, sahnedeki nesneleri vurgulayan düzlemsel olmayan alanlar bırakılır.
src/main/java/com/google/ar/core/codelab/rawdepth/DepthData.java
public static void filterUsingPlanes(FloatBuffer points, Collection<Plane> allPlanes) {
float[] planeNormal = new float[3];
// Allocate the output buffer.
int numPoints = points.remaining() / DepthData.FLOATS_PER_POINT;
// Check each plane against each point.
for (Plane plane : allPlanes) {
if (plane.getTrackingState() != TrackingState.TRACKING || plane.getSubsumedBy() != null) {
continue;
}
// Compute the normal vector of the plane.
Pose planePose = plane.getCenterPose();
planePose.getTransformedAxis(1, 1.0f, planeNormal, 0);
// Filter points that are too close to the plane.
for (int index = 0; index < numPoints; ++index) {
// Retrieves the next point.
final float x = points.get(FLOATS_PER_POINT * index);
final float y = points.get(FLOATS_PER_POINT * index + 1);
final float z = points.get(FLOATS_PER_POINT * index + 2);
// Transform point to be in world coordinates, to match plane info.
float distance = (x - planePose.tx()) * planeNormal[0]
+ (y - planePose.ty()) * planeNormal[1]
+ (z - planePose.tz()) * planeNormal[2];
// Controls the size of objects detected.
// Smaller values mean smaller objects will be kept.
// Larger values will only allow detection of larger objects, but also helps reduce noise.
if (Math.abs(distance) > 0.03) {
continue; // Keep this point, since it's far enough away from the plane.
}
// Invalidate points that are too close to planar surfaces.
points.put(FLOATS_PER_POINT * index, 0);
points.put(FLOATS_PER_POINT * index + 1, 0);
points.put(FLOATS_PER_POINT * index + 2, 0);
points.put(FLOATS_PER_POINT * index + 3, 0);
}
}
}
Bu yöntemi onDrawFrame yöntemindeki RawDepthCodelabActivity öğesine ekleyebilirsiniz:
// ********** New code to add ************
// Filter the depth data.
DepthData.filterUsingPlanes(points, session.getAllTrackables(Plane.class));
// ********** End new code to add *******
// Visualize depth points.
depthRenderer.update(points);
depthRenderer.draw(camera);
Codelab'i çalıştırdığınızda artık puanların bir alt kümesi oluşturuluyor. Bu noktalar, nesnelerin üzerinde durduğu düz yüzeyleri yoksayarak sahnedeki nesneleri temsil eder. Bu verileri kullanarak noktaları birlikte kümeleyerek nesnelerin boyutunu ve konumunu tahmin edebilirsiniz.
|
|
|
|
Çay Fincanı | Mikrofon | Kulaklık | Yastık |
Küme noktaları
Bu codelab'de çok basit bir nokta bulutu kümeleme algoritması yer almaktadır. Alınan nokta bulutlarını eksenle hizalı sınırlayıcı kutularla tanımlanan kümeler halinde gruplandırmak için codelab'i güncelleyin.
src/main/java/com/google/ar/core/codelab/rawdepth/RawDepthCodelabActivity.java
import com.google.ar.core.codelab.common.helpers.AABB;
import com.google.ar.core.codelab.common.helpers.PointClusteringHelper;
import com.google.ar.core.codelab.common.rendering.BoxRenderer;
import java.util.List;
Dosyanın en üst kısmına, diğer oluşturucularla birlikte bu sınıfa bir BoxRenderer ekleyin.
private final BoxRenderer boxRenderer = new BoxRenderer();
Ayrıca onSurfaceCreated() yönteminin içine diğer oluşturucuların yanına aşağıdakileri ekleyin:
boxRenderer.createOnGlThread(/*context=*/this);
Son olarak, alınan nokta bulutlarını kümeler hâlinde gruplandırmak ve sonuçları eksenle hizalı sınırlayıcı kutular olarak oluşturmak için onDrawFrame() içindeki RawDepthCodelabActivity bölümüne aşağıdaki satırları ekleyin.
// Visualize depth points.
depthRenderer.update(points);
depthRenderer.draw(camera);
// ************ New code to add ***************
// Draw boxes around clusters of points.
PointClusteringHelper clusteringHelper = new PointClusteringHelper(points);
List<AABB> clusters = clusteringHelper.findClusters();
for (AABB aabb : clusters) {
boxRenderer.draw(aabb, camera);
}
// ************ End new code to add ***************
|
|
|
|
Çay Fincanı | Mikrofon | Kulaklık | Yastık |
Artık bir ARCore oturumu aracılığıyla ham derinliği alabilir, derinlik bilgilerini 3D nokta bulutlarına dönüştürebilir ve bu noktalarda temel filtreleme ve oluşturma işlemleri gerçekleştirebilirsiniz.
8. Geliştirme-Çalıştırma-Test Etme
Uygulamanızı oluşturun, çalıştırın ve test edin.
Uygulamanızı derleyip çalıştırma
Uygulamanızı oluşturup çalıştırmak için aşağıdaki adımları uygulayın:
- ARCore destekli bir cihazı USB ile bağlayın.
- Projenizi menü çubuğundaki ► düğmesiyle çalıştırın.
- Uygulamanın oluşturulup cihazınıza dağıtılmasını bekleyin.
Uygulamayı cihazınıza ilk kez dağıtmaya çalıştığınızda
USB üzerinden hata ayıklamaya izin ver
cihazda. Devam etmek için Tamam'ı seçin.
Uygulamanızı cihazda ilk kez çalıştırdığınızda, uygulamanın cihazınızın kamerasını kullanma izni olup olmadığı sorulur. AR işlevini kullanmaya devam etmek için erişime izin vermeniz gerekir.
Uygulamanızı test etme
Uygulamanızı çalıştırdığınızda cihazınızı tutarak, bulunduğunuz alanda hareket ederek ve bir alanı yavaşça tarayarak uygulamanızın temel davranışını test edebilirsiniz. Bir sonraki adıma geçmeden önce en az 10 saniyelik veri toplamaya çalışın ve alanı birkaç yönden tarayın.
9. Tebrikler
Tebrikler, Google'ın ARCore Raw Depth API'sini kullanarak ilk derinliğe dayalı artırılmış gerçeklik uygulamanızı başarıyla oluşturup çalıştırdınız. Neler geliştireceğinizi görmek için sabırsızlanıyoruz.
10. Sorun giderme
Android cihazınızı geliştirme için ayarlama
- Cihazınızı bir USB kablosuyla geliştirme makinenize bağlayın. Windows kullanarak geliştirme yapıyorsanız cihazınız için uygun USB sürücüsünü yüklemeniz gerekebilir.
- Geliştirici seçenekleri penceresinde USB üzerinden hata ayıklama'yı etkinleştirmek için aşağıdaki adımları uygulayın:
- Ayarlar uygulamasını açın.
- Cihazınızda Android 8.0 veya sonraki bir sürüm yüklüyse Sistem'i seçin.
- En alta kaydırıp Telefon hakkında'yı seçin.
- En alta kaydırın ve Derleme numarası'na yedi kez dokunun.
- Önceki ekrana dönün, en alta kaydırın ve Geliştirici seçenekleri'ne dokunun.
- Geliştirici seçenekleri penceresinde aşağı kaydırarak USB üzerinden hata ayıklama'yı bulun ve etkinleştirin.
Bu süreçle ilgili daha ayrıntılı bilgiyi Google'ın Android geliştirici web sitesinde bulabilirsiniz.
Lisanslarla ilgili derleme hataları
Lisanslarla ilgili bir derleme hatasıyla (Failed to install the following Android SDK packages as some licences have not been accepted) karşılaşırsanız bu lisansları incelemek ve kabul etmek için aşağıdaki komutları kullanabilirsiniz:
cd <path to Android SDK>
tools/bin/sdkmanager --licenses

























