จดจำลายมือของผู้ใช้

Handwrite Recognition API ช่วยให้คุณจดจำข้อความจากการป้อนข้อมูลด้วยลายมือได้แบบเรียลไทม์

Handwrite Recognition API คืออะไร

Handwrite Recognition API ช่วยให้คุณสามารถแปลงการเขียนด้วยลายมือ (หมึก) จากผู้ใช้เป็นข้อความ ระบบปฏิบัติการบางระบบมี API ดังกล่าวมานานแล้ว และด้วยความสามารถใหม่นี้ เว็บแอปของคุณสามารถใช้ฟังก์ชันนี้ได้ในที่สุด Conversion จะเกิดขึ้นในอุปกรณ์ของผู้ใช้โดยตรงและทำงานได้แม้ในโหมดออฟไลน์ โดยไม่ต้องเพิ่มไลบรารีหรือบริการของบุคคลที่สาม

API นี้ใช้การจดจำที่เรียกกันว่า "ออนไลน์" หรือการจดจำที่เกือบจะเป็นแบบเรียลไทม์ ซึ่งหมายความว่าระบบจะจดจำข้อมูลที่เขียนด้วยลายมือได้ในขณะที่ผู้ใช้กำลังวาดรูปโดยบันทึกและวิเคราะห์เส้นเดียว อัลกอริทึมออนไลน์สามารถให้ความแม่นยำในระดับที่สูงขึ้นเนื่องจากสัญญาณเพิ่มเติม เช่น ลำดับเชิงเวลาและแรงกดของเส้นหมึกแต่ละเส้น ซึ่งแตกต่างจากกระบวนการ "ออฟไลน์" เช่น Optical Character Recognition (OCR)

กรณีการใช้งานที่แนะนำสำหรับ API การรู้จำลายมือ

ตัวอย่างการใช้งานมีดังนี้

  • แอปพลิเคชันสำหรับจดโน้ตที่ผู้ใช้ต้องจับโน้ตที่เขียนด้วยลายมือและแปลเป็นข้อความ
  • แอปพลิเคชันฟอร์มที่ผู้ใช้สามารถใช้การป้อนข้อมูลด้วยลายมือหรือนิ้วได้เนื่องด้วยข้อจำกัดด้านเวลา
  • เกมที่ต้องมีการเติมตัวอักษรหรือตัวเลข เช่น อักษรไขว้ ฮันแมน หรือซูโดกุ

สถานะปัจจุบัน

API การจดจำลายมือมีให้บริการจาก (Chromium 99)

วิธีใช้ API การรู้จำลายมือ

การตรวจหาฟีเจอร์

ตรวจหาการรองรับเบราว์เซอร์โดยตรวจหาการมีอยู่ของเมธอด createHandwritingRecognizer() ในออบเจ็กต์ตัวนำทาง ดังนี้

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

แนวคิดหลัก

Handwrite Recognition API จะแปลงการป้อนข้อมูลด้วยลายมือเป็นข้อความ โดยไม่คำนึงถึงวิธีการป้อนข้อมูล (เมาส์ การแตะ ปากกา) API มี 4 เอนทิตีหลักดังนี้

  1. จุดแสดงถึงตำแหน่งของตัวชี้ในช่วงเวลาหนึ่งๆ
  2. โรคหลอดเลือดสมองประกอบด้วยจุดอย่างน้อย 1 จุด การบันทึกเส้นโครงร่างจะเริ่มต้นเมื่อผู้ใช้วางตัวชี้ลง (เช่น คลิกปุ่มหลักของเมาส์ หรือใช้ปากกาหรือนิ้วแตะหน้าจอ) และสิ้นสุดลงเมื่อผู้ใช้ยกตัวชี้ขึ้นอีกครั้ง
  3. ภาพวาดประกอบด้วยเส้นอย่างน้อย 1 เส้น ซึ่งการรับรู้จริงจะเกิดขึ้นในระดับนี้
  4. โปรแกรมรู้จำได้รับการกำหนดค่าด้วยภาษาสำหรับป้อนข้อมูลที่ต้องการ ซึ่งใช้เพื่อสร้างอินสแตนซ์ของภาพวาดที่ใช้การกำหนดค่าโปรแกรมรู้จำ

แนวคิดเหล่านี้จะนำมาใช้เป็นอินเทอร์เฟซและพจนานุกรมเฉพาะ ซึ่งผมจะพูดถึงในเร็วๆ นี้

เอนทิตีหลักของ API การจดจำลายมือ: จุดอย่างน้อย 1 จุดเขียนเส้นโครงร่าง เส้นอย่างน้อย 1 เส้นสำหรับเขียนภาพวาดที่เครื่องมือรู้จำสร้างขึ้น การจดจำจริงจะเกิดขึ้นในระดับภาพวาด

การสร้างโปรแกรมรู้จำ

หากต้องการจดจำข้อความจากอินพุตที่เขียนด้วยลายมือ คุณต้องรับอินสแตนซ์ของ 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 คุณสามารถใช้ข้อมูลนี้เพื่อเปิดใช้หรือปิดใช้ฟีเจอร์บางอย่างภายในแอปพลิเคชันของคุณ หรือเพื่อปรับการค้นหาแล้วส่งการค้นหาใหม่

เริ่มวาดภาพ

ภายในแอปพลิเคชันของคุณ คุณควรจัดเตรียมพื้นที่สำหรับป้อนข้อมูลให้ผู้ใช้เขียนรายการที่เขียนด้วยลายมือของตน สำหรับเหตุผลด้านประสิทธิภาพ เราขอแนะนำให้ดำเนินการนี้โดยใช้ออบเจ็กต์ Canvas แทน การใช้งานในส่วนนี้อยู่นอกเหนือขอบเขตของบทความนี้ แต่คุณสามารถดูวิธีการใช้งานได้ในการสาธิต

หากต้องการเริ่มภาพวาดใหม่ ให้เรียกใช้เมธอด startDrawing() ในการจดจำ วิธีนี้จะนำออบเจ็กต์ที่มีคำแนะนำต่างๆ มาปรับแต่งอัลกอริทึมการจดจำ คำใบ้ทั้งหมดเป็นตัวเลือก:

  • ประเภทข้อความที่ป้อน ได้แก่ ข้อความ อีเมล ตัวเลข หรืออักขระเดี่ยว (recognitionType)
  • ประเภทของอุปกรณ์อินพุต ได้แก่ การป้อนข้อมูลด้วยเมาส์ การแตะ หรือปากกา (inputType)
  • ข้อความก่อนหน้า (textContext)
  • จำนวนการคาดการณ์ทางเลือกที่มีแนวโน้มน้อยกว่าที่ควรแสดงผล (alternatives)
  • รายการอักขระที่ระบุตัวบุคคลได้ ("กราฟ") ที่ผู้ใช้มีแนวโน้มที่จะป้อนมากที่สุด (graphemeSet)

Handwrite Recognition API ทำงานได้ดีกับเหตุการณ์ของ Pointer ซึ่งมีอินเทอร์เฟซแบบนามธรรมสำหรับใช้อินพุตจากอุปกรณ์ชี้ตำแหน่งใดๆ อาร์กิวเมนต์เหตุการณ์ของตัวชี้ มีประเภทของตัวชี้ที่ใช้ ซึ่งหมายความว่าคุณจะใช้เหตุการณ์ของตัวชี้เพื่อกำหนดประเภทอินพุตโดยอัตโนมัติได้ ในตัวอย่างต่อไปนี้ ระบบจะสร้างภาพวาดสำหรับการจดจำลายมือขึ้นโดยอัตโนมัติเมื่อเกิดเหตุการณ์ 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 ด้วย ดังนั้นแฮนเดิล pointermove จะไม่เพิ่มจุดลงในเส้นโครงร่างที่เสร็จแล้ว

ต่อไปก็ถึงเวลาจดจำข้อมูลของผู้ใช้ด้วยการเรียกใช้เมธอด getPrediction() ในภาพวาด โดยปกติการจดจำจะใช้เวลาไม่ถึง 2-3 มิลลิวินาที คุณจึงเรียกใช้การคาดการณ์ซ้ำๆ ได้หากจำเป็น ตัวอย่างต่อไปนี้เรียกใช้การคาดการณ์ใหม่หลังจากแต่ละเส้นเสร็จสมบูรณ์

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> จะใช้การควบคุมการแก้ไขที่ปรับปรุงอย่างต่อเนื่องซึ่งมีความสามารถในการจดจำลายมือ การคลิกปุ่มที่มุมขวาล่างของตัวควบคุมการแก้ไขจะเป็นการเปิดใช้งานโหมดการวาด เมื่อวาดเสร็จแล้ว คอมโพเนนต์เว็บจะเริ่มการจดจำโดยอัตโนมัติและเพิ่มข้อความที่รู้จักกลับไปยังตัวควบคุมการแก้ไข หากระบบไม่รองรับ API การจดจำลายมือเลย หรือแพลตฟอร์มไม่รองรับฟีเจอร์ที่ขอ ระบบจะซ่อนปุ่มแก้ไขไว้ แต่การควบคุมการแก้ไขพื้นฐานจะยังคงใช้งานได้ในฐานะ <textarea>

คอมโพเนนต์เว็บมีพร็อพเพอร์ตี้และแอตทริบิวต์เพื่อกำหนดพฤติกรรมการจดจำจากภายนอก ซึ่งรวมถึง languages และ recognitiontype คุณตั้งค่าเนื้อหาของตัวควบคุมผ่านแอตทริบิวต์ value ได้ดังนี้

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

หากต้องการทราบเกี่ยวกับการเปลี่ยนแปลงมูลค่า ให้ฟังเหตุการณ์ input

คุณลองใช้คอมโพเนนต์ได้โดยใช้การสาธิตเกี่ยวกับ Glitch และอย่าลืมดู ซอร์สโค้ดด้วย หากต้องการใช้การควบคุมในแอปพลิเคชันของคุณ ให้รับการควบคุมจาก npm

ความปลอดภัยและสิทธิ์

ทีม Chromium ออกแบบและใช้งาน API การรู้จำลายมือโดยใช้หลักการสำคัญที่ระบุไว้ในการควบคุมการเข้าถึงฟีเจอร์แพลตฟอร์มเว็บที่มีประสิทธิภาพ ซึ่งรวมถึงการควบคุมผู้ใช้ ความโปร่งใส และการยศาสตร์

การควบคุมของผู้ใช้

ผู้ใช้จะปิด Handwrite Recognition API ไม่ได้ โดยจะใช้ได้กับเว็บไซต์ที่แสดงผ่าน HTTPS เท่านั้น และอาจเรียกใช้จากบริบทการท่องเว็บระดับบนสุดเท่านั้น

ความโปร่งใส

ไม่มีการระบุโดยใช้การจดจำลายมือว่าเปิดใช้งานอยู่หรือไม่ เพื่อป้องกันการเก็บฟิงเกอร์ปรินต์ เบราว์เซอร์ใช้มาตรการรับมือ เช่น การแสดงข้อความแจ้งสิทธิ์แก่ผู้ใช้เมื่อตรวจพบว่าอาจมีการละเมิด

ความต่อเนื่องของสิทธิ์

ขณะนี้ Handwrite Recognition API ไม่แสดงข้อความแจ้งสิทธิ์ จึงไม่จำเป็นต้องคงสิทธิ์ไว้ ไม่ว่าด้วยวิธีใด

ความคิดเห็น

ทีม Chromium ต้องการทราบประสบการณ์ของคุณเกี่ยวกับ Handwrite Recognition API

บอกเราเกี่ยวกับการออกแบบ API

มีบางอย่างเกี่ยวกับ API ที่ไม่ทำงานตามที่คุณคาดหวังหรือไม่ หรือยังไม่มีวิธีการหรือคุณสมบัติ ที่คุณต้องใช้เพื่อนำไอเดียของคุณไปปฏิบัติ หากมีข้อสงสัยหรือความคิดเห็น เกี่ยวกับรูปแบบการรักษาความปลอดภัย แจ้งปัญหาเกี่ยวกับที่เก็บ GitHub ที่เกี่ยวข้อง หรือเพิ่มความคิดเห็นของคุณเกี่ยวกับปัญหาที่มีอยู่

รายงานปัญหาเกี่ยวกับการติดตั้งใช้งาน

คุณพบข้อบกพร่องในการใช้งาน Chromium ไหม หรือการติดตั้งใช้งานแตกต่างจากข้อกําหนดหรือไม่ รายงานข้อบกพร่องที่ new.crbug.com ตรวจสอบว่าได้ใส่รายละเอียดให้มากที่สุดเท่าที่จะเป็นไปได้ วิธีการง่ายๆ ในการสร้างอีกครั้ง และป้อน Blink>Handwriting ในช่องคอมโพเนนต์ ภาพ Glitch เหมาะสำหรับการแชร์ซ้ำที่ง่ายและรวดเร็ว

แสดงการรองรับ API

คุณวางแผนที่จะใช้ Handwrite Recognition API ไหม การสนับสนุนแบบสาธารณะของคุณช่วยให้ทีม Chromium สามารถจัดลำดับความสำคัญของฟีเจอร์ต่างๆ และแสดงให้ผู้ให้บริการเบราว์เซอร์รายอื่นเห็นว่าการสนับสนุนฟีเจอร์เหล่านี้นั้นสำคัญเพียงใด

แชร์วิธีที่คุณวางแผนจะใช้ในชุดข้อความของ WICG Discourse ส่งทวีตไปที่ @ChromiumDev โดยใช้แฮชแท็ก #HandwritingRecognition และแจ้งให้เราทราบว่าคุณใช้งานที่ไหนและอย่างไร

กิตติกรรมประกาศ

บทความนี้ได้รับการตรวจสอบโดย Joe Medley, Honglin Yu และ Jiewei Qian รูปภาพหลักโดย Samir Bouaked ใน Unsplash