Android पर एमएल किट की मदद से डिजिटल इंक की पहचान करना

ML Kit की डिजिटल इंक पहचानने की सुविधा से, हाथ से लिखे टेक्स्ट को और स्केच को उन भाषाओं में इस्तेमाल किया जा सकता है.

इसे आज़माएं

शुरू करने से पहले

  1. प्रोजेक्ट-लेवल की build.gradle फ़ाइल में, पक्का करें कि आपने buildscript और allprojects, दोनों सेक्शन में Google की Maven रिपॉज़िटरी को शामिल किया हो.
  2. अपने मॉड्यूल की ऐप्लिकेशन-लेवल की Gradle फ़ाइल में ML Kit Android लाइब्रेरी के लिए डिपेंडेंसी जोड़ें, जो आम तौर पर app/build.gradle होती है:
dependencies {
  // ...
  implementation 'com.google.mlkit:digital-ink-recognition:18.1.0'
}

अब आप Ink ऑब्जेक्ट में टेक्स्ट की पहचान करने के लिए तैयार हैं.

Ink ऑब्जेक्ट बनाएं

Ink ऑब्जेक्ट को बनाने का मुख्य तरीका है, उसे टचस्क्रीन पर ड्रॉ करना. चालू है Android के लिए, आप इसके लिए कैनवस इस मकसद से ऐसा नहीं किया जा सकता. आपका टच इवेंट हैंडलर addNewTouchEvent() पर कॉल करना चाहिए स्ट्रोक में पॉइंट स्टोर करने के लिए, नीचे दिए गए कोड स्निपेट को दिखाने का तरीका उपयोगकर्ता Ink ऑब्जेक्ट में ले जाता है.

यह सामान्य पैटर्न नीचे दिए गए कोड स्निपेट में दिखाया गया है. ज़्यादा जानकारी के लिए, ML Kit क्विकस्टार्ट सैंपल देखें.

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();

DigitalInkTagr का इंस्टेंस पाएं

पहचान करने के लिए, Ink इंस्टेंस को DigitalInkRecognizer ऑब्जेक्ट. नीचे दिया गया कोड दिखाता है कि ऐसे इंस्टैंशिएट कैसे करें BCP-47 टैग से मिला आइडेंटिफ़ायर.

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 ऑब्जेक्ट प्रोसेस करें

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));

ऊपर दिए गए सैंपल कोड में, यह माना जाता है कि पहचान करने वाला मॉडल पहले ही डाउनलोड किया गया है, जैसा कि अगले सेक्शन में बताया गया है.

मॉडल डाउनलोड मैनेज करना

डिजिटल इंक की पहचान करने वाला एपीआई सैकड़ों भाषाओं में काम करता है, लेकिन हर एक भाषा के लिए भाषा के लिए किसी भी पहचान से पहले कुछ डेटा डाउनलोड करने की आवश्यकता होती है. आस-पास हर भाषा के लिए 20 एमबी स्टोरेज की ज़रूरत है. इसे RemoteModelManager ऑब्जेक्ट.

नया मॉडल डाउनलोड करें

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));

यह पता करना कि मॉडल पहले से डाउनलोड किया गया है या नहीं

Kotlin

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

Java

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

डाउनलोड किया गया मॉडल मिटाना

डिवाइस के स्टोरेज से किसी मॉडल को हटाने से जगह खाली हो जाती है.

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));

टेक्स्ट की पहचान करने की सुविधा को बेहतर बनाने के लिए सलाह

टेक्स्ट की पहचान करने की सुविधा, अलग-अलग भाषाओं में अलग-अलग हो सकती है. जवाब का सटीक होना इस बात पर भी निर्भर करता है कि लिखने के तरीकों पर ध्यान देते हैं. डिजिटल इंक रिकग्निशन को लिखने की कई तरह की स्टाइल के हिसाब से काम करने की ट्रेनिंग दी गई है. हर उपयोगकर्ता के लिए नतीजे अलग-अलग हो सकते हैं.

टेक्स्ट आइडेंटिफ़ायर को सटीक बनाने के कुछ तरीके यहां दिए गए हैं. ध्यान दें कि ये तकनीकें, यह कैटगरी, इमोजी, ऑटोड्रॉ, और आकृतियों के लिए तय की गई ड्रॉइंग की कैटगरी तय करने वाली टेक्नोलॉजी पर लागू नहीं होती.

लिखने की जगह

कई ऐप्लिकेशन में, उपयोगकर्ता के इनपुट के लिए अच्छी तरह से लिखने की जगह होती है. चिह्न का मतलब यह है लिखने की जगह के साइज़ से तय होता है कि उसका साइज़ कितना है. उदाहरण के लिए, लोअर या अपर केस अक्षर "o" के बीच का अंतर या "c", और कॉमा बनाम a फ़ॉरवर्ड स्लैश.

आइडेंटिफ़ायर को, लिखने की जगह की चौड़ाई और ऊंचाई के बारे में बताने से, सटीक नतीजे पाने में मदद मिल सकती है. हालांकि, आइडेंटिफ़ायर यह मानता है कि लिखने की जगह में टेक्स्ट की सिर्फ़ एक लाइन है. अगर फ़िज़िकल लिखने का क्षेत्र इतना बड़ा है कि उपयोगकर्ता दो या उससे ज़्यादा लाइनें लिख सकता है. इससे आपको बेहतर की लंबाई के साथ, उस लंबाई के साथ टेक्स्ट की एक लाइन. पहचानकर्ता को आपके पास किए जाने वाले WriteArea ऑब्जेक्ट का संगत होना आवश्यक नहीं है स्क्रीन पर मौजूद लिखने की जगह पर रखें. राइटिंग एरिया की लंबाई को इस तरह बदलना अन्य भाषाओं के मुकाबले कुछ भाषाओं में बेहतर काम करती है.

लिखने की जगह बताते समय, इसकी चौड़ाई और ऊंचाई वही बताएं जो स्ट्रोक की इकाइयां हैं निर्देशांक. x,y निर्देशांक आर्ग्युमेंट के लिए, इकाई की कोई ज़रूरत नहीं है - एपीआई सभी को नॉर्मलाइज़ करता है इकाइयां, इसलिए केवल एक ही चीज़ महत्वपूर्ण है, वह है स्ट्रोक का सापेक्ष आकार और स्थिति. आपके पास ये काम करने के विकल्प हैं निर्देशांकों को किसी भी स्केल पर पास करना आपके सिस्टम के लिए फ़ायदेमंद होता है.

प्री-कॉन्टेक्स्ट

प्री-कॉन्टेक्स्ट, वह टेक्स्ट है जो Ink में स्ट्रोक से ठीक पहले होता है को पहचानने की कोशिश कर रहे हैं. पहचान करने वाले को पहचान से पहले की प्रक्रिया के बारे में बताकर उसकी मदद की जा सकती है.

उदाहरण के लिए, कर्सिव अक्षर "n" और "u" अक्सर लोग एक-दूसरे को समझ लेते हैं. अगर उपयोगकर्ता के पास पहले से आंशिक शब्द "आर्ग" दर्ज किया है, तो वे स्ट्रोक के साथ जारी रख सकते हैं जिन्हें समझा जा सकता है "ument" या "nment" शामिल करें. प्री-कॉन्टेक्स्ट "आर्ग" तय करना समस्या को हल करता है, क्योंकि "तर्क" "तर्क" के बजाय सबसे ज़्यादा इस्तेमाल होता है.

प्री-कॉन्टेक्स्ट, पहचान करने वाले व्यक्ति को शब्दों के बीच के स्पेस यानी ब्रेक ब्रेक को पहचानने में भी मदद कर सकता है. आप स्पेस वर्ण टाइप करें, लेकिन आप उसे नहीं बना सकते, इसलिए पहचानकर्ता यह कैसे तय कर सकता है कि कोई शब्द कब खत्म होगा और अगला वाला शुरू हो जाता है? अगर उपयोगकर्ता ने पहले से ही "नमस्ते" लिखा है और पहले से लिखे शब्द के साथ आगे बढ़ते हैं "world", प्री-कॉन्टेक्स्ट के बिना, आइडेंटिफ़ायर "world" स्ट्रिंग दिखाता है. हालांकि, अगर आप "हैलो" से पहले, मॉडल स्ट्रिंग " "हैलो" के साथ एक प्रमुख स्थान के साथ, दुनिया" "हैलोवर्ड" से ज़्यादा समझ में आता है.

आपको कॉन्टेक्स्ट के पहले की सबसे लंबी स्ट्रिंग देनी चाहिए. इसमें ज़्यादा से ज़्यादा 20 वर्ण होने चाहिए. इनमें ये भी शामिल हैं स्पेसेज़. अगर स्ट्रिंग लंबी है, तो आइडेंटिफ़ायर सिर्फ़ आखिरी 20 वर्णों का इस्तेमाल करता है.

नीचे दिया गया कोड सैंपल, लिखने की जगह तय करने और प्री-कॉन्टेक्स्ट के बारे में बताने के लिए RecognitionContext ऑब्जेक्ट.

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);

स्ट्रोक का क्रम

पहचान करने की सटीक जानकारी, स्ट्रोक के क्रम पर निर्भर करती है. उपयोगकर्ता, स्ट्रोक की उम्मीद उसी क्रम में हो जिस क्रम में लोग स्वाभाविक रूप से लिखेंगे; उदाहरण के लिए, अंग्रेज़ी के लिए बाएं से दाएं. कोई भी केस यह इस पैटर्न से शुरू होता है. जैसे, आखिरी शब्द से शुरू होने वाला अंग्रेज़ी वाक्य लिखना, कम सटीक नतीजे देती है.

दूसरा उदाहरण, जब Ink के बीच में मौजूद कोई शब्द हटाकर उसकी जगह पर इस्तेमाल किया जा रहा हो दूसरा शब्द. संशोधन शायद किसी वाक्य के बीच में है, लेकिन संशोधन के लिए स्ट्रोक हैं स्ट्रोक अनुक्रम के अंत में हैं. इस मामले में हमारी सलाह है कि आप नए लिखे गए शब्द को अलग से API में भेजें और पहले से पहचान करने की ज़रूरत है.

अस्पष्ट आकृतियों से निपटना

कुछ मामलों में, आइडेंटिफ़ायर को दिए गए आकार का मतलब साफ़ तौर पर नहीं बताया जाता है. इसके लिए उदाहरण के लिए, बहुत गोल किनारे वाले आयत को आयत या दीर्घवृत्त के रूप में देखा जा सकता है.

इन अस्पष्ट मामलों को पहचान स्कोर के उपलब्ध होने पर उनका इस्तेमाल करके हल किया जा सकता है. सिर्फ़ आकार की कैटगरी तय करने वाले टूल से स्कोर मिलता है. अगर मॉडल को बहुत भरोसा है, तो सबसे अच्छे नतीजे का स्कोर होगा दूसरे सर्वश्रेष्ठ से बहुत बेहतर है. अगर अनिश्चितता है, तो शीर्ष दो परिणामों के स्कोर पास हो सकता है. साथ ही, ध्यान रखें कि आकृति की कैटगरी तय करने वाले टूल पूरे Ink को सिंगल आकार. उदाहरण के लिए, अगर Ink में एक रेक्टैंगल और हर के बगल में एक एलिप्स मौजूद है अन्य, पहचानकर्ता किसी एक या दूसरे (या कुछ बिलकुल अलग) को से लिया गया है, क्योंकि मान्यता प्राप्त करने वाला एक उम्मीदवार दो आकारों का प्रतिनिधित्व नहीं कर सकता है.