זיהוי המשתמשים שלך' כתב יד

ממשק ה-API לזיהוי כתבי יד מאפשר לכם לזהות טקסט מקלט בכתב יד בזמן ההתרחשות שלו.

מהו Handwriting Recognition API?

ה-API לזיהוי כתבי יד מאפשר להמיר כתב יד (דיו) מהמשתמשים שלכם לטקסט. חלק ממערכות ההפעלה כוללות כבר זמן רב ממשקי API כאלה, ובזכות היכולת החדשה הזו, אפליקציות האינטרנט שלכם יכולות להשתמש באופן סופי בפונקציונליות הזו. ההמרה מתבצעת ישירות במכשיר של המשתמש ופועלת גם במצב אופליין, וכל זה בלי להוסיף ספריות או שירותים של צד שלישי.

ממשק ה-API הזה מיישם זיהוי שנקרא 'אונליין' או זיהוי כמעט בזמן אמת. כלומר, הקלט בכתב יד מזוהה בזמן שהמשתמש מצייר אותו, על ידי תיעוד וניתוח של הקווים הבודדים. בניגוד לפעולות 'אופליין' כמו זיהוי תווים אופטי (OCR), שבהן ידוע רק המוצר הסופי, אלגוריתמים אונליין יכולים לספק רמה גבוהה יותר של דיוק בגלל אותות נוספים כמו רצף זמן והלחץ של משיכות הדיו הנפרדות.

תרחישים לדוגמה לשימוש ב-Handwriting Recognition API

דוגמאות לשימושים:

  • אפליקציות לרישום הערות שבהן המשתמשים רוצים לצלם הערות בכתב יד ולתרגם אותן לטקסט.
  • אפליקציות של טפסים שבהן המשתמשים יכולים להשתמש בקלט באמצעות עט או אצבע בגלל מגבלות זמן.
  • משחקים שבהם צריך למלא אותיות או מספרים, כמו תשבצים, דמעות או סודוקו.

הסטטוס הנוכחי

ממשק ה-API של זיהוי כתב היד זמין מ-Chromium 99 ואילך.

איך משתמשים ב-Handwriting Recognition API

זיהוי תכונות

כדי לזהות את התמיכה בדפדפן, בודקים אם השיטה createHandwritingRecognizer() קיימת באובייקט הניווט:

if ('createHandwritingRecognizer' in navigator) {
  // 🎉 The Handwriting Recognition API is supported!
}

מושגי ליבה

ממשק ה-API לזיהוי כתב יד ממיר קלט בכתב יד לטקסט, ללא קשר לשיטת הקלט (עכבר, מגע, עט). ה-API כולל ארבע ישויות עיקריות:

  1. נקודה מייצגת את המיקום של הסמן בזמן מסוים.
  2. קו חוצה כולל נקודה אחת או יותר. ההקלטה של הקו מתחילה כשהמשתמש מניח את הסמן (כלומר לוחץ על לחצן העכבר הראשי או נוגע במסך בעזרת העט או האצבע) ומסתיימת כשהמשתמש מרים את הסמן חזרה.
  3. ציור מורכב מקשת אחת או יותר. הזיהוי בפועל מתבצע ברמה הזו.
  4. המזהה מוגדר עם שפת הקלט הצפויה. הוא משמש ליצירת מופע של ציור עם הגדרות המזהה.

המושגים האלה מיושמים כממשקים ומילונים ספציפיים, ועליהם ארחיב בהמשך.

ישויות הליבה של Handwriting Recognition API: נקודה אחת או יותר יוצרות קו, וקו אחד או יותר יוצרים ציור, שהמערכת לזיהוי יוצרת. הזיהוי בפועל מתבצע ברמת הציור.

יצירת מכשיר זיהוי

כדי לזהות טקסט מקלט בכתב יד, צריך לקבל מופע של HandwritingRecognizer על ידי קריאה ל-navigator.createHandwritingRecognizer() והפעלת אילוצים אליו. המגבלות קובעות את המודל לזיהוי כתב יד שבו צריך להשתמש. בשלב הזה אפשר לציין רשימה של שפות לפי סדר ההעדפה:

const recognizer = await navigator.createHandwritingRecognizer({
  languages: ['en'],
});

השיטה מחזירה הבטחה (promise) שמתקבלת עם מופע של HandwritingRecognizer כשהדפדפן יכול למלא את הבקשה. אחרת, הוא ידחה את ההבטחה עם שגיאה, וזיהוי כתב יד לא יהיה זמין. לכן, מומלץ קודם לבדוק אם יש תמיכה בתכונות זיהוי מסוימות בזיהוי.

תמיכה בשאילתות למזהה

אפשר להפעיל את navigator.queryHandwritingRecognizerSupport() כדי לבדוק אם פלטפורמת היעד תומכת בתכונות של זיהוי כתב היד שבהן אתם מתכוונים להשתמש. בדוגמה הבאה, המפתח:

  • רוצה לזהות טקסטים באנגלית
  • קבלת תחזיות חלופיות ופחות סבירות, כשהן זמינות
  • לקבל גישה לתוצאת הפיצול, כלומר התווים שזוהו, כולל הנקודות והקווים שמרכיבים אותם
const { languages, alternatives, segmentationResults } =
  await navigator.queryHandwritingRecognizerSupport({
    languages: ['en'],
    alternatives: true,
    segmentationResult: true,
  });

console.log(languages); // true or false
console.log(alternatives); // true or false
console.log(segmentationResult); // true or false

השיטה מחזירה הבטחה (promise) שמתבררת עם אובייקט תוצאה. אם הדפדפן תומך בתכונה שהוגדרה על ידי המפתח, הערך שלו יוגדר כ-true. אחרת, הוא יוגדר כ-false. אפשר להשתמש במידע הזה כדי להפעיל או להשבית תכונות מסוימות באפליקציה, או כדי לשנות את השאילתה ולשלוח שאילתה חדשה.

התחלת שרטוט

באפליקציה, צריך להציע אזור קלט שבו המשתמש מזין את הפרטים בכתב יד. מטעמי ביצועים, מומלץ להטמיע את הקוד הזה בעזרת אובייקט לוח. ההטמעה המדויקת של החלק הזה לא נכללת במאמר הזה, אבל אפשר לעיין בהדגמה כדי לראות איך עושים את זה.

כדי להתחיל ציור חדש, צריך להפעיל את השיטה startDrawing() במזהה. בשיטה הזו נעשה שימוש באובייקט שמכיל רמזים שונים כדי לשפר את אלגוריתם הזיהוי. כל ההנחיות הן אופציונליות:

  • סוג הטקסט שמוזן: טקסט, כתובות אימייל, מספרים או תו בודד (recognitionType)
  • סוג מכשיר הקלט: עכבר, קלט מגע או קלט עט (inputType)
  • הטקסט הקודם (textContext)
  • מספר התחזיות החלופיות פחות הסבירות שצריך להחזיר (alternatives)
  • רשימה של תווים מזהים של משתמשים ('גרפימות') שהמשתמשים צפויים להזין (graphemeSet)

ה-API לזיהוי כתבי יד פועל היטב עם אירועי מצביע, שמספקים ממשק מופשט לקבלת קלט מכל התקן הצבעה. הארגומנטים של אירועי מצביע מכילים את סוג הסמן שבו משתמשים. כלומר, אפשר להשתמש באירועי סמן כדי לקבוע את סוג הקלט באופן אוטומטי. בדוגמה הבאה, הציור לזיהוי כתב יד נוצר באופן אוטומטי במופע הראשון של אירוע pointerdown באזור הכתב היד. מכיוון ש-pointerType יכול להיות ריק או מוגדר לערך קנייני, הוספתי בדיקת עקביות כדי לוודא שהערכים שמוגדרים לסוג הקלט של הציור הם רק ערכים נתמכים.

let drawing;
let activeStroke;

canvas.addEventListener('pointerdown', (event) => {
  if (!drawing) {
    drawing = recognizer.startDrawing({
      recognitionType: 'text', // email, number, per-character
      inputType: ['mouse', 'touch', 'pen'].find((type) => type === event.pointerType),
      textContext: 'Hello, ',
      alternatives: 2,
      graphemeSet: ['f', 'i', 'z', 'b', 'u'], // for a fizz buzz entry form
    });
  }
  startStroke(event);
});

הוספת קו

האירוע pointerdown הוא גם המקום הנכון להתחיל קו חדש. כדי לעשות זאת, יוצרים מכונה חדשה של HandwritingStroke. בנוסף, כדאי לאחסן את השעה הנוכחית כנקודת התייחסות לנקודות הבאות שנוספו אליה:

function startStroke(event) {
  activeStroke = {
    stroke: new HandwritingStroke(),
    startTime: Date.now(),
  };
  addPoint(event);
}

הוסף נקודה

אחרי שיוצרים את הקו, צריך להוסיף אליו את הנקודה הראשונה ישירות. בהמשך ככל שתוסיפו עוד נקודות, כדאי להטמיע את הלוגיקה של יצירת הנקודות בשיטה נפרדת. בדוגמה הבאה, השיטה addPoint() מחשבת את משך הזמן שחלף מחותמת הזמן של ההפניה. המידע על הזמן הוא אופציונלי, אבל הוא יכול לשפר את איכות הזיהוי. לאחר מכן, המערכת קוראת את הקואורדינטות X ו-Y מאירוע הסמן ומוסיפה את הנקודה לקו הנוכחי.

function addPoint(event) {
  const timeElapsed = Date.now() - activeStroke.startTime;
  activeStroke.stroke.addPoint({
    x: event.offsetX,
    y: event.offsetY,
    t: timeElapsed,
  });
}

הגורם המטפל באירועים pointermove נקרא כשהסמן מועבר במסך. צריך להוסיף גם את הנקודות האלה לקו. האירוע יכול להתרחש גם אם הסמן לא נמצא במצב 'מופעל', למשל כשמזיזים את הסמן במסך בלי ללחוץ על לחצן העכבר. פונקציית הטיפול באירועים בדוגמה הבאה בודקת אם יש קו פעיל ומוסיפה אליו את הנקודה החדשה.

canvas.addEventListener('pointermove', (event) => {
  if (activeStroke) {
    addPoint(event);
  }
});

זיהוי טקסט

כשהמשתמש ירים שוב את הסמן, תוכלו להוסיף את הקו לציור על ידי קריאה לשיטה addStroke(). הדוגמה הבאה גם מאפסת את activeStroke, כך שה-handler של pointermove לא יוסיף נקודות לקווים שהושלמו.

בשלב הבא, הגיע הזמן לזהות את הקלט של המשתמש, על ידי קריאה ל-method getPrediction() בשרטוט. זיהוי בדרך כלל נמשך פחות מכמה מאות אלפיות השנייה, כך שאפשר להריץ תחזיות שוב ושוב לפי הצורך. בדוגמה הבאה מתבצעת הפקה של תחזית חדשה אחרי כל קו שמושלם.

canvas.addEventListener('pointerup', async (event) => {
  drawing.addStroke(activeStroke.stroke);
  activeStroke = null;

  const [mostLikelyPrediction, ...lessLikelyAlternatives] = await drawing.getPrediction();
  if (mostLikelyPrediction) {
    console.log(mostLikelyPrediction.text);
  }
  lessLikelyAlternatives?.forEach((alternative) => console.log(alternative.text));
});

השיטה הזו מחזירה הבטחה שמסתיימת במערך של חיזויים, שמסודרים לפי הסבירות. מספר הרכיבים תלוי בערך שהעברתם לטיפת העזרה alternatives. אפשר להשתמש במערך הזה כדי להציג למשתמש מבחר של התאמות אפשריות ולבקש ממנו לבחור אפשרות. לחלופין, אפשר פשוט להשתמש בתחזית הסבירה ביותר, כפי שעשיתי בדוגמה.

אובייקט התחזית מכיל את הטקסט שזוהה ותוצאת פילוח אופציונלית, אותה אסביר בקטע הבא.

תובנות מפורטות עם תוצאות של פילוח

אם פלטפורמת היעד תומכת בכך, אובייקט התחזית יכול להכיל גם תוצאת פילוח. מערך שמכיל את כל קטעי הכתב שזוהו, שילוב של התו המזוהה של המשתמש (grapheme) יחד עם המיקום שלו בטקסט שזוהה (beginIndex, endIndex), והמשיכות והנקודות שיצרו אותו.

if (mostLikelyPrediction.segmentationResult) {
  mostLikelyPrediction.segmentationResult.forEach(
    ({ grapheme, beginIndex, endIndex, drawingSegments }) => {
      console.log(grapheme, beginIndex, endIndex);
      drawingSegments.forEach(({ strokeIndex, beginPointIndex, endPointIndex }) => {
        console.log(strokeIndex, beginPointIndex, endPointIndex);
      });
    },
  );
}

אפשר להשתמש במידע הזה כדי לאתר שוב את הגרפמות שזוהו בקנבס.

תיבות משורטטות סביב כל גרפים מזוהה

הכרה מלאה

אחרי שהזיהוי מסתיים, אפשר לפנות משאבים על ידי קריאה לשיטה clear() ב-HandwritingDrawing ולשיטה finish() ב-HandwritingRecognizer:

drawing.clear();
recognizer.finish();

הדגמה (דמו)

רכיב האינטרנט <handwriting-textarea> מטמיע אמצעי בקרה לעריכה שמתפתח בהדרגה, עם יכולת לזיהוי כתב יד. לוחצים על הלחצן בפינה השמאלית התחתונה של חלונית הבקרה של העריכה כדי להפעיל את מצב הציור. כשמסיימים את הציור, רכיב האינטרנט מתחיל את הזיהוי באופן אוטומטי ומוסיף את הטקסט שזוהה חזרה לכלי העריכה. אם אין תמיכה ב-Handwriting Recognition API בכלל, או שהפלטפורמה לא תומכת בתכונות המבוקשות, לחצן העריכה יהיה מוסתר. עם זאת, עדיין אפשר להשתמש בלחצן הבקרה הבסיסי לעריכה כ-<textarea>.

רכיב האינטרנט מציע מאפיינים ומאפיינים משניים כדי להגדיר את התנהגות הזיהוי מבחוץ, כולל languages ו-recognitiontype. אפשר להגדיר את התוכן של הרכיב באמצעות המאפיין value:

<handwriting-textarea languages="en" recognitiontype="text" value="Hello"></handwriting-textarea>

כדי לקבל עדכונים על שינויים בערך, אפשר להאזין לאירוע input.

אפשר לנסות את הרכיב באמצעות ההדגמה הזו ב-Glitch. כדאי גם לעיין בקוד המקור. כדי להשתמש באמצעי הבקרה באפליקציה, צריך לקבל אותו מ-npm.

אבטחה והרשאות

צוות Chromium תכנן ויישם את Handwriting Recognition API בהתאם לעקרונות המרכזיים שמוגדרים במאמר בקרת הגישה לתכונות מתקדמות של פלטפורמת האינטרנט, כולל בקרת משתמשים, שקיפות וארגונומיה.

שליטת משתמשים

המשתמש לא יכול להשבית את Handwriting Recognition API. הוא זמין רק לאתרים שמוצגים באמצעות HTTPS, וניתן להפעיל אותו רק מההקשר של הגלישה ברמה העליונה.

שקיפות

אין אינדיקציה לכך שזיהוי כתב היד פעיל. כדי למנוע יצירה של טביעת אצבע דיגיטלית, הדפדפן נוקט אמצעים נגדיים, כמו הצגת בקשה להרשאה למשתמש כשהוא מזהה שימוש לרעה אפשרי.

התמדת ההרשאות

בשלב הזה לא מוצגות בקשות להרשאות מה-API של זיהוי כתב יד. לכן, אין צורך לשמור את ההרשאה בשום צורה.

משוב

צוות Chromium רוצה לשמוע על החוויה שלכם עם Handwriting Recognition API.

תיאור של עיצוב ה-API

האם יש משהו ב-API שלא פועל כצפוי? או אולי חסרות שיטות או מאפיינים שאתם צריכים כדי להטמיע את הרעיון? יש לכם שאלות או הערות לגבי מודל האבטחה? אפשר לשלוח דיווח על בעיה במפרט במאגר GitHub המתאים, או להוסיף את המחשבות שלכם לבעיה קיימת.

דיווח על בעיה בהטמעה

מצאתם באג בהטמעה של Chromium? או שההטמעה שונה מהמפרט? שולחים דיווח על באג בכתובת new.crbug.com. חשוב לכלול כמה שיותר פרטים, הוראות פשוטות לשחזור הבעיה ולהזין את הערך Blink>Handwriting בתיבה Components. Glitch הוא כלי מצוין לשיתוף שחזור מהיר וקל של באגים.

תמיכה ב-API

אתם מתכננים להשתמש ב-Handwriting Recognition API? התמיכה הציבורית שלכם עוזרת לצוות Chromium לתעדף תכונות ומראה לספקי דפדפנים אחרים עד כמה חשוב לתמוך בהם.

אתם יכולים לספר איך אתם מתכננים להשתמש בו בשרשור ב-Discourse של WICG. שלחו ציוץ אל @ChromiumDev. באמצעות ה-hashtag #HandwritingRecognition תוכלו לספר לנו איפה אתם משתמשים בו ואיך אתם משתמשים בו.

אישורים

המסמך הזה נבדק על ידי Joe Medley,‏ Honglin Yu ו-Jiewei Qian.