Tìm hiểu về OCR, xây dựng chức năng Extract text từ hình ảnh sử dụng PHP

OCR.jpg

How to extract text from images ?

Chào mọi người, hôm nay mình sẽ giới thiệu cách làm thế nào để có thể đọc được text từ hình ảnh có sẵn. Trước tiên đi vào thực hiện (code) mình sẽ trình bày sơ qua về cái mà mình sẽ sử dụng đó là công nghệ nhận dạng ký tự quang học OCR. Vậy thì OCR là gì ???

1. Khái niệm

OCR là một thuật ngữ viết tắt từ cụm từ Optical Character Recognition có thể dịch nôm na nó là Nhận dạng ký tự bằng quang học. Đây là công nghệ được áp dụng để đọc text trên một file ảnh thành định dạng text.

2. Ứng dụng

Chắc hẳn các bạn đã một lần sử dụng đến công nghệ nhưng không để ý, vì chúng ta chỉ sử dụng nó một cách gián tiếp đó là máy Scanner. OCR được ứng dụng như một phần mềm được tích hợp trên máy tính hoặc trực tiếp vào một phần cứng nào đó. Một số phần mềm khá nổi tiếng như:

Trong số những phần mềm đó thì mình nghĩ ABBYY FineReader là phần mềm tốt nhất, đơn giản vì thời sinh viên mình rất hay dùng phần mềm này để convert những file PDF sang word để copy cho nhanh đỡ phải gõ lại (haha)

3. Hạn chế của OCR

Bên cạnh đó thì OCR cũng còn khá nhiều những hạn chế như:

  • Hầu hết các phần mềm sử dụng OCR chỉ nhận dạng được khoảng 80 - 90% trên hình ảnh rõ nét.
  • Đối với những hình ảnh có màu nền mà màu chữ không có nhiều chênh lệch, hay các hình chụp chữ viết tay thì kết quả nhận dạng không khả quan cho lắm
  • Đến thời điểm hiện tại thì OCR chưa support tất cả các ngôn ngữ.

4. Xây dựng demo chức năng Extract text from Image sử dụng OCR

Mình sẽ code demo chắc năng này với CakePHP và sử dụng IDOL OCR API (A.hihi)

IDOL OCR API là gì thì mình xin giới thiệu nhanh, nó là một web-service và bạn có thể dử dụng service này ở nhiều ngôn ngữ như PHP , Java , .NET , Python,…etc. Còn trong khuôn khổ bài viết này thì mình sẽ sử dụng ngôn ngữ PHP =)) IDOL OCR API support những format sau:

- Image Formats
  • TIFF
  • JPEG
  • PNG
  • GIF
  • BMP and ICO
  • PBM, PGM, and PPM
- Document Formats
  • Adobe PDF (PDF)
  • Microsoft Word Documnent (DOC and DOCX)
  • Microsoft Excel Sheet (XLS and XLSX)
  • Microsoft Powerpoint Presentation (PPT and PPTX)
  • OpenDocument Text (ODT)
  • Rich Text (RTF)

Để sử dụng service này thì việc cần làm những bước sau

Bước 1

Đăng ký một tài khoản tại đây

Bước 2

Đăng nhập và copy API Key tại đây Selection_026.png

Xong 2 bước trên bạn đã có thể sử dụng service này rồi, bạn có thể sử dụng web service này với cả phương thức POST và GET, còn trong demo này mình sẽ sử dụng phương thức POST thôi nhóe!

Lý thuyết nhiều rồi, nào! bây giờ là lúc các bạn bắt tay vào thực hiện một chức năng để hiểu được những gì mình đã giới thiệu bên trên. Tất cả những thứ bạn cần làm là 1 action và một view thể hiện giao diện của action đó.

View: TopPages/extract_text_from_images.ctp


<div class="row">
    <div class="container">
        <form class="form-group" action="" method="post" enctype="multipart/form-data">
            <div class="col-md-4">
                <?php if ($image) { ?>
                <div class="row">
                <label>Extracted text from Image</label>
                    <div class="col-md-12">
                        <img src="<?php echo $image ;?>" class="img-rounded img-responsive"/>
                    </div>
                </div>
                <?php } ?>
                <div class="row">
                    <label>Select file:</label>
                    <input type="file" name="file" class="form-control" />
                </div>
                <div class="row">
                    <label>Select mode</label>
                    <select class="form-control" name="mode">
                        <option value="subtitle">Subtitle</option>
                        <option value="scene_photo">Scene_photo</option>
                        <option value="document_scan">Document_scan</option>
                        <option value="document_photo">Document_photo</option>
                    </select>
                </div>
                <div class="row">
                    <br/>
                    <input type="submit" value="Extract" class="btn btn-primary form-control"/>
                </div>
            </div>
            <div class="col-md-4">
                <label> 科目</label>
                <input type="text" name="subject" value="<?php echo $subject; ?>" class="form-control" />
                <label> 技能士番号</label>
                <input type="text" name="skills" class="form-control" value="<?php echo $skillNumber; ?>" />
                <br/>
                <textarea class="form-control" rows="15" placeholder="Result"><?php echo $scanOCR; ?></textarea>
            </div>
        </form>
    </div>
</div>

Để thực hiện extract text from image, mình cần 1 input để chọn ảnh, 1 box để hiển thị ảnh, một select box để hiển thị các chế độ (mode) ứng với từng hình ảnh và một nút submit. Ý nghĩa của các mode như sau, mình xin copy nguyên tài liệu để tránh dịch sai ý nghĩ gốc của nó

  • document_photo: (default) Use to recognize text in a document that has been digitized with variable light, such as through a mobile phone camera.

  • document_scan: Use to recognize text in a document that has been digitized with constant lighting, such as through a flatbed scanner.

  • scene_photo: Use to recognize text in a scene, for example signs and billboards in a landscape.

  • subtitle: Use to recognize text superimposed on an image, such as TV subtitles.

Ứng với từng mode thì text được extract ra hình ảnh là khác nhau, ở đây mình chọn mode là subtitle bời vì hầu hết các hình ảnh mình thực hiện đề có dạng văn bản chồng lên hình ảnh 😃 Bạn có thể tìm hiểu rõ hơn https://dev.havenondemand.com/apis/ocrdocument#overview.

Controllers/TopPages/extractTextFromImages

public function extractTextFromImages() {
    $urlApi = 'http://api.havenondemand.com/1/api/sync/ocrdocument/v1?apikey=' .
    APIKEY_HAVENONDEMAND . '&languages=en&languages=ja';
    $output_dir = 'img/';
    $subject = $skillNumber = $scanOCR = $image = '';
    if(isset($_FILES['file'])) {
        $fileName = $_FILES['file']['name'];
        $image = $fileName;
        move_uploaded_file($_FILES['file']['tmp_name'], $output_dir . $fileName);
        $filePath = realpath($output_dir . $fileName);
        $post = [
            'file' =>'@' . $filePath,
            'mode' => $this->request->data['mode']
        ];
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $urlApi);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $result=curl_exec ($ch);
        curl_close ($ch);
        $data = json_decode($result);
        $scanOCR = isset($data->text_block[0]->text) ? $data->text_block[0]->text : '';
        if ($scanOCR != ''){
            $subjectStart = strpos($scanOCR, '目');
            $subjectEnd = strpos($scanOCR, '技能士番号') - $subjectStart;
            $skillStart = strpos($scanOCR, '号');
            $skillEnd = strpos($scanOCR, '格') - $skillStart;
            $subject = ltrim(substr($scanOCR, $subjectStart, $subjectEnd), '目 ');
            $skillNumber = ltrim(substr($scanOCR, $skillStart, $skillEnd), '号 ');
        }
    }
    $this->set(compact(array('subject', 'skillNumber', 'scanOCR', 'image')));
}

Ờ đây, do mình sử dụng API cung cấp của bên thứ 3 nên chúng là cần dùng CURL để post dữ liệu tới web-service đó và nằm đợi kết quả trả về. Biến $urlApi chính là địa chỉ chúng ta sẽ gửi đến thông qua CURL, nơi mà bạn cần đăng ký apikey tại đó. Mặc định nếu bạn không ghi gì thì ngôn ngữ support mặc định bạn sẽ đước support mặc định bới IDOL OCR API sẽ là tiếng anh. Chúng ta có thể add thêm ngôn ngữ qua việc add thêm param languages trên URL. Trong ví dụ này mình sẽ sử dụng add thêm Tiếng Anh và Tiếng Nhật

PHP
$urlApi = 'http://api.havenondemand.com/1/api/sync/ocrdocument/v1?apikey=' . APIKEY_HAVENONDEMAND . '&languages=en&languages=ja';

Cho tới này IDOL OCR API service đã hỗ trợ khá nhiều ngôn ngữ bạn có thể tìm hiểu thêm Supported Languages

PHP
$post = [
    'file' =>'@' . $filePath,
    'mode' => $this->request->data['mode']
];

Sau khi upload hình ảnh lên server, bạn sẽ put đường dẫn đó vào $post để gửi đi. Bạn sẽ nhận được kết quả trả về khi HAVENONDEMAND return data.

PHP
$data = json_decode($result);
$scanOCR = isset($data->text_block[0]->text) ? $data->text_block[0]->text : '';
if ($scanOCR != ''){
    $subjectStart = strpos($scanOCR, '目');
    $subjectEnd = strpos($scanOCR, '技能士番号') - $subjectStart;
    $skillStart = strpos($scanOCR, '号');
    $skillEnd = strpos($scanOCR, '格') - $skillStart;
    $subject = ltrim(substr($scanOCR, $subjectStart, $subjectEnd), '目 ');
    $skillNumber = ltrim(substr($scanOCR, $skillStart, $skillEnd), '号 ');
}

Đoạn code này là cách mình xử lý dữ liệu trả về để hiện ra form. Bạn hoàn toàn không cần sử dụng đoạn code naỳ mà có thể xử lý theo cách của riêng bạn. Đã xong, và đây là kết quả mà chúng ta sẽ nhận được good.png

**Chú ý: ** Hàng tháng,havenondemand cho bạn gửi 5000 requests miến phí, nếu bạn muộn unlimit vui lòng Liên hệ để được hỗ trợ

5. Kết thúc

Cảm ơn bạn đã xem bài viết của mình, trên đây chỉ là chút kiến thức mình đã tìm hiểu và chia sẻ lại, rất mong nhận được sự góp ý của bạn để giúp mình có thể hoàn thiện hơn. (thankyou)

6. Tài liệu tham khảo

All Rights Reserved