Một số phép xử lý trong OpenCV

Một phần của tài liệu (LUẬN văn THẠC sĩ) ứng dụng xử lý ảnh trong việc nhận dạng và trích xuất thông tin, dữ liệu trong các tờ hóa đơn bán hàng (Trang 34 - 44)

Chương 3 : CÔNG CỤ

3.1 Mã nguồn mở thị giác máy (OpenC V– Open Source Computer Vision)

3.1.2 Một số phép xử lý trong OpenCV

3.1.2.1 Đọc ảnh, hiển thị và lưu ảnh

Đọc ảnh:

Cú pháp: image = cv2.imread("tham số")

Để đọc file ảnh thành một mảng NumPy, chúng ta sử dụng hàm

cv2.imread() với với tham số là đường dẫn của hình ảnh. Sau bước này, ta nhận

được một mảng NumPy là image. Mảng Numpy chứa các thơng số về file ảnh, gồm có chiều dài, chiều rộng và số kênh. Cách NumPy lưu các thông số về bức ảnh:

Một bức ảnh có 2 chiều X và Y, gốc toạ độ tại pixel trên cùng bên trái của bức ảnh. Chiều X từ trái sang phải và chiều Y từ trên xuống dưới. NumPy lưu số pixel: image.shape[0] là số pixel theo chiều Y và image.shape[1] là số pixel theo chiều X.

Mỗi pixel trên bức ảnh được biểu thị dưới một trong 2 dạng: Xám (grayscale) hoặc dạng ảnh màu (color). Thông số image.shape[2] lưu số kênh biểu thị mỗi pixel. Với ảnh màu hiển thị trên RGB thì số kênh là 3, cịn với ảnh xám (grayscale) chúng ta chỉ có 1 channel duy nhất.

Hiển thị ảnh:

Cú pháp: cv2.imshow("Tên hiển thị", image)

Hàm cv2.imshow() là hàm hiển thị hình ảnh ra một cửa sổ với các tham số: Tên hiển thị được đặt trong dấu " " để đặt tên cho cửa sổ hình ảnh. Tham số image là một mảng Numpy chứa các thông số của 1 file ảnh.

Ngoài ra để hiển thị ảnh mà người xem có thể nhìn thấy được hình ảnh cần có một thời gian chờ để ảnh hiển thị trên màn hình. Để khai báo thời gian chờ ta dùng lệnh cv2.waitKey(time) ở đây tham số time là thời gian chờ tính theo đơn vị mili giây và hiển thị hình ảnh trong thời gian này. Để hình ảnh hiển thị trên màn hình mãi mãi ta đặt tham số thời gian bằng 0 cv2.waitKey(0).

Ngồi ra ta cũng có thể hiển thị một số thơng tin cần thiết về một hình ảnh ví dụ như chiều dài, chiều rộng, số pixel, giá trị màu tại một điểm ảnh qua lệnh print.

Ví dụ: Hiển thị thơng tin về kích thước của hình ảnh: print image.shape[0] (Hiển thị chiều dài ảnh) print image.shape[1] (Hiển thị chiều cao ảnh) ❖ Lưu ảnh:

Cú pháp: cv2.imwrite("Tên.định dạng", image)

Hàm cv2.imwrite() là hàm lưu hình ảnh sau khi tiến hành một số thao tác chỉnh sửa hình ảnh. Với các tham số: là tên và định dạng mới của hình ảnh được đặt trong dấu " " và tham số image là một mảng Numpy chứa các thông số của 1 file ảnh cần lưu.

3.1.2.2 Chuyển đổi giữa các không gian màu

Để chuyển đổi giữa các không gian màu ta sử dụng hàm cv2.cvtColor(). Với các tham số: image là một mảng Numpy chứa thông số ảnh gốc cần chuyển,

cv2.COLOR_BGR2GRAY là tham số chọn khơng gian màu để chuyển đổi ví dụ

như trong cú pháp mẫu này ta chuyển đổi không gian màu RGB sang không gian màu xám và kết quả chuyển đổi được lưu trong một mảng Numpy được đặt tên là

gray.

Ta có thể chuyển đổi giữa các không gian khác bằng cách thay đổi thông số chọn không gian màu chuyển đổi như: Chuyển đổi từ RGB sang HSV ta đặt tham số lựa chọn là cv2.COLOR_BGR2HSV, từ RGB sang CMYK ta đặt tham số lựa chọn là cv2.COLOR_BGR2CMYK…

3.1.2.3 Ảnh nhị phân và ngưỡng

Ảnh nhị phân là ảnh mà giá trị của các điểm ảnh chỉ được biểu diễn bằng hai giá trị 0 hoặc 255 tương ứng với hai màu đen hoặc trắng. Để chuyển đổi một ảnh xám sang ảnh nhị phân ta dựa vào một giá trị ngưỡng T với phương pháp chuyển tất cả các điểm ảnh có giá trị mức xám nhỏ hơn hoặc bằng ngưỡng T thành giá trị 0 ứng với màu đen ( f(x,y) ≤ T  f(x,y) = 0) và ngược lại những điểm ảnh có giá trị

mức xám lớn hơn ngưỡng T thì chuyển thành giá trị 255 ứng với màu trắng ( f(x,y) > T  f(x,y) = 255).

Trong OpenCV hỗ trợ hàm cv2.threshold để chuyển ảnh xám sang ảnh nhị

phân với cú pháp:

(T, thresh) = cv2.threshold(image, Tin, Tout, cv2.THRESH_BINARY) Với các tham số: image là mảng Numpy chứa thông số của hình ảnh, Tin là

ngưỡng ta nhập vào để chuyển đổi ảnh xám thành ảnh nhị phân, Tout là giá trị mức xám được thay đổi giá trị điểm ảnh lớn hơn ngưỡng T (Ví dụ: ta đặt Tout = 250 thì các điểm ảnh có giá trị mức xám lớn hơn T thì sẽ chuyển thành 250).

cv2.THRESH_BINARY là tham số lựa hình thức để so sánh giá trị điểm ảnh với ngưỡng với hai giá trị là:

- cv2.THRESH_BINARY: Được gọi là nhị phân hóa thuận (f(x,y) ≤ T

f(x,y) = 0 và f(x,y) > T  f(x,y) = Tout)

- cv2.THRESH_BINARY_INV: Được gọi là nhị phân hóa nghịch (f(x,y) ≤ T

Và kết quả được lưu với 2 thông số là: Ngưỡng T là ngưỡng để chuyển đổi ảnh xám thành ảnh nhị phân trong trường hợp này T = Tin. Và một mảng Numpy được đặt tên là thresh chứa thông tin của ảnh nhị phân sau khi được chuyển đổi.

Ngoài ra, ta cịn có một số phương pháp xác định ngưỡng tự động ví dụ như phương pháp Otsu và phương pháp ngưỡng thích nghi (Adaptive Threshold):

Phương pháp Otsu:

Đây là phương pháp xác định ngưỡng dựa trên biểu đồ (Histograms) mức xám. Với cú pháp:

(T, thresh) = cv2.threshold(image, Tin, Tout, cv2.THRESH_BINARY | cv2.THRESH_OTSU)

Với các tham số giống như trong phương pháp nhị phân hóa dạng tổng quát đã đề cập ở trên với chút thay đổi là: tham số Tin trong trường hợp này là tham số "don’t care" tức là giá trị Tin khơng có ảnh hưởng tới kết quả ngưỡng xác định bằng phương pháp Otsu ngoài ra ta thêm một tham số nữa là cv2.THRESH_OTSU là tham số lựa chọn phương pháp lấy ngưỡng ở đây là phương pháp Otsu.

Phương pháp ngưỡng thích nghi (Adaptive Threshold):

Đây là phương pháp xác định ngưỡng dựa trên dựa trên những điểm ảnh lân cận nhau bằng cách xác định một cửa sổ chứa hình ảnh và ngưỡng theo từng vùng. Với cú pháp:

thresh = cv2.adaptiveThreshold(image, Tout,

cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, wx, wy) Với phương pháp này ta sử dụng hàm cv2.adaptiveThreshold các tham số

image, Tout và cv2.THRESH_BINARY giống như trong phương pháp nhị phân

hóa dạng tổng quát đã đề cập ở trên. Và một số tham số khác như:

cv2.ADAPTIVE_THRESH_MEAN_C là tham số lựa chọn phương pháp như ở đây ta lựa chọn phương pháp lấy ngưỡng bằng trung bình cộng các giá trị điểm ảnh có trong cửa sổ. Ngồi ra, ta cịn có phương pháp lấy trung bình Gaussian bằng cách đặt tham số lựa chọn phương pháp là cv2.ADAPTIVE_THRESH_GAUSSIAN_C, hai tham số wx và wy là tham số đặt kích thước của cửa sổ để tính ngưỡng. Do phương pháp này có thể cho ngưỡng khác nhau ứng với mỗi pixel nên kết quả chỉ trả về mảng thresh.

3.1.2.4 Histogram và cân bằng histogram

Histogram của một ảnh là một biểu đồ nói lên mối quan hệ giữa các giá trị của pixel ảnh (điểm ảnh) và tần suất xuất hiện của chúng. Nhìn vào biểu đồ histogram ta có thể đốn được một ảnh sáng tối như thế nào.

Nếu một ảnh có histogram lệch về phía phải biểu đồ, ta nói ảnh đó thừa sáng. Nếu lệch về phía trái thì ảnh đó thiếu sáng. Hình bên dưới mơ tả histogram của một ảnh xám, ảnh này có histogram lệch về phía trái của biểu đồ và do đó ảnh này là khá tối. Đối với ảnh màu, ta có thể tính tốn histogram cho từng kênh màu một.

Hình 3.1: Biểu đồ histogram của ảnh xám Hàm tính tốn histogram có cú pháp:

hist = cv2.calcHist(image, kênh, mặt nạ, kích thước, phạm vi) Trong đó có các tham số image là mảng Numpy chứa thông tin ảnh, kênh là danh sách kênh cần tính tốn histogram, với một ảnh xám chỉ có một kênh nên danh sách là [0] và với ảnh màu RGB có ba kênh nên danh sách sẽ là [0,1,2], mặt nạ là tham số được cung cấp để chỉ tính histogram cho những pixel trong mặt nạ, khi không sử dụng mặt nạ thì ta đặt giá trị tham số này làn none, kích thước là tham số cho thấy thơng tin số ngăn chứa giá trị của biểu đồ, phạm vi là tham số chỉ mức độ dao động của giá trị các điểm ảnh ở đây giả sử ta cho phạm vi dao động từ [0 – 255] thì ta cần đặt tham số là [0 – 256] vì giá trị 256 là giá trị khơng bao gồm nên không được xét đến và được bỏ qua.

Cân bằng histogram

Cân bằng histogram (histogram equalization) là phương pháp làm cho biểu đồ histogram của ảnh được phân bố một cách đồng đều. Đây là một biến đổi khá quan

trọng giúp nâng cao chất lượng ảnh, thông thường đây là bước tiền xử lý cho hình ảnh vào cho các bước tiếp theo.

Để cân bằng histogram ta sử dụng hàm cv2.equalizeHist().

3.1.2.5 Dị biên[12]

Việc tìm biên cho ta xác định được đường bao của các đối tượng. Cú pháp:

void findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point())

Các thông số:

Image: Là ảnh ngõ vào, yêu cầu là ảnh đơn kênh 8 bit. Các điểm ảnh không bằng không được gán là 1 và các điểm ảnh bằng 0 được gán là 0, vì vậy ảnh ngõ vào được coi là một ảnh nhị phân. Ta có thể sử dụng các phương pháp phân đoạn ảnh để chuyển ảnh thành ảnh nhị phân.

Contours: Là kết quả đường bao thu được và được lưu dưới dạng vector điểm Hierarchy: Vectơ tùy chọn ngõ ra, chứa thông tin về topo hình ảnh. Nó có nhiều yếu tố như số lượng các đường viền, Đối với mỗi đường viền thứ i contours[i], các thành phần hierarchy[i][0], hiearchy[i][1], hiearchy[i][2] và hiearchy[i][3] được thiết lập chỉ số từ 0 và dựa trên các chỉ số trong contours để ta phân cấp đường viền theo các cấp bậc tương ứng. Nếu đối với đường viền i khơng có cạnh liền kề trước hoặc sau nó thì các yếu tố tương ứng hierarchy[i] sẽ là âm.

Mode: Các chế độ để tìm biên

- CV_RETR_EXTERNAL: Chế độ này chỉ lấy ra các đường bao ngoài

- CV_RETR_LIST: lấy tất cả các đường bao mà không cần thiết lập bất kỳ

mối quan hệ phân cấp nào

- CV_RETR_CCOMP: lấy ra tất cả các đường bao và sắp xếp chúng thành hệ thống phân cấp hai cấp. Ở cấp cao nhất, có các đường bao bên ngồi của các phần tử. Ở cấp độ thứ hai, có những đường bao của các lỗ trống. Nếu có một đường bao bên trong một lỗ của một phần tử có liên kết, nó vẫn nằm ở mức cao nhất.

- CV_RETR_TREE lấy tất cả các đường bao và tái tạo lại toàn bộ thứ bậc của

các đường bao lồng nhau

Method: Các phương pháp xấp xỉ đường bao

- CV_CHAIN_APPROX_SIMPLE: Nén các đoạn thằng theo chiều ngang,

dọc, và chéo lại chỉ giữ lại các điểm đầu cuối. Ví dụ, một đường bao hình chữ nhật sẽ được mã hoá thành 4 điểm

- CV_CHAIN_APPROX_TC89_L1, CV_CHAIN_APPROX_TC89_KCOS:

Áp dụng một trong những ưu điểm của thuật tốn xấp xỉ Teh-Chin.

3.1.2.6 Biến đổi hình thái

Phép biến đổi hình thái là một số thao tác đơn giản dựa trên hình dạng hình ảnh. Nó thường được thực hiện trên các hình ảnh nhị phân. Nó cần hai ngõ vào, một là hình ảnh ban đầu của chúng ta, thứ hai được gọi là cấu trúc phần tử (structuring element) hoặc hạt nhân (kernel) quyết định bản chất của hoạt động. Có hai phép biến đổi hình thái cơ bản là Erosion and Dilation. Sau đó các biến thể của nó giống như Open, Close, Gradient…

Xói mịn (Erosion)

Ý tưởng cơ bản về xói mịn tương tự như sự xói mịn đất, nó làm xói mịn các đường biên của đối foreground (Ở đây, đối tượng chính ln là màu trắng). Hạt nhân sẽ trượt qua hình ảnh (như trong hội tụ 2D). Một pixel trong ảnh ban đầu (hoặc 1 hoặc 0) sẽ có giá trị là 1 chỉ khi tất cả các điểm ảnh dưới hạt nhân là 1, nếu khơng nó bị ăn mịn (được gán bằng khơng).

Vì vậy, tất cả các điểm ảnh gần biên sẽ được loại bỏ tùy thuộc vào kích thước của hạt nhân. Vì vậy, độ dày hoặc kích thước của foreground chính giảm chỉ đơn giản là vùng trắng trong hình ảnh giảm trong hình ảnh. Nó rất hữu ích để loại bỏ nhiễu trắng nhỏ, tách hai vật thể được liên kết với nhau

Ví dụ, ta sẽ sử dụng một hạt nhân 5x5 với mang giá trị 1:

Giãn nở (Dilation)

Trường hợp này ngược với hình thái xói mịn. Ở đây, một pixel sẽ là '1' nếu ít nhất một điểm ảnh dưới hạt nhân là '1'. Vì vậy, nó làm tăng vùng màu trắng trong hình ảnh hoặc kích thước của foreground tăng lên. Thơng thường, trong trường hợp như loại bỏ nhiễu, sự xói mịn thường được theo sau đó là sự giãn nở. Bởi vì, xói

mịn sẽ làm giảm nhiễu trắng, nhưng cũng làm giảm đối tượng của chúng ta. Vì vậy, ta cần mở rộng nó lại. Vì nhiễu biến mất, chúng sẽ khơng trở lại, nhưng diện tích đối tượng của chúng ta tăng lên. Nó cũng rất hữu ích trong việc nối các phần vỡ của một vật thể.

Mở (Opening)

Hình thái mở chỉ là một tên khác của sự xói mịn tiếp theo đó là sự giãn nở. Nó rất hữu ích trong việc loại bỏ nhiễu, như đã giải thích ở trên. Ở đây, để sử dụng hình thái này chúng ta sử dụng hàm:

morphologyEx ( img , MORPH_OPEN , hạt nhân )

Đóng (Closing)

Hình thái này ngược với hình thái mở nó thực hiện giãn nở trước sau đó xói mịn. Nó rất hữu ích trong việc loại bỏ các điểm đen bên trong đối tượng. Ta sử dụng hàm:

morphologyEx ( img , MORPH_CLOSE, hạt nhân )

Gradient

Hình thái này là hiệu số của hình thái giãn nở và xói mịn. Kết quả sẽ trong như lấy đường bao của đối tượng

Cấu trúc phân tử

Trong OpenCV có hỗ trợ hàm getStructuringElement() để ta xác định dạng cấu trúc phân tử hay hạt nhân để thực hiện biến đổi hình thái.

Ta có một số dạng cấu trúc sau:

- Rectangular Kernel: (Hạt nhân hình chữ nhật)

getStructuringElement (MORPH_RECT , ( 5 , 5 ))

Như ví dụ với cú pháp trên ta có hạt nhân hình chữ nhật có kích thước 5x5 1 1 1 1 1

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

- Elliptical Kernel: (Hạt nhân hình ellipse)

getStructuringElement (MORPH_ELLIPSE , ( 5 , 5 ))

Như ví dụ với cú pháp trên ta có hạt nhân hình elip có kích thước 5x5 0 0 1 0 0

0 1 1 1 0 1 1 1 1 1 0 1 1 1 0 0 0 1 0 0

- Cross-shaped Kernel: (Hạt nhân hình chữ thập)

getStructuringElement ( MORPH_CROSS, ( 5 , 5 ))

Như ví dụ với cú pháp trên ta có hạt nhân hình chữ thập có kích thước 5x5

0 0 1 0 0

0 0 1 0 0

1 1 1 1 1

0 0 1 0 0

Một phần của tài liệu (LUẬN văn THẠC sĩ) ứng dụng xử lý ảnh trong việc nhận dạng và trích xuất thông tin, dữ liệu trong các tờ hóa đơn bán hàng (Trang 34 - 44)