Detect ký tự trong hình ảnh
Đọc ký tự trong văn bản trong một khung cảnh thiên nhiên là một phần quan trọng của nhiều tác vụ thị giác máy tính (Computer Vision-CV). Ví dụ, việc thực hiện nhận dạng ký tự quang học (Optical Character Recognition-OCR) các thuật toán có thể được cải thiện bằng cách đầu tiên xác định các khu vực ...
Đọc ký tự trong văn bản trong một khung cảnh thiên nhiên là một phần quan trọng của nhiều tác vụ thị giác máy tính (Computer Vision-CV). Ví dụ, việc thực hiện nhận dạng ký tự quang học (Optical Character Recognition-OCR) các thuật toán có thể được cải thiện bằng cách đầu tiên xác định các khu vực của văn bản trong hình ảnh. Phát hiện văn bản trong những cảnh thiên nhiên là một lĩnh vực nghiên cứu chuyên sâu và có rất nhiều cách tiếp cận để giải quyết vấn đề này: sử dụng opencv, swt, swt kết hợp cùng opencv trong bài viết này mình sẽ giới thiệu về cách sử dụng swt(stroke awidth transform)
1. SWT (Stroke Width Transform)
Được công bố năm 2010 bởi 3 tác giả Boris Epshtein, Eyal Ofek và Yonatan Wexler. Công trình khoa học này đã được Thuật toán này còn khá mới mẻ đối với giới xử lý ảnh. SWT là thuật toán dựa trên phép biến đổi về bề rộng chữ. Điều này có nghĩa là ta có thể phát hiện được vùng ký tự của các các ngôn ngữ khác nhau một cách dễ dàng mà không đòi hỏi phải cho máy học trước với lượng database lớn.
1.1 Biến đổi bề rộng nét chữ (SWT)
Phần này sẽ mô tả thuật toán chuyển đổi bề rộng nét chữ. Thuật toán nhận được một hình ảnh RGB và trả về một hình ảnh có cùng kích thước. Gồm có 3 bước chính:
- Biến đổi bề rộng của nét chữ.
- Nhóm các điểm ảnh vào các kí tự có thể dựa trên bề rộng nét chữ.
- Nhóm các kí tự đó vào vùng văn bản.
1.2. Loại bỏ một số dòng từ bản đồ bề rộng nét chữ (SW-Map)
Các ký tự trong hình ảnh kết nối với nhau nhiều lần và thuật toán nhận một nhóm các kí tự như một thành phần duy nhất. Vì các tính chất của một nhóm các ký tự không nhất thiết phải phù hợp với các tính chất của một ký tự duy nhất, các thành phần này có thể bị bỏ trong các giai đoạn tiếp theo. Khi xem xét các bước của thuật toán, ta nhận thấy rằng các thuật toán SW trả về nhiều dòng rải rác kết nối các chữ cái với nhau. Sau khi loại bỏ dòng như vậy thì những kí tự này không còn được coi là một phần của các thành phần tương tự. Vì vậy, việc thêm một bước mà các thuật toán đi qua mỗi điểm ảnh, và nếu vùng lân cận của nó không chứa đủ điểm ảnh từ các thành phần của nó, điểm ảnh đó được xóa khỏi các thành phần.
2. SWT với python
Để sử dụng swt với python ta cần thực hiện 1 số bước như sau:
- clone repo https://github.com/liuliu/ccv
- cài swig: sudo apt-get install swig
- tạo file ccvwrapper.i trong thư mục ccv/lib:
%module ccvwrapper %{ #include "ccvwrapper.h" %} %typemap(out) int* swt { int i; $result = PyList_New($1[0]); for(i = 0; i < $1[0]; i++){ PyObject *o = PyInt_FromLong($1[i+1]); PyList_SetItem($result, i, o); } free($1); } %include "ccvwrapper.h"
- build wrapper file
swig -python ccvwrapper.i gcc -fpic -c ccvwrapper.c ccvwrapper_wrap.c ccv_algebra.c ccv_basic.c ccv_cache.c ccv_classic.c ccv_io.c ccv_memory.c ccv_output.c ccv_resample.c ccv_sift.c ccv_swt.c ccv_transform.c ccv_util.c ./3rdparty/sha1/sha1.c -I/usr/include/python2.7 ld -shared ccvwrapper.o ccvwrapper_wrap.o ccv_algebra.o ccv_basic.o ccv_cache.o ccv_classic.o ccv_io.o ccv_memory.o ccv_output.o ccv_resample.o ccv_sift.o ccv_swt.o ccv_transform.o ccv_util.o sha1.o -ljpeg -o _ccvwrapper.so
- coppy file ccvwrapper về folder code hoặc để LD_LIBRARY_PATH đến folder ccv/lib
3. Demo
Ở đoạn code này mình hoàn toàn dùng cwt để detect cái ký tự trong hình ảnh, chỉ dùng skimage để mở, lư ảnh và vẽ vùng kết quả lên ảnh
from __future__ import print_function import ccvwrapper import numpy as np from skimage import draw from skimage.io import imread, imshow, imsave from matplotlib import pyplot as plt def rectangle_perimeter(r0, c0, awidth, height, shape=None, clip=False): rr, cc = [r0, r0 + awidth, r0 + awidth, r0], [c0, c0, c0 + height, c0 + height] return draw.polygon_perimeter(rr, cc, shape=shape, clip=clip) if __name__ == "__main__": image_name = "test.jpg" bytes = open(image_name, "rb").read() swt_result_raw = ccvwrapper.swt(bytes, len(bytes), 1024, 1360) swt_result = np.reshape(swt_result_raw, (len(swt_result_raw) / 4, 4)) image = imread(image_name, as_grey=False) for x, y, awidth, height in swt_result: for i in xrange(0, 3): # just to make lines thicker rr, cc = rectangle_perimeter(y + i, x + i, height, awidth, shape=image.shape, clip=True) image[rr, cc] = (255, 0, 0) imshow(image) imsave("result.jpg", image) plt.show()
Đây là kết quả mình đã thử