Android'de ML Kit ile pozları algılama

ML Kit, poz algılama için iki optimize edilmiş SDK sağlar.

SDK Adıpoz-algılamapose-detection-accurate
UygulamaKod ve öğeler, derleme sırasında statik olarak uygulamanıza bağlıdır.Kod ve öğeler, derleme sırasında uygulamanıza statik olarak bağlanır.
Uygulama boyutuna etkisi (kod ve öğeler dahil)~10,1 MB~13,3 MB
PerformansPixel 3XL: ~30 FPSPixel 3XL: CPU ile ~23FPS, GPU ile ~30FPS

Deneyin

Başlamadan önce

  1. Proje düzeyindeki build.gradle dosyanıza, hem buildscript hem de allprojects bölümlerinize Google'ın Maven deposunu eklediğinizden emin olun.
  2. ML Kit Android kitaplıklarının bağımlılıkları, modülünüzün uygulama düzeyindeki Gradle dosyasına (genellikle app/build.gradle) eklenmelidir:

    dependencies {
      // If you want to use the base sdk
      implementation 'com.google.mlkit:pose-detection:18.0.0-beta5'
      // If you want to use the accurate sdk
      implementation 'com.google.mlkit:pose-detection-accurate:18.0.0-beta5'
    }
    

1. PoseDetector örneği oluşturun

PoseDetector seçenek

Bir resimdeki pozu algılamak için önce PoseDetector örneği oluşturun ve isteğe bağlı olarak algılayıcı ayarlarını belirtin.

Algılama modu

PoseDetector, iki algılama modunda çalışır. Eşleşen etiketi seçtiğinizden emin olun ne kadar iyi karşıladığını görebileceksiniz.

STREAM_MODE (varsayılan)
Poz dedektörü öncelikle en fazla hareketi algılar ve ardından poz algılama özelliğini çalıştırın. Sonraki karelerde kişi algılama adımını, artık yüksek güvenilirlikle algılanmaz. Poz algılayıcı, en belirgin kişiyi izlemeye çalışır ve her çıkarım için kişinin pozunu döndürür. Bu, gecikmeyi azaltır ve algılamayı kolaylaştırır. Bir video akışındaki pozu algılamak istediğinizde bu modu kullanın.
SINGLE_IMAGE_MODE
Duruş algılayıcı, bir kişiyi algılar ve ardından duruş algılama işlemini başlatır. Kişi algılama adımı her görüntü için uygulanır. Bu nedenle gecikme daha yüksek olduğunu fark edeceksiniz. Statik resimlerde veya izlemenin istenmediği durumlarda poz algılama özelliğini kullanırken bu modu kullanın.

Donanım yapılandırması

PoseDetector, performansı optimize etmek için birden fazla donanım yapılandırmasını destekler:

  • CPU: Algılayıcıyı yalnızca CPU kullanarak çalıştırır.
  • CPU_GPU: Hem CPU hem de GPU'yu kullanarak dedektörü çalıştırın

Algılayıcı seçeneklerini oluştururken donanım seçimini kontrol etmek için API'yi setPreferredHardwareConfigs kullanabilirsiniz. Varsayılan olarak tüm donanım yapılandırmaları tercih edilen şekilde ayarlanır.

ML Kit, her yapılandırmanın kullanılabilirliğini, kararlılığını, doğruluğunu ve gecikmesini dikkate alarak tercih edilen yapılandırmalar arasından en iyisini seçer. Tercih edilen yapılandırmalardan hiçbiri geçerli değilse yedek olarak CPU yapılandırması otomatik olarak kullanılır. Makine Öğrenimi Kiti, bu kontrolleri ve ilgili hazırlığı herhangi bir hızlandırmayı etkinleştirmeden önce bunu engellemeyen bir yol olduğundan büyük olasılıkla kullanıcınız algılayıcıyı ilk kez çalıştırdığında CPU kullanır. Tüm bu nedenlerden sonra hazırlaması biterse sonraki çalıştırmalarda en iyi yapılandırma kullanılır.

setPreferredHardwareConfigs'ün örnek kullanımları:

  • ML Kit'in en iyi yapılandırmayı seçmesine izin vermek için bu API'yi çağırmayın.
  • Hızlandırmayı etkinleştirmek istemiyorsanız yalnızca CPU parametresini iletin.
  • GPU daha yavaş olsa bile CPU'dan yük almak için GPU'yu kullanmak istiyorsanız yalnızca CPU_GPU parametresini iletin.

Poz algılayıcı seçeneklerini belirtin:

Kotlin

// Base pose detector with streaming frames, when depending on the pose-detection sdk
val options = PoseDetectorOptions.Builder()
    .setDetectorMode(PoseDetectorOptions.STREAM_MODE)
    .build()

// Accurate pose detector on static images, when depending on the pose-detection-accurate sdk
val options = AccuratePoseDetectorOptions.Builder()
    .setDetectorMode(AccuratePoseDetectorOptions.SINGLE_IMAGE_MODE)
    .build()

Java

// Base pose detector with streaming frames, when depending on the pose-detection sdk
PoseDetectorOptions options =
   new PoseDetectorOptions.Builder()
       .setDetectorMode(PoseDetectorOptions.STREAM_MODE)
       .build();

// Accurate pose detector on static images, when depending on the pose-detection-accurate sdk
AccuratePoseDetectorOptions options =
   new AccuratePoseDetectorOptions.Builder()
       .setDetectorMode(AccuratePoseDetectorOptions.SINGLE_IMAGE_MODE)
       .build();

Son olarak, PoseDetector öğesinin bir örneğini oluşturun. Belirttiğiniz seçenekleri iletin:

Kotlin

val poseDetector = PoseDetection.getClient(options)

Java

PoseDetector poseDetector = PoseDetection.getClient(options);

2. Giriş resmini hazırlama

Bir resimdeki pozları algılamak için cihazdaki bir Bitmap, media.Image, ByteBuffer, bayt dizisi veya dosyadan InputImage nesnesi oluşturun. Ardından InputImage nesnesini PoseDetector nesnesine aktarın.

Poz algılama için en az 480x360 piksel boyutunda bir resim kullanmanız gerekir. Pozları gerçek zamanlı olarak algılıyorsanız kareleri bu minimum çözünürlükte yakalamak gecikmeyi azaltmaya yardımcı olabilir.

Farklı kaynaklardan InputImage nesnesi oluşturabilirsiniz. Bunların her biri aşağıda açıklanmıştır.

media.Image kullanma

InputImage oluşturmak için media.Image nesnesinden bir nesneden (örneğin, cihazın kamerasını, media.Image nesnesini ve resmin döndürme değeri InputImage.fromMediaImage() değerine ayarlanır.

CameraX kitaplığını kullanıyorsanız OnImageCapturedListener ve ImageAnalysis.Analyzer sınıfları rotasyon değerini sizin için hesaplar.

Kotlin

private class YourImageAnalyzer : ImageAnalysis.Analyzer {

    override fun analyze(imageProxy: ImageProxy) {
        val mediaImage = imageProxy.image
        if (mediaImage != null) {
            val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
            // Pass image to an ML Kit Vision API
            // ...
        }
    }
}

Java

private class YourAnalyzer implements ImageAnalysis.Analyzer {

    @Override
    public void analyze(ImageProxy imageProxy) {
        Image mediaImage = imageProxy.getImage();
        if (mediaImage != null) {
          InputImage image =
                InputImage.fromMediaImage(mediaImage, imageProxy.getImageInfo().getRotationDegrees());
          // Pass image to an ML Kit Vision API
          // ...
        }
    }
}

Resmin dönme derecesini sağlayan bir kamera kitaplığı kullanmıyorsanız cihazın dönüş derecesinden ve kameranın yönünden hesaplayabilir cihazdaki sensör:

Kotlin

private val ORIENTATIONS = SparseIntArray()

init {
    ORIENTATIONS.append(Surface.ROTATION_0, 0)
    ORIENTATIONS.append(Surface.ROTATION_90, 90)
    ORIENTATIONS.append(Surface.ROTATION_180, 180)
    ORIENTATIONS.append(Surface.ROTATION_270, 270)
}

/**
 * Get the angle by which an image must be rotated given the device's current
 * orientation.
 */
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Throws(CameraAccessException::class)
private fun getRotationCompensation(cameraId: String, activity: Activity, isFrontFacing: Boolean): Int {
    // Get the device's current rotation relative to its "native" orientation.
    // Then, from the ORIENTATIONS table, look up the angle the image must be
    // rotated to compensate for the device's rotation.
    val deviceRotation = activity.windowManager.defaultDisplay.rotation
    var rotationCompensation = ORIENTATIONS.get(deviceRotation)

    // Get the device's sensor orientation.
    val cameraManager = activity.getSystemService(CAMERA_SERVICE) as CameraManager
    val sensorOrientation = cameraManager
            .getCameraCharacteristics(cameraId)
            .get(CameraCharacteristics.SENSOR_ORIENTATION)!!

    if (isFrontFacing) {
        rotationCompensation = (sensorOrientation + rotationCompensation) % 360
    } else { // back-facing
        rotationCompensation = (sensorOrientation - rotationCompensation + 360) % 360
    }
    return rotationCompensation
}

Java

private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
static {
    ORIENTATIONS.append(Surface.ROTATION_0, 0);
    ORIENTATIONS.append(Surface.ROTATION_90, 90);
    ORIENTATIONS.append(Surface.ROTATION_180, 180);
    ORIENTATIONS.append(Surface.ROTATION_270, 270);
}

/**
 * Get the angle by which an image must be rotated given the device's current
 * orientation.
 */
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private int getRotationCompensation(String cameraId, Activity activity, boolean isFrontFacing)
        throws CameraAccessException {
    // Get the device's current rotation relative to its "native" orientation.
    // Then, from the ORIENTATIONS table, look up the angle the image must be
    // rotated to compensate for the device's rotation.
    int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
    int rotationCompensation = ORIENTATIONS.get(deviceRotation);

    // Get the device's sensor orientation.
    CameraManager cameraManager = (CameraManager) activity.getSystemService(CAMERA_SERVICE);
    int sensorOrientation = cameraManager
            .getCameraCharacteristics(cameraId)
            .get(CameraCharacteristics.SENSOR_ORIENTATION);

    if (isFrontFacing) {
        rotationCompensation = (sensorOrientation + rotationCompensation) % 360;
    } else { // back-facing
        rotationCompensation = (sensorOrientation - rotationCompensation + 360) % 360;
    }
    return rotationCompensation;
}

Ardından, media.Image nesnesini ve döndürme derecesi değerini InputImage.fromMediaImage() değerine ayarlayın:

Kotlin

val image = InputImage.fromMediaImage(mediaImage, rotation)

Java

InputImage image = InputImage.fromMediaImage(mediaImage, rotation);

Dosya URI'si kullanarak

Dosya URI'sinden InputImage nesnesi oluşturmak için uygulama bağlamını ve dosya URI'sini InputImage.fromFilePath()'a iletin. Bu özellik, kullanıcıdan seçim yapmasını istemek için bir ACTION_GET_CONTENT niyeti kullanın galeri uygulamasından bir resim.

Kotlin

val image: InputImage
try {
    image = InputImage.fromFilePath(context, uri)
} catch (e: IOException) {
    e.printStackTrace()
}

Java

InputImage image;
try {
    image = InputImage.fromFilePath(context, uri);
} catch (IOException e) {
    e.printStackTrace();
}

ByteBuffer veya ByteArray kullanma

InputImage oluşturmak için bir ByteBuffer veya ByteArray nesnesinden alıp almayacaksanız önce resmi hesaplayın media.Image girişi için daha önce açıklandığı gibi dönme derecesi. Ardından, arabellek veya diziyle InputImage nesnesini, bu resmin yükseklik, genişlik, renk kodlama biçimi ve döndürme derecesi:

Kotlin

val image = InputImage.fromByteBuffer(
        byteBuffer,
        /* image width */ 480,
        /* image height */ 360,
        rotationDegrees,
        InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12
)
// Or:
val image = InputImage.fromByteArray(
        byteArray,
        /* image width */ 480,
        /* image height */ 360,
        rotationDegrees,
        InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12
)

Java

InputImage image = InputImage.fromByteBuffer(byteBuffer,
        /* image width */ 480,
        /* image height */ 360,
        rotationDegrees,
        InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12
);
// Or:
InputImage image = InputImage.fromByteArray(
        byteArray,
        /* image width */480,
        /* image height */360,
        rotation,
        InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12
);

Bitmap kullanma

Bir Bitmap nesnesinden InputImage nesnesi oluşturmak için aşağıdaki beyanı yapın:

Kotlin

val image = InputImage.fromBitmap(bitmap, 0)

Java

InputImage image = InputImage.fromBitmap(bitmap, rotationDegree);

Resim, döndürme dereceleriyle birlikte bir Bitmap nesnesi ile temsil edilir.

3. Resmi işleme

Hazırlanan InputImage nesnesini PoseDetector öğesinin process yöntemine iletin.

Kotlin

Task<Pose> result = poseDetector.process(image)
       .addOnSuccessListener { results ->
           // Task completed successfully
           // ...
       }
       .addOnFailureListener { e ->
           // Task failed with an exception
           // ...
       }

Java

Task<Pose> result =
        poseDetector.process(image)
                .addOnSuccessListener(
                        new OnSuccessListener<Pose>() {
                            @Override
                            public void onSuccess(Pose pose) {
                                // Task completed successfully
                                // ...
                            }
                        })
                .addOnFailureListener(
                        new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                // Task failed with an exception
                                // ...
                            }
                        });

4. Algılanan poz hakkında bilgi edinme

Görüntüde bir kişi algılanırsa poz algılama API'si bir Pose döndürür 33 PoseLandmark içeren bir nesne olacaktır.

Kişi görüntünün içinde tamamen değilse model, eksik yer işareti koordinatlarını çerçevenin dışına atar ve bunlara düşük InFrameConfidence değerleri verir.

Karede kişi algılanmazsa Pose nesnesi PoseLandmark içermez.

Kotlin

// Get all PoseLandmarks. If no person was detected, the list will be empty
val allPoseLandmarks = pose.getAllPoseLandmarks()

// Or get specific PoseLandmarks individually. These will all be null if no person
// was detected
val leftShoulder = pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER)
val rightShoulder = pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER)
val leftElbow = pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW)
val rightElbow = pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW)
val leftWrist = pose.getPoseLandmark(PoseLandmark.LEFT_WRIST)
val rightWrist = pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST)
val leftHip = pose.getPoseLandmark(PoseLandmark.LEFT_HIP)
val rightHip = pose.getPoseLandmark(PoseLandmark.RIGHT_HIP)
val leftKnee = pose.getPoseLandmark(PoseLandmark.LEFT_KNEE)
val rightKnee = pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE)
val leftAnkle = pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE)
val rightAnkle = pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE)
val leftPinky = pose.getPoseLandmark(PoseLandmark.LEFT_PINKY)
val rightPinky = pose.getPoseLandmark(PoseLandmark.RIGHT_PINKY)
val leftIndex = pose.getPoseLandmark(PoseLandmark.LEFT_INDEX)
val rightIndex = pose.getPoseLandmark(PoseLandmark.RIGHT_INDEX)
val leftThumb = pose.getPoseLandmark(PoseLandmark.LEFT_THUMB)
val rightThumb = pose.getPoseLandmark(PoseLandmark.RIGHT_THUMB)
val leftHeel = pose.getPoseLandmark(PoseLandmark.LEFT_HEEL)
val rightHeel = pose.getPoseLandmark(PoseLandmark.RIGHT_HEEL)
val leftFootIndex = pose.getPoseLandmark(PoseLandmark.LEFT_FOOT_INDEX)
val rightFootIndex = pose.getPoseLandmark(PoseLandmark.RIGHT_FOOT_INDEX)
val nose = pose.getPoseLandmark(PoseLandmark.NOSE)
val leftEyeInner = pose.getPoseLandmark(PoseLandmark.LEFT_EYE_INNER)
val leftEye = pose.getPoseLandmark(PoseLandmark.LEFT_EYE)
val leftEyeOuter = pose.getPoseLandmark(PoseLandmark.LEFT_EYE_OUTER)
val rightEyeInner = pose.getPoseLandmark(PoseLandmark.RIGHT_EYE_INNER)
val rightEye = pose.getPoseLandmark(PoseLandmark.RIGHT_EYE)
val rightEyeOuter = pose.getPoseLandmark(PoseLandmark.RIGHT_EYE_OUTER)
val leftEar = pose.getPoseLandmark(PoseLandmark.LEFT_EAR)
val rightEar = pose.getPoseLandmark(PoseLandmark.RIGHT_EAR)
val leftMouth = pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH)
val rightMouth = pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH)

Java

// Get all PoseLandmarks. If no person was detected, the list will be empty
List<PoseLandmark> allPoseLandmarks = pose.getAllPoseLandmarks();

// Or get specific PoseLandmarks individually. These will all be null if no person
// was detected
PoseLandmark leftShoulder = pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER);
PoseLandmark rightShoulder = pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER);
PoseLandmark leftElbow = pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW);
PoseLandmark rightElbow = pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW);
PoseLandmark leftWrist = pose.getPoseLandmark(PoseLandmark.LEFT_WRIST);
PoseLandmark rightWrist = pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST);
PoseLandmark leftHip = pose.getPoseLandmark(PoseLandmark.LEFT_HIP);
PoseLandmark rightHip = pose.getPoseLandmark(PoseLandmark.RIGHT_HIP);
PoseLandmark leftKnee = pose.getPoseLandmark(PoseLandmark.LEFT_KNEE);
PoseLandmark rightKnee = pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE);
PoseLandmark leftAnkle = pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE);
PoseLandmark rightAnkle = pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE);
PoseLandmark leftPinky = pose.getPoseLandmark(PoseLandmark.LEFT_PINKY);
PoseLandmark rightPinky = pose.getPoseLandmark(PoseLandmark.RIGHT_PINKY);
PoseLandmark leftIndex = pose.getPoseLandmark(PoseLandmark.LEFT_INDEX);
PoseLandmark rightIndex = pose.getPoseLandmark(PoseLandmark.RIGHT_INDEX);
PoseLandmark leftThumb = pose.getPoseLandmark(PoseLandmark.LEFT_THUMB);
PoseLandmark rightThumb = pose.getPoseLandmark(PoseLandmark.RIGHT_THUMB);
PoseLandmark leftHeel = pose.getPoseLandmark(PoseLandmark.LEFT_HEEL);
PoseLandmark rightHeel = pose.getPoseLandmark(PoseLandmark.RIGHT_HEEL);
PoseLandmark leftFootIndex = pose.getPoseLandmark(PoseLandmark.LEFT_FOOT_INDEX);
PoseLandmark rightFootIndex = pose.getPoseLandmark(PoseLandmark.RIGHT_FOOT_INDEX);
PoseLandmark nose = pose.getPoseLandmark(PoseLandmark.NOSE);
PoseLandmark leftEyeInner = pose.getPoseLandmark(PoseLandmark.LEFT_EYE_INNER);
PoseLandmark leftEye = pose.getPoseLandmark(PoseLandmark.LEFT_EYE);
PoseLandmark leftEyeOuter = pose.getPoseLandmark(PoseLandmark.LEFT_EYE_OUTER);
PoseLandmark rightEyeInner = pose.getPoseLandmark(PoseLandmark.RIGHT_EYE_INNER);
PoseLandmark rightEye = pose.getPoseLandmark(PoseLandmark.RIGHT_EYE);
PoseLandmark rightEyeOuter = pose.getPoseLandmark(PoseLandmark.RIGHT_EYE_OUTER);
PoseLandmark leftEar = pose.getPoseLandmark(PoseLandmark.LEFT_EAR);
PoseLandmark rightEar = pose.getPoseLandmark(PoseLandmark.RIGHT_EAR);
PoseLandmark leftMouth = pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH);
PoseLandmark rightMouth = pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH);

Performansı iyileştirmeye yönelik ipuçları

Sonuçlarınızın kalitesi, giriş resminin kalitesine bağlıdır:

  • ML Kit'in pozu doğru şekilde algılayabilmesi için resimdeki kişinin yeterli piksel verisiyle temsil edilmesi gerekir. En iyi performans için özne en az 256x256 piksel olmalıdır.
  • Gerçek zamanlı bir uygulamada pozu algılarsanız giriş resimlerinin genel boyutlarını da dikkate alabilirsiniz. Daha küçük resimler daha hızlı işlenebilir. Bu nedenle, gecikmeyi azaltmak için resimleri daha düşük çözünürlüklerde çekin ancak yukarıdaki çözünürlük şartlarını göz önünde bulundurun ve öznenin resmin mümkün olduğunca büyük bir kısmını kaplamasını sağlayın.
  • Kötü bir resim odağı, doğruluğu da etkileyebilir. Kabul edilebilir sonuçlar elde etmezseniz kullanıcıdan resmi tekrar çekmesini isteyin.

Poz algılamayı gerçek zamanlı bir uygulamada kullanmak istiyorsanız en iyi kare hızlarına ulaşmak için şu yönergeleri uygulayın:

  • Temel poz algılama SDK'sını ve STREAM_MODE'ü kullanın.
  • Görüntüleri daha düşük çözünürlükte çekmeyi düşünün. Ancak bu API'nin resim boyutu koşullarını da göz önünde bulundurun.
  • Camera veya camera2 API'sini kullanıyorsanız algılayıcıya yapılan çağrıları sınırlayın. Yeni bir video çerçeve, algılayıcı çalışırken kullanılabilir hale gelirse çerçeveyi bırakın. Örnek olarak hızlı başlangıç kılavuzu örnek uygulamasındaki VisionProcessorBase sınıfına bakın.
  • CameraX API'sini kullanıyorsanız geri basınç stratejisinin varsayılan değerine ayarlandığından emin olun ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST. Bu, aynı anda yalnızca bir resmin analiz için gönderilmesini garanti eder. Analizör meşgulken daha fazla görüntü oluşturulursa bu görüntüler otomatik olarak bırakılır ve yayınlama için sıraya alınmaz. Analiz edilen resim, çağırarak kapatıldıktan sonra ImageProxy.close(), bir sonraki en son resim yayınlanır.
  • Algılayıcının çıkışını, üzerine grafik yerleştirmek için giriş görüntüsünü kullanın, önce ML Kit'ten sonucu alın ve ardından görüntüyü oluşturun tek bir adımda yapabilirsiniz. Bu, görüntü yüzeyine oluşturulur her giriş karesi için yalnızca bir kez. Örnek olarak, hızlı başlangıç kılavuzundaki örnek uygulamadaki CameraSourcePreview ve GraphicOverlay sınıflarına bakın.
  • Camera2 API'yi kullanıyorsanız resimleri ImageFormat.YUV_420_888 biçiminde kaydedin. Eski Camera API'yi kullanıyorsanız resimleri ImageFormat.NV21 biçiminde çekin.

Sonraki adımlar