کاربران خود را بشناسید' دست خط

Handwriting Recognition API به شما این امکان را می دهد که متن را از ورودی دست نویس در صورت وقوع تشخیص دهید.

Handwriting Recognition API چیست؟

Handwriting Recognition API به شما امکان می دهد دست خط (جوهر) را از کاربران خود به متن تبدیل کنید. برخی از سیستم‌عامل‌ها مدت‌هاست که چنین APIهایی را در خود جای داده‌اند و با این قابلیت جدید، برنامه‌های وب شما در نهایت می‌توانند از این قابلیت استفاده کنند. تبدیل مستقیماً در دستگاه کاربر انجام می شود، حتی در حالت آفلاین نیز کار می کند، همه اینها بدون افزودن هیچ گونه کتابخانه یا خدمات شخص ثالثی است.

این API به اصطلاح "آنلاین" یا تقریباً واقعی تشخیص را پیاده سازی می کند. این بدان معنی است که ورودی دست نویس در حالی که کاربر در حال ترسیم آن است با گرفتن و تجزیه و تحلیل تک ضربه ها شناسایی می شود. برخلاف روش‌های "خارج از خط" مانند تشخیص کاراکتر نوری (OCR)، که در آن فقط محصول نهایی مشخص است، الگوریتم‌های آنلاین می‌توانند به دلیل سیگنال‌های اضافی مانند توالی زمانی و فشار جوهر فردی، دقت بالاتری را ارائه دهند. سکته های مغزی

موارد استفاده پیشنهادی برای Handwriting Recognition API

مصارف مثال عبارتند از:

  • برنامه های یادداشت برداری که در آن کاربران می خواهند یادداشت های دست نویس را ثبت کنند و آنها را به متن ترجمه کنند.
  • برنامه هایی را تشکیل می دهد که کاربران می توانند به دلیل محدودیت زمانی از ورودی قلم یا انگشت استفاده کنند.
  • بازی هایی که نیاز به پر کردن حروف یا اعداد دارند، مانند جدول کلمات متقاطع، جلاد یا سودوکو.

وضعیت فعلی

Handwriting Recognition API از (Chromium 99) در دسترس است.

نحوه استفاده از Handwriting Recognition API

تشخیص ویژگی

با بررسی وجود متد createHandwritingRecognizer() در شی ناوبر، پشتیبانی مرورگر را شناسایی کنید:

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

مفاهیم اصلی

Handwriting Recognition API ورودی دست‌نویس را بدون توجه به روش ورودی (موس، لمس، قلم) به متن تبدیل می‌کند. API دارای چهار موجودیت اصلی است:

  1. نقطه نشان دهنده جایی است که نشانگر در یک زمان خاص قرار داشته است.
  2. سکته مغزی شامل یک یا چند نقطه است. ضبط سکته مغزی زمانی شروع می شود که کاربر نشانگر را پایین می آورد (یعنی روی دکمه اصلی ماوس کلیک می کند، یا با قلم یا انگشت خود صفحه را لمس می کند) و زمانی که نشانگر را به سمت بالا بالا می برد، پایان می یابد.
  3. یک نقاشی از یک یا چند ضربه تشکیل شده است. شناخت واقعی در این سطح صورت می گیرد.
  4. شناساگر با زبان ورودی مورد انتظار پیکربندی شده است. برای ایجاد نمونه ای از طراحی با پیکربندی شناساگر اعمال شده استفاده می شود.

این مفاهیم به‌عنوان رابط‌ها و دیکشنری‌های خاص پیاده‌سازی می‌شوند که به زودی به آن‌ها خواهم پرداخت.

موجودیت‌های اصلی Handwriting Recognition API: یک یا چند نقطه یک سکته مغزی را می‌سازند، یک یا چند ضربه یک طرح را می‌سازند که شناسایی‌کننده ایجاد می‌کند. تشخیص واقعی در سطح طراحی صورت می گیرد.

ایجاد یک شناساگر

برای تشخیص متن از ورودی دست‌نویس، باید نمونه‌ای از HandwritingRecognizer را با فراخوانی navigator.createHandwritingRecognizer() و دادن محدودیت‌هایی به آن دریافت کنید. محدودیت ها مدل تشخیص دست خطی را که باید استفاده شود تعیین می کند. در حال حاضر، می‌توانید فهرستی از زبان‌ها را به ترتیب اولویت مشخص کنید:

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

زمانی که مرورگر بتواند درخواست شما را برآورده کند، این روش قولی را برمی‌گرداند که با یک نمونه از 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

متد یک وعده حل با یک شیء نتیجه را برمی گرداند. اگر مرورگر از ویژگی مشخص شده توسط توسعه دهنده پشتیبانی کند، مقدار آن روی true تنظیم می شود. در غیر این صورت روی false تنظیم می شود. می‌توانید از این اطلاعات برای فعال یا غیرفعال کردن ویژگی‌های خاص در برنامه‌تان یا تنظیم درخواست خود و ارسال درخواست جدید استفاده کنید.

یک نقاشی را شروع کنید

در برنامه خود، باید یک ناحیه ورودی ارائه دهید که در آن کاربر دست نوشته های خود را وارد می کند. به دلایل عملکرد، توصیه می شود این را با کمک یک شیء بوم پیاده سازی کنید. پیاده سازی دقیق این قسمت از حوصله این مقاله خارج است، اما برای مشاهده نحوه انجام آن می توانید به دمو مراجعه کنید.

برای شروع یک طراحی جدید، متد startDrawing() را روی شناساگر فراخوانی کنید. این روش یک شی حاوی نکات مختلف را برای تنظیم دقیق الگوریتم تشخیص می گیرد. همه نکات اختیاری هستند:

  • نوع متنی که وارد می شود: متن، آدرس ایمیل، اعداد یا یک کاراکتر ( recognitionType )
  • نوع دستگاه ورودی: ورودی ماوس، لمسی یا قلم ( inputType )
  • متن قبلی ( textContext )
  • تعداد پیش‌بینی‌های جایگزین با احتمال کمتری که باید برگردانده شوند ( alternatives )
  • لیستی از کاراکترهای قابل شناسایی توسط کاربر ("graphemes") که کاربر به احتمال زیاد وارد می کند ( graphemeSet )

Handwriting Recognition API با Pointer Events که یک رابط انتزاعی برای مصرف ورودی از هر دستگاه اشاره گر ارائه می دهد، به خوبی بازی می کند. آرگومان های رویداد اشاره گر شامل نوع اشاره گر مورد استفاده است. این بدان معنی است که می توانید از رویدادهای اشاره گر برای تعیین خودکار نوع ورودی استفاده کنید. در مثال زیر، نقاشی برای تشخیص دست خط به طور خودکار در اولین رخداد یک رخداد 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 زمانی فراخوانی می شود که نشانگر در سراسر صفحه جابجا شود. این نکات نیز باید به سکته مغزی اضافه شوند. اگر نشانگر در حالت "پایین" نباشد، برای مثال هنگام حرکت مکان نما در سراسر صفحه بدون فشار دادن دکمه ماوس، رویداد می تواند افزایش یابد. کنترل کننده رویداد از مثال زیر بررسی می کند که آیا یک stroke فعال وجود دارد یا خیر، و نقطه جدید را به آن اضافه می کند.

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

متن را تشخیص دهید

وقتی کاربر دوباره نشانگر را بلند کرد، می‌توانید با فراخوانی متد addStroke() آن را به نقاشی خود اضافه کنید. مثال زیر activeStroke را نیز بازنشانی می‌کند، بنابراین کنترل‌کننده pointermove امتیازی را به stroke تکمیل‌شده اضافه نمی‌کند.

در مرحله بعد، نوبت به تشخیص ورودی کاربر با فراخوانی متد 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 با استفاده از اصول اصلی تعریف شده در کنترل دسترسی به ویژگی‌های قدرتمند پلتفرم وب ، از جمله کنترل کاربر، شفافیت، و ارگونومی، API تشخیص دست‌نویس را طراحی و پیاده‌سازی کرد.

کنترل کاربر

Handwriting Recognition API نمی تواند توسط کاربر خاموش شود. این فقط برای وب‌سایت‌هایی که از طریق HTTPS ارائه می‌شوند در دسترس است و ممکن است فقط از بافت مرور سطح بالا فراخوانی شود.

شفافیت

هیچ نشانه ای وجود ندارد که آیا تشخیص دست خط فعال است یا خیر. برای جلوگیری از اثرانگشت، مرورگر اقدامات متقابلی را اجرا می‌کند، مانند نمایش درخواست مجوز به کاربر در صورت تشخیص سوء استفاده احتمالی.

تداوم مجوز

Handwriting Recognition API در حال حاضر هیچ درخواست مجوزی را نشان نمی دهد. بنابراین، به هیچ وجه نیازی به اصرار مجوز نیست.

بازخورد

تیم Chromium می‌خواهد درباره تجربیات شما با Handwriting Recognition API بشنود.

در مورد طراحی API به ما بگویید

آیا چیزی در مورد API وجود دارد که آنطور که انتظار داشتید کار نمی کند؟ یا آیا روش ها یا ویژگی هایی وجود دارد که برای اجرای ایده خود به آنها نیاز دارید؟ سوال یا نظری در مورد مدل امنیتی دارید؟ یک مشکل مشخصات را در مخزن GitHub مربوطه ثبت کنید یا افکار خود را به یک مشکل موجود اضافه کنید.

گزارش مشکل در اجرا

آیا با اجرای Chromium اشکالی پیدا کردید؟ یا اجرا با مشخصات متفاوت است؟ یک اشکال را در new.crbug.com ثبت کنید. اطمینان حاصل کنید که تا آنجا که می توانید جزئیات، دستورالعمل های ساده برای بازتولید را وارد کنید و Blink>Handwriting در کادر Components وارد کنید. Glitch برای به اشتراک گذاری سریع و آسان تکرارها عالی عمل می کند.

پشتیبانی از API را نشان دهید

آیا قصد استفاده از Handwriting Recognition API را دارید؟ پشتیبانی عمومی شما به تیم Chromium کمک می‌کند ویژگی‌ها را اولویت‌بندی کند و به سایر فروشندگان مرورگر نشان می‌دهد که چقدر حمایت از آنها ضروری است.

نحوه استفاده از آن را در موضوع WICG Discourse به اشتراک بگذارید. با استفاده از هشتگ #HandwritingRecognition یک توییت به @ChromiumDev ارسال کنید و به ما اطلاع دهید که کجا و چگونه از آن استفاده می کنید.

سپاسگزاریها

این مقاله توسط Joe Medley ، Honglin Yu و Jiewei Qian بررسی شده است. تصویر قهرمان توسط سمیر بواکد در Unsplash .