Android'de ML Kit ile dijital mürekkebi tanıma

ML Kit'in dijital mürekkep tanıma özelliğiyle tek bir cihazda el yazısıyla yazılmış metinleri yüzlerce dilde dijital yüzeyler oluşturabilir ve çizimleri sınıflandırabilir.

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ını, modülünüzün uygulama düzeyindeki Gradle dosyasına ekleyin. Bu dosya genellikle app/build.gradle olan:
dependencies {
  // ...
  implementation 'com.google.mlkit:digital-ink-recognition:18.1.0'
}

Artık Ink nesnedeki metinleri tanımaya başlamak için hazırsınız.

Ink nesnesi oluşturun

Bir Ink nesnesi oluşturmanın ana yolu, onu dokunmatik ekranda çizmektir. Şu tarihte: Android'de, Canvas: bu şekilde ilerler. Sizin dokunma etkinliği işleyicileri addNewTouchEvent() yöntemi, fırça fırçalarındaki noktaları depolamak için aşağıdaki kod snippet'ini Ink nesnesini çeker.

Bu genel kalıp, aşağıdaki kod snippet'inde gösterilmektedir. Bkz. ML Kit hızlı başlangıç örneği inceleyebilirsiniz.

Kotlin

var inkBuilder = Ink.builder()
lateinit var strokeBuilder: Ink.Stroke.Builder

// Call this each time there is a new event.
fun addNewTouchEvent(event: MotionEvent) {
  val action = event.actionMasked
  val x = event.x
  val y = event.y
  var t = System.currentTimeMillis()

  // If your setup does not provide timing information, you can omit the
  // third paramater (t) in the calls to Ink.Point.create
  when (action) {
    MotionEvent.ACTION_DOWN -> {
      strokeBuilder = Ink.Stroke.builder()
      strokeBuilder.addPoint(Ink.Point.create(x, y, t))
    }
    MotionEvent.ACTION_MOVE -> strokeBuilder!!.addPoint(Ink.Point.create(x, y, t))
    MotionEvent.ACTION_UP -> {
      strokeBuilder.addPoint(Ink.Point.create(x, y, t))
      inkBuilder.addStroke(strokeBuilder.build())
    }
    else -> {
      // Action not relevant for ink construction
    }
  }
}

...

// This is what to send to the recognizer.
val ink = inkBuilder.build()

Java

Ink.Builder inkBuilder = Ink.builder();
Ink.Stroke.Builder strokeBuilder;

// Call this each time there is a new event.
public void addNewTouchEvent(MotionEvent event) {
  float x = event.getX();
  float y = event.getY();
  long t = System.currentTimeMillis();

  // If your setup does not provide timing information, you can omit the
  // third paramater (t) in the calls to Ink.Point.create
  int action = event.getActionMasked();
  switch (action) {
    case MotionEvent.ACTION_DOWN:
      strokeBuilder = Ink.Stroke.builder();
      strokeBuilder.addPoint(Ink.Point.create(x, y, t));
      break;
    case MotionEvent.ACTION_MOVE:
      strokeBuilder.addPoint(Ink.Point.create(x, y, t));
      break;
    case MotionEvent.ACTION_UP:
      strokeBuilder.addPoint(Ink.Point.create(x, y, t));
      inkBuilder.addStroke(strokeBuilder.build());
      strokeBuilder = null;
      break;
  }
}

...

// This is what to send to the recognizer.
Ink ink = inkBuilder.build();

DigitalInkRekred'in bir örneğini alma

Tanıma işlemini gerçekleştirmek için Ink örneğini şuraya gönderin: DigitalInkRecognizer nesne algılandı. Aşağıdaki kod, bu tür bir BCP-47 etiketinden tanıyıcı olabilir.

Kotlin

// Specify the recognition model for a language
var modelIdentifier: DigitalInkRecognitionModelIdentifier
try {
  modelIdentifier = DigitalInkRecognitionModelIdentifier.fromLanguageTag("en-US")
} catch (e: MlKitException) {
  // language tag failed to parse, handle error.
}
if (modelIdentifier == null) {
  // no model was found, handle error.
}
var model: DigitalInkRecognitionModel =
    DigitalInkRecognitionModel.builder(modelIdentifier).build()


// Get a recognizer for the language
var recognizer: DigitalInkRecognizer =
    DigitalInkRecognition.getClient(
        DigitalInkRecognizerOptions.builder(model).build())

Java

// Specify the recognition model for a language
DigitalInkRecognitionModelIdentifier modelIdentifier;
try {
  modelIdentifier =
    DigitalInkRecognitionModelIdentifier.fromLanguageTag("en-US");
} catch (MlKitException e) {
  // language tag failed to parse, handle error.
}
if (modelIdentifier == null) {
  // no model was found, handle error.
}

DigitalInkRecognitionModel model =
    DigitalInkRecognitionModel.builder(modelIdentifier).build();

// Get a recognizer for the language
DigitalInkRecognizer recognizer =
    DigitalInkRecognition.getClient(
        DigitalInkRecognizerOptions.builder(model).build());

Ink nesnesini işleyin

Kotlin

recognizer.recognize(ink)
    .addOnSuccessListener { result: RecognitionResult ->
      // `result` contains the recognizer's answers as a RecognitionResult.
      // Logs the text from the top candidate.
      Log.i(TAG, result.candidates[0].text)
    }
    .addOnFailureListener { e: Exception ->
      Log.e(TAG, "Error during recognition: $e")
    }

Java

recognizer.recognize(ink)
    .addOnSuccessListener(
        // `result` contains the recognizer's answers as a RecognitionResult.
        // Logs the text from the top candidate.
        result -> Log.i(TAG, result.getCandidates().get(0).getText()))
    .addOnFailureListener(
        e -> Log.e(TAG, "Error during recognition: " + e));

Yukarıdaki örnek kod, tanıma modelinin zaten başarılı bir şekilde indirilmelidir.

Model indirmelerini yönetme

Dijital mürekkep tanıma API'si yüzlerce dili desteklese de her biri dil seçeneği, herhangi bir tanıma işleminden önce bazı verilerin indirilmesini gerektirir. Şu civarda: Her dil için 20 MB depolama alanı gerekir. Bu işlem RemoteModelManager nesne algılandı.

Yeni model indirin

Kotlin

import com.google.mlkit.common.model.DownloadConditions
import com.google.mlkit.common.model.RemoteModelManager

var model: DigitalInkRecognitionModel =  ...
val remoteModelManager = RemoteModelManager.getInstance()

remoteModelManager.download(model, DownloadConditions.Builder().build())
    .addOnSuccessListener {
      Log.i(TAG, "Model downloaded")
    }
    .addOnFailureListener { e: Exception ->
      Log.e(TAG, "Error while downloading a model: $e")
    }

Java

import com.google.mlkit.common.model.DownloadConditions;
import com.google.mlkit.common.model.RemoteModelManager;

DigitalInkRecognitionModel model = ...;
RemoteModelManager remoteModelManager = RemoteModelManager.getInstance();

remoteModelManager
    .download(model, new DownloadConditions.Builder().build())
    .addOnSuccessListener(aVoid -> Log.i(TAG, "Model downloaded"))
    .addOnFailureListener(
        e -> Log.e(TAG, "Error while downloading a model: " + e));

Bir modelin önceden indirilip indirilmediğini kontrol etme

Kotlin

var model: DigitalInkRecognitionModel =  ...
remoteModelManager.isModelDownloaded(model)

Java

DigitalInkRecognitionModel model = ...;
remoteModelManager.isModelDownloaded(model);

İndirilen bir modeli silme

Bir modelin cihazın depolama alanından kaldırılması yer açar.

Kotlin

var model: DigitalInkRecognitionModel =  ...
remoteModelManager.deleteDownloadedModel(model)
    .addOnSuccessListener {
      Log.i(TAG, "Model successfully deleted")
    }
    .addOnFailureListener { e: Exception ->
      Log.e(TAG, "Error while deleting a model: $e")
    }

Java

DigitalInkRecognitionModel model = ...;
remoteModelManager.deleteDownloadedModel(model)
                  .addOnSuccessListener(
                      aVoid -> Log.i(TAG, "Model successfully deleted"))
                  .addOnFailureListener(
                      e -> Log.e(TAG, "Error while deleting a model: " + e));

Metin tanıma doğruluğunu iyileştirmeye yönelik ipuçları

Metin tanımanın doğruluğu diller arasında farklılık gösterebilir. Doğruluk oranı şuna da bağlıdır: ele alacağız. Dijital Mürekkep Tanıma özelliği, pek çok yazma stilini işleyecek şekilde eğitilir. sonuç kullanıcıya göre değişebilir.

Metin tanıyıcının doğruluğunu artırmanın bazı yolları aşağıda verilmiştir. Bu tekniklerin emoji, otomatik çizim ve şekillere yönelik çizim sınıflandırıcılarında geçerli değildir.

Yazma alanı

Birçok uygulamanın, kullanıcı girişi için iyi tanımlanmış bir yazma alanı vardır. Bir simgenin anlamı boyutu, onu içeren yazı alanının boyutuna göre kısmen belirlenir. Örneğin, "o" harfi ile küçük veya büyük harf veya "c", virgül ve a eğik çizgi.

Tanıyıcıya, yazma alanının genişliğini ve yüksekliğini söylemek doğruluğu artırabilir. Ancak, tanıyıcı, yazma alanında yalnızca tek bir satırlık metin olduğunu varsayar. Fiziksel yazma alanı kullanıcının iki veya daha fazla satır yazmasına izin verecek kadar büyük olursa yüksekliğini en iyi tahmin ettiğiniz yükseklikle bir WriteArea'dan geçerek sonuçlar elde edebilirsiniz. tek satırlık metin kullanarak ekleyebilirsiniz. Tanıyıcıya ilettiğiniz WriteArea nesnesinin karşılık gelmesine gerek yok ekrandaki fiziksel yazı alanıyla aynı olur. WriteArea yüksekliğini bu şekilde değiştirme bazı dillerde daha iyi çalışır.

Yazma alanını belirlerken genişliğini ve yüksekliğini fırçayla aynı birimlerde belirtin koordinatlar. x, y koordinat bağımsız değişkenlerinin birim gereksinimleri yoktur; API, olduğundan, önemli olan tek şey çizgilerin göreceli boyutu ve konumudur. İsterseniz sisteminiz için uygun olan ölçekte koordinat verebilir.

Bağlam öncesi

Bağlam ön bilgisi, eklediğiniz Ink içindeki fırçalardan hemen önce gelen metindir birlikte çalışır. Tanıyıcıya bağlam öncesi hakkında bilgi vererek yardımcı olabilirsiniz.

Örneğin, "n" şeklinde el yazısı harfleri ve "u" çoğu zaman birbiriyle karıştırılır. Kullanıcı "arg" kısmi kelimesini girmişlerse "ument" veya "nment". Bağlam öncesi "arg" değerini belirtme muğlaklığı giderir çünkü "bağımsız değişken" "bağımsız değişken"den daha olasıdır.

Bağlam ön bilgisi, tanıyıcının kelime sonlarını, yani kelimeler arasındaki boşlukları belirlemesine de yardımcı olabilir. Şunları yapabilirsiniz: boşluk karakteri giriyor ama çizemiyorsun, o halde tanıyıcı bir kelimenin ne zaman sona erdiğini nasıl belirleyebilir bir sonraki başlıyor mu? Kullanıcı zaten "merhaba" yazdıysa ve şöyle devam eder: "world" değerini, bağlam öncesi olmadan tanıyıcı "world" dizesini döndürür. Ancak, bağlam öncesi "merhaba" ise model, " "merhaba"dan itibaren baştaki boşlukla dünya" "merhabakelime"den daha anlamlıdır.

Mümkün olan en uzun bağlam öncesi dizesini (en fazla 20 karakter dahil) sağlamanız gerekir. alanlar'a dokunun. Dize daha uzunsa tanıyıcı yalnızca son 20 karakteri kullanır.

Aşağıdaki kod örneğinde bir yazma alanının nasıl tanımlanacağı ve RecognitionContext nesnesini ifade eder.

Kotlin

var preContext : String = ...;
var width : Float = ...;
var height : Float = ...;
val recognitionContext : RecognitionContext =
    RecognitionContext.builder()
        .setPreContext(preContext)
        .setWritingArea(WritingArea(width, height))
        .build()

recognizer.recognize(ink, recognitionContext)

Java

String preContext = ...;
float width = ...;
float height = ...;
RecognitionContext recognitionContext =
    RecognitionContext.builder()
                      .setPreContext(preContext)
                      .setWritingArea(new WritingArea(width, height))
                      .build();

recognizer.recognize(ink, recognitionContext);

Çizgi sıralama

Tanıma doğruluğu kulaçların sırasına göre hassastır. Tanıyıcılar darbelerin kullanıcıların doğal olarak yazdıkları sırayla olmasıdır; örneğin İngilizce için soldan sağa. Tüm durumlar Örneğin, bu kalıptan farklı bir dizi kelime kullanabilirsiniz. Örneğin, doğruluk oranı daha düşük sonuçlar verir.

Başka bir örnek de Ink kelimesinin ortasındaki bir kelime kaldırılıp ekleyebilirsiniz. Revizyon muhtemelen bir cümlenin ortasındadır, ancak düzeltmedeki fırça darbeleri çizgi dizisinin sonundadır. Bu durumda, yeni yazılan kelimeyi API'ye ayrı olarak göndermenizi ve ve kendi mantığınızı kullanarak önceki tanımalardan geleceksiniz.

Belirsiz şekillerle başa çıkma

Tanıyıcıya sağlanan şeklin anlamının belirsiz olduğu durumlar vardır. Örneğin, Örneğin, kenarları çok yuvarlanmış bir dikdörtgen, dikdörtgen veya elips olarak görülebilir.

Net olmayan bu destek kayıtları, mevcut olduğunda tanıma puanları kullanılarak ele alınabilir. Yalnızca şekil sınıflandırıcılar puanlar sağlar. Model çok güveniliyorsa en yüksek sonucun puanı ikinci en iyisinden çok daha iyi. Belirsizlik varsa ilk iki sonuca ait puanlar yakın olun. Ayrıca, şekil sınıflandırıcılarının tüm Ink öğesini bir tek şekil. Örneğin, Ink her birinin yanında bir dikdörtgen ve bir elips içeriyorsa, tanıyıcı, bu uyarının diğer bir özelliğinden (ya da tamamen farklı bir şey) Çünkü tek bir tanıma adayı iki şekli temsil edemez.