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

Handwriting Recognition API ช่วยให้คุณจดจำข้อความจากการป้อนข้อมูลด้วยลายมือขณะที่ป้อน

Handwriting Recognition API คืออะไร

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

API นี้ใช้การจดจําแบบ "ออนไลน์" หรือแบบเกือบเรียลไทม์ ซึ่งหมายความว่าระบบจะจดจำข้อมูลที่เขียนด้วยมือขณะที่ผู้ใช้เขียนโดยจับภาพและวิเคราะห์การเขียนแต่ละครั้ง ซึ่งแตกต่างจากกระบวนการ "ออฟไลน์" เช่น การรู้จำอักขระด้วยภาพ (OCR) ที่ทราบเฉพาะผลิตภัณฑ์ขั้นสุดท้ายเท่านั้น อัลกอริทึมแบบออนไลน์จะให้ผลลัพธ์ที่แม่นยำกว่าเนื่องจากมีสัญญาณเพิ่มเติม เช่น ลำดับเวลาและแรงกดของเส้นหมึกแต่ละเส้น

กรณีการใช้งานที่แนะนำสำหรับ Handwriting Recognition API

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

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

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

Handwriting Recognition API พร้อมใช้งานใน (Chromium 99)

วิธีใช้ Handwriting Recognition API

การตรวจหาองค์ประกอบ

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

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

แนวคิดหลัก

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

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

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

เอนทิตีหลักของ Handwriting Recognition 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)

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

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

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

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

ความโปร่งใส

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

การเก็บรักษาสิทธิ์

ปัจจุบัน Handwriting Recognition API ไม่ได้แสดงข้อความแจ้งสิทธิ์ใดๆ ดังนั้นจึงไม่จำเป็นต้องเก็บสิทธิ์ไว้

ความคิดเห็น

ทีม Chromium อยากทราบความคิดเห็นของคุณเกี่ยวกับ Handwriting Recognition API

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

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

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

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

แสดงการสนับสนุน API

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

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

ขอขอบคุณ

เอกสารนี้ผ่านการตรวจสอบโดย Joe Medley, Honglin Yu และ Jiewei Qian