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 จุด การบันทึกเส้นขีดจะเริ่มเมื่อผู้ใช้วางเคอร์เซอร์ลง (เช่น คลิกปุ่มเมาส์หลัก หรือแตะหน้าจอด้วยสไตลัสหรือนิ้ว) และสิ้นสุดเมื่อผู้ใช้ยกเคอร์เซอร์ขึ้น
- ภาพวาดประกอบด้วยเส้นอย่างน้อย 1 เส้น การจดจำจริงจะเกิดขึ้นในระดับนี้
- ตัวจดจำได้รับการกำหนดค่าด้วยภาษาอินพุตที่คาดไว้ ใช้เพื่อสร้างอินสแตนซ์ ของภาพวาดที่มีการกำหนดค่าตัวจดจำ
แนวคิดเหล่านี้ได้รับการติดตั้งใช้งานเป็นอินเทอร์เฟซและพจนานุกรมที่เฉพาะเจาะจง ซึ่งฉันจะกล่าวถึงในอีกไม่ช้า
การสร้างตัวจดจำ
หากต้องการจดจำข้อความจากอินพุตลายมือ คุณต้องรับอินสแตนซ์ของ
HandwritingRecognizer
โดยการเรียก navigator.createHandwritingRecognizer()
และส่งข้อจำกัด
ไปยังอินสแตนซ์ ข้อจำกัดจะกำหนดโมเดลการจดจำลายมือที่ควรใช้ ปัจจุบันคุณ
ระบุรายการภาษาตามลำดับความต้องการได้ดังนี้
const recognizer = await navigator.createHandwritingRecognizer({
languages: ['en'],
});
เมธอดจะแสดงผล Promise ที่แก้ไขด้วยอินสแตนซ์ของ HandwritingRecognizer
เมื่อเบราว์เซอร์ดำเนินการตามคำขอได้ มิเช่นนั้น ระบบจะปฏิเสธสัญญาด้วยข้อผิดพลาด และการจดจำลายมือจะไม่พร้อมใช้งาน ด้วยเหตุนี้ คุณจึงอาจต้องค้นหาการรองรับฟีเจอร์การจดจำที่เฉพาะเจาะจงของ
ตัวจดจำก่อน
การค้นหาการรองรับตัวจดจำ
การเรียกใช้ navigator.queryHandwritingRecognizer()
จะช่วยให้คุณตรวจสอบได้ว่าแพลตฟอร์มเป้าหมายรองรับฟีเจอร์การจดจำลายมือที่คุณต้องการใช้หรือไม่ เมธอดนี้ใช้
ออบเจ็กต์ข้อจำกัดเดียวกันกับเมธอด navigator.createHandwritingRecognizer()
ซึ่งมีรายการภาษาที่ขอ เมธอดจะแสดงผล Promise ที่แก้ไขด้วยออบเจ็กต์ผลลัพธ์หากพบตัวจดจำที่เข้ากันได้ มิเช่นนั้น Promise จะเปลี่ยนเป็น null
ในตัวอย่างต่อไปนี้ นักพัฒนาแอปจะทำสิ่งต่อไปนี้
- ต้องการตรวจหาข้อความเป็นภาษาอังกฤษ
- รับการคาดการณ์ทางเลือกที่มีโอกาสเกิดขึ้นน้อยกว่าเมื่อพร้อมใช้งาน
- เข้าถึงผลการแบ่งกลุ่ม เช่น อักขระที่ระบบจดจำ รวมถึงจุดและ เส้นที่ประกอบเป็นอักขระเหล่านั้น
const result =
await navigator.queryHandwritingRecognizerSupport({
languages: ['en']
});
console.log(result?.textAlternatives); // true if alternatives are supported
console.log(result?.textSegmentation); // true if segmentation is supported
หากเบราว์เซอร์รองรับฟีเจอร์
ที่นักพัฒนาแอปต้องการ ระบบจะตั้งค่าเป็น 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', 'stylus'].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()
ใน
drawing โดยปกติแล้ว การจดจำจะใช้เวลาน้อยกว่า 200 มิลลิวินาที คุณจึงเรียกใช้การคาดการณ์ซ้ำๆ ได้หากจำเป็น ตัวอย่างต่อไปนี้จะเรียกใช้การคาดคะเนใหม่หลังจากที่วาดแต่ละครั้งเสร็จสมบูรณ์
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));
});
เมธอดนี้จะแสดงผล Promise ซึ่งจะแก้ไขด้วยอาร์เรย์ของการคาดการณ์ที่เรียงตาม
ความน่าจะเป็น จำนวนองค์ประกอบจะขึ้นอยู่กับค่าที่คุณส่งไปยังคำใบ้ 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);
});
},
);
}
คุณสามารถใช้ข้อมูลนี้เพื่อติดตามกราฟีมที่ระบบจดจำได้บน Canvas อีกครั้ง
การจดจำที่สมบูรณ์
หลังจากที่การจดจำเสร็จสมบูรณ์แล้ว คุณจะปล่อยทรัพยากรได้โดยเรียกใช้เมธอด 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
คุณลองใช้คอมโพเนนต์ได้โดยใช้การสาธิตนี้ใน GitHub และอย่าลืมดูซอร์สโค้ดด้วย หากต้องการใช้การควบคุมในแอปพลิเคชัน ให้รับจาก npm
ความปลอดภัยและสิทธิ์
ทีม Chromium ออกแบบและใช้ Handwriting Recognition API โดยใช้หลักการพื้นฐาน ที่กำหนดไว้ในการควบคุมการเข้าถึงฟีเจอร์ที่มีประสิทธิภาพของแพลตฟอร์มเว็บ ซึ่งรวมถึงการควบคุมของผู้ใช้ ความโปร่งใส และการยศาสตร์
การควบคุมของผู้ใช้
ผู้ใช้ปิด Handwriting Recognition API ไม่ได้ โดยจะใช้ได้กับเว็บไซต์ที่แสดงผ่าน HTTPS เท่านั้น และเรียกใช้ได้จากบริบทการท่องเว็บระดับบนสุดเท่านั้น
ความโปร่งใส
ไม่มีข้อบ่งชี้ว่าการจดจำลายมือทำงานอยู่หรือไม่ เบราว์เซอร์จะใช้มาตรการตอบโต้เพื่อป้องกันการเก็บลายนิ้วมือ เช่น การแสดงข้อความแจ้งขอสิทธิ์ต่อผู้ใช้เมื่อตรวจพบการละเมิดที่อาจเกิดขึ้น
การคงอยู่ของสิทธิ์
ปัจจุบัน Handwriting Recognition API ไม่แสดงข้อความแจ้งขอสิทธิ์ใดๆ ดังนั้นจึงไม่จำเป็นต้องบันทึกสิทธิ์ในลักษณะใดๆ
ความคิดเห็น
ทีม Chromium ต้องการทราบความคิดเห็นของคุณเกี่ยวกับประสบการณ์การใช้งาน Handwriting Recognition API
บอกเราเกี่ยวกับการออกแบบ API
มีอะไรเกี่ยวกับ API ที่ไม่ทำงานตามที่คุณคาดหวังไว้ไหม หรือมีเมธอด หรือพร็อพเพอร์ตี้ที่ขาดหายไปซึ่งคุณต้องใช้เพื่อนำแนวคิดไปใช้ไหม หากมีคำถามหรือความคิดเห็นเกี่ยวกับโมเดลความปลอดภัย แจ้งปัญหาเกี่ยวกับข้อกำหนดในที่เก็บ GitHub ที่เกี่ยวข้อง หรือแสดงความคิดเห็นในปัญหาที่มีอยู่
รายงานปัญหาเกี่ยวกับการติดตั้งใช้งาน
หากพบข้อบกพร่องในการใช้งาน Chromium หรือการติดตั้งใช้งานแตกต่างจากข้อกำหนด
ยื่นข้อบกพร่องที่ new.crbug.com โปรดใส่รายละเอียดให้มากที่สุดเท่าที่จะทำได้
วิธีการง่ายๆ ในการทำซ้ำ และป้อน Blink>Handwriting
ในช่องคอมโพเนนต์
แสดงการสนับสนุน API
คุณวางแผนที่จะใช้ Handwriting Recognition API ไหม การสนับสนุนแบบสาธารณะของคุณจะช่วยให้ทีม Chromium จัดลําดับความสําคัญของฟีเจอร์และแสดงให้ผู้ให้บริการเบราว์เซอร์รายอื่นๆ เห็นว่าการสนับสนุนฟีเจอร์เหล่านี้มีความสําคัญเพียงใด
แชร์วิธีที่คุณวางแผนจะใช้ในเธรด Discourse ของ WICG ทวีตถึง @ChromiumDev โดยใช้แฮชแท็ก
#HandwritingRecognition
และแจ้งให้เราทราบว่าคุณใช้ฟีเจอร์นี้ที่ใดและอย่างไร
ลิงก์ที่มีประโยชน์
- คำอธิบาย
- ร่างข้อกำหนด
- ที่เก็บ GitHub
- ChromeStatus
- ข้อบกพร่องของ Chromium
- การตรวจสอบ TAG
- ความตั้งใจที่จะสร้างต้นแบบ
- ชุดข้อความ WebKit-Dev
- ตำแหน่งมาตรฐานของ Mozilla
คำขอบคุณ
เอกสารนี้ได้รับการตรวจสอบโดย Joe Medley Honglin Yu และ Jiewei Qian