Xin chào các bạn, hôm nay tôi sẽ cùng các bạn tìm hiểu một số phép tính toán số học đơn giản trên ảnh sử dụng thư viện OpenCV nhé
Image Addition
Đây là phép tính cộng hai ảnh vào với nhau, hiểu đơn giản là ảnh thu được sau phép cộng sẽ là kết quả của việc cộng giá trị các pixel tương ứng ở cùng một vị trí của các ảnh thành phần.
img_dst = img1 + img2
. Điều kiện để có thể thực hiện phép cộng là 2 ảnh phải có cùng kích thước và cùng kiểu giá trị biểu diễn các pixel, hoặc ảnh thứ 2 là một ma trận số nguyên.
Lưu ý phép cộng 2 ảnh khác với phép cộng của thư viện numpy Xem ví dụ dưới đây để hiểu sự khác nhau nhé
>>> x = np.uint8([250])
>>> y = np.uint8([10])
>>> print( cv2.add(x,y) ) # 250+10 = 260 => 255
[[255]]
>>> print( x+y ) # 250+10 = 260 % 256 = 4
[4]
Khi cộng 2 ảnh ta có thể sử dụng luôn dòng code img_dst = img1 + img2
hoặc sử dụng hàm cv2.add()
Dưới đây là 1 ví dụ khi cộng 2 ảnh vào nhau
import cv2
image1 = cv2.imread('images/img1.jpg')
image2 = cv2.imread('images/img2.jpg')
imgAdd = cv2.add(image1, image2)
cv2.imshow("Add", imgAdd)
if cv2.waitKey(0) & 0xff == 27:
cv2.destroyAllWindows()
kết quả thu được như hình dưới đây
Image Subtraction
Nếu như Image Addition là việc cộng 2 giá trị pixel tại tọa độ tương ứng trên hai ảnh thì Image Subtraction sẽ thực hiện phép trừ giá trị 2 pixel tại cùng một tọa độ trên hai ảnh.
Cùng xem ví dụ thông qua đoạn code dưới đây nhé
import cv2
import numpy as np
image1 = cv2.imread('images/img_sub1.jpg')
image2 = cv2.imread('images/imgsub2.jpg')
sub = cv2.subtract(image1, image2)
cv2.imshow('Subtracted Image', sub)
if cv2.waitKey(0) & 0xff == 27:
cv2.destroyAllWindows()
Kết quả được thể hiện ở hình dưới đây:
Sau khi lấy image 1 trừ đi image 2 thì trên ảnh kết quả, những pixel trắng trên image 2 đã sang màu đen do trên ảnh image 1 cũng có những pixel trắng nằm ở vị trí tương ứng.
Image Saturation
Như đã đề cập ở trên phần Image Addition, thay vì việc cộng hoặc trừ 2 ảnh cho nhau, ta có thể cộng hoặc trừ một ảnh với một ma trận số nguyên nhằm thay đổi giá trị pixel của ảnh ban đầu. Cách làm như vậy gọi là Image Saturation, nó thường được sử dụng để tăng hoặc giảm độ sáng của ảnh đầu vào.
Để thực hiện ta sẽ tạo ra một ma trận số nguyên với kích thước bằng đúng ảnh đầu vào. Và tùy mục đích tăng hay giảm độ sáng ta sẽ sử dụng các function hợp lý. Ví dụ như tăng độ sáng thì sẽ dùng cv2.add() và ngược lại giảm độ sáng ta sẽ dùng cv2.subtract() Cùng thử ví dụ nhé:
Dùng OpenCV đọc ảnh cần xử lý:
import cv2
import numpy as np
img = cv2.imread("images/meow.jpg", 1)
cv2.imshow("Original image", img)
Tạo ma trận số nguyên để sử dụng
img_100 = np.ones(img.shape, dtype = "uint8") * 100
Thử tăng độ sáng
img2=cv2.add(img,img_100)
cv2_imshow(img2)
và kết quả là
Thử giảm độ sáng xem sao
img3=cv2.subtract(img,img_100)
cv2_imshow(img3)
và kết quả
Image Blending
Image Blending cũng có thể coi là 1 loại Image Addition. Trong khi Image Addition chỉ đơn giản là việc cộng giá trị của các pixel có cùng vị trí trên hai ảnh để thu được kết quả thì Image Blending có thêm một cơ chế đánh trọng số vào giá trị các pixel của mỗi ảnh.
Trong đó:
- là tọa độ của pixel trong ảnh.
- là giá trị của pixel tại tọa độ x trên ảnh kết quả.
- và là 2 ảnh để thực hiện phép blending.
- là giá trị trọng số, giá trị của nằm trong đoạn . Với mỗi giá trị khác nhau ta sẽ thu được một ảnh kết quả khác nhau.
Ngoài ra công thức trên ta cũng có thể thực hiện Image Blending với công thức sau:
Trong đó:
- giống với công thức phía trên
- là trọng số của từng ảnh thành phần, và hai trọng số này không phụ thuộc vào nhau.
- là một phần giá trị được thêm vào sau quá trình cộng 2 ảnh. Thường thì
Thư viện OpenCV cung cấp hàm cv2.addWeighted() để thực hiện blending image.
Để thử nghiệm ta dùng đoạn code dưới đây:
import cv2
image1 = cv2.imread('images/img1.jpg')
image2 = cv2.imread('images/img2.jpg')
weightedSum = cv2.addWeighted(image1, 0.5, image2, 0.4, 0)
cv2.imshow('Weighted Image', weightedSum)
if cv2.waitKey(0) & 0xff == 27:
cv2.destroyAllWindows()
Sau khi thực hiện đoạn code trên sẽ thu được ảnh kết quả như hình dưới đây
Bitwise Operations
Bitwise operations bao gồm các phép AND, OR, XOR, NOT. Bảng chân lý của các phép toán này được thể hiện ở hình dưới đây:
Khi thực hiện trên ảnh, X, Y sẽ đại diện cho giá trị pixel của ảnh khi đó:
- AND có giá trị 1 khi 2 pixel có giá trị lớn hơn 0.
- OR có giá trị 1 nếu một trong 2 pixel có giá trị lớn hơn 0.
- XOR có giá trị 1 nếu một trong 2 pixel có giá trị lớn hơn 0, nhưng đồng thời pixel còn lại phải có giá trị 0.
- NOT Đảo ngược giá trị pixel.
Với Bitwise Operations, phép toán này chỉ thực hiện trên ảnh nhị phân. Do đó để thực hiện ta cần đưa ảnh về nhị phân với quy luật đơn giản là pixel nào có giá trị lớn hơn 0 thì sẽ mang giá trị 1 và còn lại những pixel nào có giá trị 0 thì vẫn giữ nguyên giá trị là 0. Hình dưới mô tả điều này
Sau khi đưa về được ảnh nhị phân rồi thì kết quả các phép AND OR XOR NOT sẽ như hình dưới đây :v
Để hiểu rõ hơn về cách thức hoạt động của các phép bitwise tôi sẽ cùng các bạn đi vào ví dụ cụ thể nhé.
Đầu tiên tôi tạo 2 ảnh có kích thước bằng nhau, một hình nền đen chứa hình chữ nhật trắng và một hình nền đen chứ hình tròn trắng. Để tạo được 2 hình này tôi sử dụng đoạn code dưới đây
Đầu tiên là hình chữ nhật trắng trên nền đen
img_rectangle = np.ones((400,400), dtype = "uint8")
cv2.rectangle(img_rectangle, (50,50), (300,300), (255,255,255), -1)
và đây là kết quả
Tiếp theo là hình tròn trắng trên nền đen
img_circle = np.ones((400, 400), dtype="uint8")
cv2.circle(img_circle, (300, 300), 70, (255, 255, 255), -1)
và đây là kết quả
Tiếp theo ta sẽ đi xem kết quả của từng phép bitwise trên 2 ảnh vừa rồi nhé
AND
bitwiseAnd = cv2.bitwise_and(img_rectangle,img_circle)
Kết quả là
OR
bitwiseOr = cv2.bitwise_or(img_rectangle,img_circle)
Kết quả là
XOR
bitwiseXor = cv2.bitwise_xor(img_rectangle,img_circle)
Kết quả là
NOT
bitwiseNot_rec = cv2.bitwise_not(img_rectangle)
bitwiseNot_circ = cv2.bitwise_not(img_circle)
Kết quả trên ảnh hình chữ nhật
Kết quả trên ảnh hình tròn
Tổng hợp kết quả lại ta có như hình dưới đây
Hình này được tôi tham khảo tại #005 Image Arithmetic and Logical operations in OpenCV with Python