Nhận dạng chữ viết tay của người dùng

API Nhận dạng chữ viết tay cho phép bạn nhận dạng văn bản từ dữ liệu nhập viết tay khi nó xảy ra.

API Nhận dạng chữ viết tay là gì?

API Nhận dạng chữ viết tay cho phép bạn chuyển đổi chữ viết tay (mực) của người dùng thành văn bản. Từ lâu, một số hệ điều hành đã bao gồm những API như vậy và với chức năng mới này, ứng dụng web của bạn có thể cuối cùng là sử dụng chức năng này. Quá trình chuyển đổi diễn ra ngay trên thiết bị của người dùng, ở chế độ ngoại tuyến mà không cần thêm bất kỳ thư viện hoặc dịch vụ nào của bên thứ ba.

API này triển khai tính năng được gọi là "trực tuyến" hoặc gần như nhận dạng theo thời gian thực. Điều này có nghĩa là dữ liệu đầu vào viết tay sẽ được nhận dạng trong khi người dùng vẽ nó bằng cách thu thập và phân tích dữ liệu đầu vào lần quạt tay. Trái ngược với "ngoại tuyến" như Nhận dạng ký tự quang học (OCR), trong đó chỉ có sản phẩm cuối được biết đến, các thuật toán trực tuyến có thể cung cấp mức độ chính xác cao hơn do các tín hiệu bổ sung như trình tự thời gian và áp lực của từng nét mực.

Các trường hợp sử dụng đề xuất cho API Nhận dạng chữ viết tay

Sau đây là một số ví dụ về cách sử dụng:

  • Ứng dụng ghi chú mà người dùng muốn chụp ghi chú viết tay và yêu cầu dịch ghi chú thành văn bản.
  • Biểu mẫu các ứng dụng mà người dùng có thể sử dụng phương thức nhập bằng bút hoặc ngón tay do hạn chế về thời gian.
  • Các trò chơi yêu cầu điền chữ cái hoặc số, chẳng hạn như ô chữ, treo người hoặc sudoku.

Trạng thái hiện tại

API Nhận dạng chữ viết tay được cung cấp từ (Chromium 99).

Cách sử dụng API Nhận dạng chữ viết tay

Phát hiện tính năng

Phát hiện tính năng hỗ trợ trình duyệt bằng cách kiểm tra sự tồn tại của phương thức createHandwritingRecognizer() trên đối tượng trình điều hướng:

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

Các khái niệm chính

API Nhận dạng chữ viết tay chuyển đổi dữ liệu nhập bằng tay thành văn bản, bất kể phương thức nhập (chuột, chạm, bút). API này có 4 thực thể chính:

  1. Điểm đại diện cho vị trí của con trỏ tại một thời điểm cụ thể.
  2. Nét vẽ bao gồm một hoặc nhiều điểm. Quá trình ghi lại nét vẽ bắt đầu khi người dùng đặt con trỏ xuống (tức là nhấp vào nút chuột chính hoặc chạm vào màn hình bằng bút hoặc ngón tay) và kết thúc khi họ đưa con trỏ lên trở lại.
  3. Bản vẽ bao gồm một hoặc nhiều nét vẽ. Quá trình ghi nhận thực tế diễn ra ở cấp độ này.
  4. Trình nhận dạng được định cấu hình với ngôn ngữ nhập dự kiến. Tệp này được dùng để tạo một thực thể của một bản vẽ được áp dụng cấu hình trình nhận dạng.

Các khái niệm này được triển khai dưới dạng các giao diện và từ điển cụ thể mà tôi sẽ đề cập ngay sau đây.

Các thực thể cốt lõi của API Nhận dạng chữ viết tay: Một hoặc nhiều điểm tạo nên một nét vẽ, một hoặc nhiều nét tạo nên một bản vẽ mà trình nhận dạng tạo ra. Quá trình nhận dạng thực tế diễn ra ở cấp độ bản vẽ.

Tạo trình nhận dạng

Để nhận dạng văn bản từ dữ liệu đầu vào viết tay, bạn cần có được một thực thể của HandwritingRecognizer bằng cách gọi navigator.createHandwritingRecognizer() và truyền các điều kiện ràng buộc vào ứng dụng. Các quy tắc ràng buộc xác định mô hình nhận dạng chữ viết tay sẽ được sử dụng. Hiện tại, bạn có thể chỉ định danh sách ngôn ngữ theo thứ tự ưu tiên:

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

Phương thức này trả về một giải pháp hứa hẹn bằng một thực thể của HandwritingRecognizer khi trình duyệt có thể thực hiện yêu cầu của bạn. Nếu không, Bard sẽ từ chối lời hứa kèm theo lỗi và sẽ không có tính năng nhận dạng chữ viết tay. Vì lý do này, bạn nên truy vấn hỗ trợ của trình nhận dạng cho các tính năng nhận dạng cụ thể trước tiên.

Truy vấn hỗ trợ trình nhận dạng

Bằng cách gọi navigator.queryHandwritingRecognizerSupport(), bạn có thể kiểm tra xem nền tảng mục tiêu có phải là hỗ trợ tính năng nhận dạng chữ viết tay mà bạn định sử dụng. Trong ví dụ sau, phương thức nhà phát triển:

  • muốn phát hiện văn bản bằng tiếng Anh
  • nhận các cụm từ gợi ý thay thế, ít có khả năng xảy ra (nếu có)
  • có quyền truy cập vào kết quả phân đoạn, tức là các ký tự được công nhận, bao gồm các điểm và những nét tạo nên
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

Phương thức này trả về một giải pháp hứa hẹn bằng đối tượng kết quả. Nếu trình duyệt hỗ trợ tính năng này do nhà phát triển chỉ định, thì giá trị sẽ được đặt thành true. Nếu không, giá trị này sẽ được thiết lập thành false. Bạn có thể sử dụng thông tin này để bật hoặc tắt các tính năng nhất định trong ứng dụng của mình hoặc để điều chỉnh truy vấn của bạn và gửi truy vấn mới.

Bắt đầu vẽ

Trong đơn đăng ký, bạn nên cung cấp một vùng nhập dữ liệu nơi người dùng viết tay mục nhập. Vì lý do liên quan đến hiệu suất, bạn nên triển khai phương thức này với sự trợ giúp của đối tượng canvas. Cụm từ chính xác Việc triển khai phần này nằm ngoài phạm vi của bài viết này, nhưng bạn có thể tham khảo bản minh hoạ để xem cách thực hiện.

Để bắt đầu một bản vẽ mới, hãy gọi phương thức startDrawing() trên trình nhận dạng. Phương thức này lấy một chứa các gợi ý khác nhau để tinh chỉnh thuật toán nhận dạng. Tất cả gợi ý là không bắt buộc:

  • Loại văn bản được nhập: văn bản, địa chỉ email, số hoặc ký tự cá nhân (recognitionType)
  • Loại thiết bị đầu vào: chuột, cảm ứng hoặc phương thức nhập bằng bút (inputType)
  • Văn bản ở trước (textContext)
  • Số lượng cụm từ gợi ý thay thế ít có khả năng được trả về (alternatives)
  • Danh sách các ký tự có thể nhận dạng người dùng ("biểu đồ") mà người dùng có nhiều khả năng nhập nhất (graphemeSet)

API Nhận dạng chữ viết tay hoạt động tốt với Sự kiện Con trỏ, cung cấp giao diện trừu tượng để xử lý dữ liệu đầu vào từ bất kỳ thiết bị trỏ nào. Các đối số sự kiện con trỏ chứa loại con trỏ đang được sử dụng. Tức là bạn có thể sử dụng các sự kiện con trỏ để xác định loại dữ liệu đầu vào tự động. Trong ví dụ sau, bản vẽ để nhận dạng chữ viết tay được tự động được tạo vào lần đầu tiên diễn ra sự kiện pointerdown trên khu vực chữ viết tay. Là pointerType có thể để trống hoặc được đặt thành giá trị độc quyền. Tôi đã giới thiệu quy trình kiểm tra tính nhất quán để đảm bảo đảm bảo chỉ đặt các giá trị được hỗ trợ cho loại dữ liệu đầu vào của bản vẽ.

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);
});

Thêm nét vẽ

Sự kiện pointerdown cũng là nơi thích hợp để bắt đầu một nét vẽ mới. Để thực hiện việc này, hãy tạo một thực thể của HandwritingStroke. Ngoài ra, bạn nên lưu trữ thời gian hiện tại làm điểm tham chiếu cho các điểm tiếp theo được thêm vào đó:

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

Thêm một điểm

Sau khi tạo nét vẽ, bạn nên thêm trực tiếp điểm đầu tiên vào nét vẽ đó. Vì bạn sẽ thêm nhiều hơn điểm sau này, bạn nên triển khai logic tạo điểm theo một phương thức riêng. Trong ví dụ sau đây: phương thức addPoint() tính thời gian đã trôi qua từ dấu thời gian tham chiếu. Thông tin tạm thời là không bắt buộc, nhưng có thể cải thiện chất lượng nhận dạng. Sau đó, hệ thống sẽ đọc X và Toạ độ Y từ sự kiện con trỏ và thêm điểm vào nét vẽ hiện tại.

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

Trình xử lý sự kiện pointermove được gọi khi con trỏ di chuyển trên màn hình. Số điểm đó cũng cần được thêm vào nét vẽ. Sự kiện cũng có thể được tạo ra nếu con trỏ không nằm trong một "down" (xuống) trạng thái, ví dụ: khi di chuyển con trỏ qua màn hình mà không nhấn chuột . Trình xử lý sự kiện trong ví dụ sau sẽ kiểm tra xem có nét vẽ đang hoạt động hay không và thêm phương thức điểm mới vào ứng dụng đó.

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

Nhận dạng văn bản

Khi người dùng nhấc con trỏ lên lại, bạn có thể thêm nét vẽ vào bản vẽ bằng cách gọi addStroke(). Ví dụ sau đây cũng đặt lại activeStroke, vì vậy, pointermove trình xử lý sẽ không thêm điểm vào nét vẽ đã hoàn tất.

Tiếp theo, đã đến lúc nhận dạng hoạt động đầu vào của người dùng bằng cách gọi phương thức getPrediction() trên bản vẽ. Quá trình nhận dạng thường mất chưa đến vài trăm mili giây nên bạn có thể liên tục chạy các dự đoán nếu cần. Ví dụ sau đây chạy một thông tin dự đoán mới sau mỗi lần vẽ xong nét vẽ.

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));
});

Phương thức này trả về một hàm hứa hẹn phân giải bằng một loạt các dự đoán được sắp xếp theo khả năng. Số lượng phần tử phụ thuộc vào giá trị bạn đã chuyển đến gợi ý alternatives. Bạn có thể sử dụng mảng này để hiển thị cho người dùng một lựa chọn các kết quả phù hợp có thể có và yêu cầu họ chọn một . Ngoài ra, bạn chỉ cần chọn dự đoán có khả năng xuất hiện nhất, đó là việc tôi làm trong ví dụ:

Đối tượng dự đoán chứa văn bản được nhận dạng và kết quả phân đoạn không bắt buộc. Tôi sẽ thảo luận trong phần sau.

Thông tin chi tiết kèm theo kết quả về phân đoạn

Nếu được nền tảng mục tiêu hỗ trợ, đối tượng dự đoán cũng có thể chứa kết quả phân đoạn. Đây là một mảng chứa tất cả đoạn chữ viết tay đã nhận dạng, kết hợp của những đoạn ký tự có thể nhận dạng người dùng (grapheme) cùng với vị trí của ký tự đó trong văn bản được công nhận (beginIndex, endIndex) cũng như các nét vẽ và điểm tạo ra hàm đó.

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);
      });
    },
  );
}

Bạn có thể dùng thông tin này để theo dõi lại các đồ thị được nhận dạng trên canvas.

Các hộp được vẽ xung quanh mỗi biểu đồ được nhận dạng

Nhận dạng toàn bộ

Sau khi quá trình ghi nhận hoàn tất, bạn có thể giải phóng tài nguyên bằng cách gọi phương thức clear() trên HandwritingDrawing và phương thức finish() trên HandwritingRecognizer:

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

Bản minh hoạ

Thành phần web <handwriting-textarea> sẽ triển khai một được cải tiến dần, chế độ kiểm soát chỉnh sửa có khả năng viết tay nhận dạng cá nhân. Bằng cách nhấp vào nút ở góc dưới bên phải của chế độ điều khiển chỉnh sửa, bạn sẽ kích hoạt chế độ vẽ. Khi bạn hoàn tất bản vẽ, thành phần web sẽ tự động khởi động nhận dạng và thêm văn bản đã được nhận dạng trở lại chế độ điều khiển chỉnh sửa. Nếu tính năng Nhận dạng chữ viết tay API hoàn toàn không được hỗ trợ hoặc nền tảng không hỗ trợ các tính năng được yêu cầu, nút chỉnh sửa sẽ bị ẩn. Tuy nhiên, chế độ điều khiển chỉnh sửa cơ bản vẫn có thể dùng làm <textarea>.

Thành phần web cung cấp các thuộc tính và thuộc tính để xác định hành vi nhận dạng từ bên ngoài, bao gồm languagesrecognitiontype. Bạn có thể đặt nội dung kiểm soát thông qua Thuộc tính value:

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

Để nhận thông báo về mọi thay đổi đối với giá trị, bạn có thể theo dõi sự kiện input.

Bạn có thể thử thành phần này qua bản minh hoạ này trên Glitch. Ngoài ra, hãy nhớ xem mã nguồn. Để sử dụng tính năng kiểm soát trong ứng dụng của bạn, lấy từ npm.

Tính bảo mật và quyền truy cập

Nhóm Chromium đã thiết kế và triển khai API Nhận dạng chữ viết tay bằng cách sử dụng các nguyên tắc cốt lõi được xác định trong Kiểm soát quyền truy cập vào các tính năng nền tảng web mạnh mẽ, bao gồm cả người dùng khả năng kiểm soát, tính minh bạch và tính công thái học.

Quyền kiểm soát của người dùng

Người dùng không thể tắt API Nhận dạng chữ viết tay. Tính năng này chỉ dành cho các trang web được phân phối qua HTTPS và chỉ có thể được gọi từ ngữ cảnh duyệt web cấp cao nhất.

Sự minh bạch

Không có chỉ báo cho biết liệu tính năng nhận dạng chữ viết tay có đang hoạt động hay không. Để ngăn tạo vân tay số, trình duyệt triển khai các biện pháp đối phó, chẳng hạn như hiển thị lời nhắc cấp quyền cho người dùng khi phát hiện thấy hành vi sai trái có thể xảy ra.

Khả năng lưu trữ cố định quyền

API Nhận dạng chữ viết tay hiện không hiển thị bất kỳ lời nhắc cấp quyền nào. Do đó, quyền không cần phải duy trì theo bất kỳ cách nào.

Phản hồi

Nhóm Chromium muốn tìm hiểu về trải nghiệm của bạn với API Nhận dạng chữ viết tay.

Cho chúng tôi biết về thiết kế API

Có điều gì về API không hoạt động như bạn mong đợi không? Hoặc có phương thức nào bị thiếu hoặc thuộc tính nào bạn cần để triển khai ý tưởng của mình? Có câu hỏi hoặc nhận xét về bảo mật mẫu? Báo cáo vấn đề về thông số kỹ thuật trên kho lưu trữ GitHub tương ứng hoặc thêm ý kiến của bạn vào một vấn đề hiện tại.

Báo cáo sự cố về triển khai

Bạn có phát hiện lỗi trong quá trình triển khai Chromium không? Hay cách triển khai có khác với thông số kỹ thuật không? Báo cáo lỗi tại new.crbug.com. Hãy nhớ cung cấp càng nhiều thông tin chi tiết càng tốt, các hướng dẫn đơn giản để tái tạo rồi nhập Blink>Handwriting vào hộp Components (Thành phần). Glitch rất hữu ích khi chia sẻ các bản dựng lại nhanh chóng và dễ dàng.

Hiện thông tin hỗ trợ về API này

Bạn có định sử dụng API Nhận dạng chữ viết tay không? Sự hỗ trợ công khai của bạn giúp ích cho nhóm Chromium ưu tiên các tính năng và cho các nhà cung cấp trình duyệt khác biết tầm quan trọng của việc hỗ trợ các tính năng đó.

Chia sẻ cách bạn dự định sử dụng tài khoản này trên chuỗi bài thuyết trình về WICG. Gửi bài đăng tới @ChromiumDev bằng cách sử dụng hashtag #HandwritingRecognition đồng thời cho chúng tôi biết bạn đang sử dụng ở đâu và như thế nào.

Xác nhận

Bài viết này do Joe Medley, Honglin Yu và Jiewei Qian đánh giá. Hình ảnh chính của Samir Bouaked bật Không hiển thị màn hình.