Professional Documents
Culture Documents
Báo cáo Xử lý ảnh nhóm 1
Báo cáo Xử lý ảnh nhóm 1
TRƯỜNG CƠ KHÍ
Khoa Cơ điện tử
***************
XỬ LÝ ẢNH
Đo kích thước vật thể realtime
Giảng viên hướng dẫn: TS. Dương Văn Lạc
HÀ NỘI, 7/2023
3
Kết quả đánh giá Hà Nội, ngày 31 tháng 7 năm 2023
Giảng viên hướng dẫn
Họ và tên Điểm
Nguyễn Văn Đức
Đặng Đức Độ
Nguyễn Bá Công
4
MỤC LỤC
CHƯƠNG 1. LỜI NÓI ĐẦU..................................................................................6
2.2 Cơ sở lý thuyết cách đo kích thước vật thể bằng OpenCV thuần....................8
3.6.2 Diện tích hình chữ nhật tối thiểu bao quanh Contour....................17
5
4.1 Nhận xét và đánh giá......................................................................................24
6
CHƯƠNG 1. LỜI NÓI ĐẦU
Hiện nay, xử lý ảnh là một lĩnh vực đang được quan tâm rất nhiều. Tại hầu hết
các nước có nền khoa học tiên tiến trên thế giới, các loại trang thiết bị máy móc,
sản phẩm thông minh được ứng dụng hầu hết vào mọi lĩnh vực.
Trước đây, người ta thường chỉ sử dụng các thiết bị đo mà việc tính toán và xử lí
kết quả hoàn toàn là thủ công. Do những yêu cầu cấp thiết trong sản xuất chế tạo
mà đo lường ngày càng phát triển. Giờ đây với sự tiến bộ của các ngành cơ-điện
tử-tin học và việc ứng dụng những thành tựu của kỹ thuật điện tử, công nghệ thông
tin, trí tuệ nhân tạo, vào ngành cơ khí thì xử lí ảnh và đo lường trong các hệ thống
và robot công nghiệp đã được ứng dụng ngày càng rộng rãi. Nó là công cụ để
kiểm tra đánh giá chất lượng của sản phẩm, nó làm tai mắt cho các hệ thống tự
động hóa quá trình sản xuất hay các robot thông minh, với những khả năng vượt
trội so với các phương pháp truyển thống như:
Khả năng tự xử lí và lưu trữ kết quả đo.
Thực hiện công việc đo theo chương trình
Tự động thu thập, phân loại và báo lỗi, …
Và trong lần này, nhóm chúng em làm với một đề tài nhỏ đó là đo kích
thước vật thể, với vật thể tham chiếu được chọn là đồng xu. Đề tài sử dụng thuật
toán Canny và thư viện Opencv.
7
CHƯƠNG 2. TỔNG QUAN VỀ ĐỀ TÀI
Sản phẩm sau khi được lắp ráp hay gia công đều cần được kiểm ngoại dạng
trước khi chuyển sang công đoạn tiếp theo để đảm bảo không để lọt bất cứ sản
phẩm lỗi hay kém chất lượng nào tới khách hàng. Thông thường công đoạn kiểm
tra này do người thao tác (công nhân) trực tiếp dùng mắt kiểm tra với 1 quy trình
nhất định. Việc này có nhiều ưu điểm song lại không đạt được độ chính xác cao
nhất mà nhà sản xuất mong muốn.
Từ những vấn đề đó, xử lý ảnh trong công nghiệp hiện nay phát triển có nhiều
ứng dụng có thể kể đến như:
Nhận diện/kiểm tra ngoại dạng sản phẩm
Nhận diện/kiểm tra màu sắc
Đo lường/kiểm tra kích thước không tiếp xúc
Kiểm tra kí tự quang học (OCV)
Kiểm tra mã vạch
Điều hướng Robot
…
Trong những ứng dụng trên, nhóm chúng em sẽ tập trung vào ứng dụng thứ
3 đó là đo lường và kiểm tra kích thước của vật. Các phép đo truyền thống được
thực hiện với các dụng cụ đo bằng cơ (đã được hiệu chỉnh rất chính xác) và người
thực hiện đo phải được huấn luyện về kĩ thuật đo mới đảm bảo kết quả đo có độ tin
cậy cao. Khi sản xuất hàng loạt, sản phẩm rất nhiều & nhỏ, khiến cho việc kiểm tra
kích thước sản phẩm bằng con người trở nên hết sức khó khăn và tốn kém vì vậy,
sự tiến bộ của kĩ thuật và công nghệ cung cấp giải pháp đo kiểm kích thước không
tiếp xúc dùng camera giúp xác định chính xác (cỡ dưới 10µm và bằng 10% dung
sai kích thước bản vẽ) với tốc độ cao các: khoảng cách, góc, diện tích, độ khớp
8
đường, độ khớp tròn … Từ đó nhà máy sẽ tiết kiệm được rất nhiều chi phí nhân
công, giảm được tối đa sai sót so với phương pháp đo kiểm truyền thống. Ứng
dụng này được xử dụng trong công nghiệp rất nhiều với nhiều những hình dạng và
kích thước khác nhau. Và trong lần này chúng em sẽ làm với đề tài đo kích thước
của một số vật đơn giản.
2.2 Cơ sở lý thuyết cách đo kích thước vật thể bằng OpenCV thuần
Muốn đo kích thước vật thể trong ảnh ta phải biết được các yếu tố như:
Khoảng cách từ camera đến vật khi chụp, Tiêu cự của camera, góc chụp…. rất
phức tạp như hình dưới:
9
Sau đó, Giả sử ta đo được đường kính trong ảnh của Vật tham
chiếu là Dc =100 pixel, ta suy ra kích thước thật của 1-pixel là 20/100 =
0.2mm (goi là số P)
Bước cuối cung, ta đo kích thước trong ảnh Vật muốn đo bằng pixel, sau đó
nhân với P là sẽ ra kích thước thật của vật.
10
(tìm đường bao): tìm cạnh của vật bằng thuật toán Canny và xử lí
đường bao bằng cách loại bỏ các đường viền nhỏ. Sau đó tính diện
tích của vật bằng định lý green.
(đo kích thước): sau khi tìm được các contour ta thực hiện tính toán
kích thước của nó bằng cách tìm hình chữ nhật có diện tích bé nhất
của contour. Ta tính toán được chiều dài 2 cạnh theo pixel nhờ vào
các hàm trong thư viện OpenCV. Và cuối cùng ta tiến hành xử lý giá
trị chiều dài 2 cạnh theo pixel có ở trên để tìm được kích thước thật
bên ngoài
Bước 4 (Xuất ảnh): Ảnh đã vẽ hình bao và ghi kích thước của đồng xu và
vật mẫu. Hoặc ở chế độ realtime, video xuất ra sẽ quay trực tiếp vật được đo
và ghi kích thước đo được lên khung hình camera.
11
CHƯƠNG 3. NỘI DUNG CÁC BƯỚC THỰC HIỆN
Nhóm sử dụng camera điện thoại để chụp được hình ảnh của vật cần đo. Để
đo được chính xác kích thước của vật, ta cần đảm bảo cố định hai yếu tố là góc
chụp của camera và khoảng cách từ camera tới vật. Do đó, điện thoại được gá cố
định trên một hệ khung như hình.
12
Hình 2.2 Hình ảnh của vật cần đo
Nhóm sử dụng các tấm fomex để làm thành hộp kín, có ánh sáng từ đèn điện
thoại, sau đó có chỗ để camera khác để thu hình ảnh vật đo đặt dưới đáy hộp.
13
3.2 Tiền xử lý
Khi có được các ảnh, trước hết ta lấy dữ liệu ảnh và thực hiện bước tiền xử lý.
Tất cả phần này được viết trong hàm:
image,edged = read_and_preprocess(filename, canny_low=50,
canny_high=100, blur_kernel=9, close_kernel=3)
với dữ liệu đầu vào gồm tên tệp ảnh (filename), ngưỡng thấp và cao của
thuật toán Canny (canny_low, canny_high), kích thước ma trận vuông cho nhân
của thuật toán làm mờ Gauss (blur_kernel), kích thước ma trận vuông cho nhân
của thuật toán hình thái học Closing (close_kernel). Đầu ra của hàm này là một ảnh
đọc từ tệp và một ảnh chứa cạnh của vật thể cùng nhiễu thông cao.0
trong thư viện cv2. Trong đó, flag là cờ chuyển đổi kiểu dữ liệu ảnh. Hàm này sẽ
đọc từng điểm ảnh ở 3 kênh màu RGB, cho ra một mảng 3 chiều với 2 chiều đầu
tiên là kích thước ảnh, chiều thứ 3 là 3 kênh màu. Ở đây, ta bỏ qua flag để thu
14
được ảnh gốc. Do ảnh có độ phân giải cao, khi lấy dữ liệu sẽ cho ra ảnh lớn, nên ta
cần giảm kích thước ảnh mà không để ảnh sai tỉ lệ kích thước. Ta sẽ sử dụng hàm:
image = cv2.resize(src, dsize)
trong thư viện cv2. Src là ảnh gốc (image), dsize là kích thước mới của ảnh (siz1,
siz2). Kích thước mới được tính toán từ kích thước ảnh gốc, lấy được bằng đặc tính
của đối tượng ma trận - shape. Ta lấy kích thước ảnh gốc chia 1.5 cho đến khi kích
thước lớn nhất của ảnh nhỏ hơn 1000, sau đó chuyển kích thước về số nguyên.
Bước tính toán trên dưới dạng ngôn ngữ lập trình sẽ như sau:
siz1, siz2 = image. shape [0:2]
while max (siz1, siz2) > 1000:
siz1 = siz1/1.5
siz2 = siz2/1.5
siz1 = int(siz1)
siz2 = int(siz2)
image = cv2.resize(image, (siz2, siz1))
Sau khi ảnh gốc đã đạt kích thước phù hợp, muốn thực hiện thuật toán tìm
cạnh Canny, ta cần chuyển ảnh sang ảnh xám để xử lý 1 kênh màu, làm mờ ảnh với
mặt nạ Gauss để xử lý nhiễu thông thấp mà cạnh của vật thể không bị biến dạng
quá nhiều. Ta chuyển ảnh sang ảnh xám với hàm:
gray = cv2.cvtColor(src, code)
trong thư viện cv2. Src là ảnh gốc (image), code là gọi hàm chuyển đổi không gian
màu (cv2.COLOR_BGR2GRAY). Hàm này lấy giá trị trung bình của 3 kênh màu tại mỗi
pixel, ta sẽ thu được ảnh 1 kênh màu (ảnh xám) ở đầu ra. Sau đó, ta sử dụng hàm:
blur = cv2.GaussianBlur(src, ksize, sigmaX)
trong thư viện cv2. Với src là ảnh gốc (gray), ksize là kích thước mặt nạ Gauss
(blur_kernel, blur_kernel), sigmaX là hệ số trong đồ thị phân bố xác suất chuẩn
Gauss theo trục x (để bằng 0, vì đã chọn ksize nên không cần). Hàm này sử dụng
15
mặt nạ phân bố chuẩn Gauss, thực hiện tích chập với ảnh gốc. Đầu ra của hàm này
là ảnh được làm mờ.
Tiếp theo, ta sử dụng thuật toán Canny để tìm cạnh với hàm:
edged = cv2.Canny(image, threshold1, threshold2)
trong thư viện cv2. Image là ảnh gốc (blur), threshold1 là ngưỡng thấp
(canny_low), threshold2 là ngưỡng cao (canny_high). Thuật toán Canny thực hiện
tích chập ảnh với mặt nạ Sobel để tìm các vector vuông góc với cạnh, loại bỏ các
điểm không phải cực đại địa phương (đưa về 0), sau đó dùng ngưỡng để chọn ra
thành phần cạnh và không phải cạnh. Cụ thể, tích chập với ma trận Sobel có dạng
như sau:
Trong đó, A là ma trận dữ liệu ảnh, (G x, Gy) là vector hướng G tại từng
điểm. Vector G có hướng luôn vuông góc với các đường cạnh trong ảnh (ranh giới
nơi cường độ sáng có bước nhảy), có độ dài tỉ lệ với độ chênh lệch cường độ sáng
với các điểm ảnh lân cận. Từ giá trị độ dài của G, ta lọc cơ sở bằng cách giữ lại các
điểm là cực đại so với 2 điểm lân cận (xét trên 4 phương), các điểm khác đưa về
giá trị 0.
Khi có được các điểm ảnh có khả năng là cạnh, ta áp đặt ngưỡng cao và
ngưỡng thấp để giữ lại các cạnh đủ lớn. Các điểm ảnh có (|G| > ngưỡng cao) hoặc
(|G| > ngưỡng thấp và nằm cạnh điểm ảnh có |G| > ngưỡng cao) sẽ được giữ lại.
Đầu ra của hàm là ảnh nền đen cạnh trắng.
Để đề phòng trường hợp cạnh bị đứt đoạn nhỏ, ta sử dụng thuật toán Closing
gồm 2 hàm:
edged = cv2.dilate(src, kernel)
16
edged = cv2.erode(src, kernel)
trong thư viện cv2. Src là ảnh gốc (edged), kernel là ma trận dùng tích chập với
ảnh (có thể chỉ cần đưa vào kích thước (close_kernel, close_kernel)). Dilate
và erode sẽ tích chập mặt nạ với ảnh, dilate đặt điểm mốc giá trị 255 khi và chỉ khi
ít nhất một điểm qua mặt nạ khác 0, còn erode thì đặt điểm mốc giá trị 255 khi và
chỉ khi tất cả điểm qua mặt nạ đều khác 0. Kết quả là dilate làm phần màu trắng
giãn ra, cạnh bị đứt sẽ được nối liền, erode làm phần màu trắng co lại kích thước
ban đầu. Như vậy là đã kết thúc bước tiền xử lý.
Sau bước tiền xử lý – sử dụng thuật toán Canny detection để tìm ra cạnh,
đường viền của bức ảnh ta sử dụng thuật toán FindContour để tìm đường viền
mong muốn dưới dạng là chuỗi tọa độ các điểm trên đường viền (bao gồm tất cả
các đường viền và cạnh bao):
cnts=cv2.findContours(edged.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_
SIMPLE)
Ở đây ta điền 3 tham số:
edged.copy() – đây là tham số ảnh sau khi đã tiền xử lý sử dụng Canny
Detection, như trong code là ảnh copy từ ảnh edge đã được xử lý ở trên.
cv2.RETR_EXTERNAL – đây là tham số giúp chúng ta chỉ lấy các đường viền
bên ngoài, loại bỏ các đường viền bên trong.
cv2.CHAIN_APPROX_SIMPLE – tham số này sẽ loại bỏ các nét thừa, đường
viền không kín.
Kết quả chúng ta sẽ được tập hợp các tọa độ thuộc các đường bao.
Sau đó ta tiến hành đưa các chuỗi tìm được về dạng dữ liệu Tuple (sử dụng
hàm imutils.grab_contours()) trong python để xử lý các đường viền này :
cnts = imutils.grab_contours(cnts)
17
Tham số đưa vào là ‘cnts’ đây là kết quả lấy được từ hàm findcontour,
qua hàm trên sẽ chuyển tạp hợp các tọa độ về dạng dữ liệu Tuple (nhóm các tạo độ
cùng thuộc 1 đường bao)
Tiếp theo ta tiến hành sắp xếp các đường viền theo thứ tự từ trái qua phải
trên dữ liệu vừa nhận được qua hàm:
(cnts, _) = contours.sort_contours(cnts)
Ta loải bỏ các đường viền nhỏ (không cần thiết) trên ảnh mà ta thu được
thông qua việc so sánh diện tích của các đường bao (sử dụng hàm contourArea()
để tìm diện tích của các đường bao) với một số xác định đã được cho trước:
if cv2.contourArea(c) < area_threshold :
continue
Ở đây c chính là tập hợp các tọa độ pixel thuộc cùng một đường bao đã xác
định ở trên, area_threshold là giá trị giới hạn diện tích theo pixel mà nếu nhỏ
hơn ta sẽ loại bỏ. Từ đầu vào của thuật toán contourArea( ) là tập hợp tọa độ các
pixel thuộc cùng một đường bao, ta sẽ vẽ được dạng của đường bao. Sau đó áp
dụng định lý Green ta sẽ tính được diện tích của đường bao theo đơn vị là pixel
18
3.6.2 Diện tích hình chữ nhật tối thiểu bao quanh Contour
Hình ảnh bên dưới hiển thị 2 hình chữ nhật, hình chữ nhật màu xanh lá cây
là hình chữ nhật bao quanh bình thường trong khi hình màu đỏ là hình chữ nhật có
diện tích tối thiểu. Xem cách xoay hình chữ nhật màu đỏ.
19
3.6.3 Góc quay của hình chữ nhật tối thiểu
Như chúng ta đã biết rằng 4 điểm góc được sắp xếp theo chiều kim đồng hồ
bắt đầu từ điểm có y cao nhất như hình bên dưới. Nếu 2 điểm có cùng y cao nhất
thì điểm ngoài cùng bên phải là điểm xuất phát. Các điểm được đánh số là 0,1,2,3
(0-bắt đầu, 3-kết thúc).
Vì vậy, góc quay được cung cấp bởi cv2.minAreaRect() của OpenCV thực
sự là góc giữa đường thẳng (nối điểm đầu và điểm cuối) và phương nằm ngang
như minh họa bên dưới:
Do đó, giá trị góc luôn nằm trong khoảng [-90,0) . Tại sao? bởi vì nếu vật thể
bị xoay hơn 90 độ, thì cạnh tiếp theo được sử dụng để tính góc so với phương
ngang. Và do đó, góc được tính toán luôn nằm trong khoảng [-90,0). Xem hình ảnh
bên dưới trong đó đường màu xanh lá cây hiển thị đường nối điểm đầu và điểm
20
cuối được sử dụng để tính góc. Ngoài ra, hãy xem điểm bắt đầu và điểm cuối thay
đổi như thế nào khi xoay đối tượng. Các điểm được đánh số là 0,1,2,3 (0-bắt đầu,
3-kết thúc).
Sau khi tìm được các contour, ta sẽ thực hiện tính toán kích thước của nó
bằng pixel. Ở đây ta sẽ đo kích thước của vật bằng cách tìm MinAreaRect, tức là
hình chữ nhật bao có diện tích bé nhất của contour, xác định vị trí các đỉnh và tính
độ dài 2 chiều của hình chữ nhật này theo pixel và mm.
Ta định nghĩa hàm get_distance_in_pixels (orig, c) nhận vào 2 biến là
ảnh gốc và contour c đã tìm được:
def get_distance_in_pixels (orig, c):
box = cv2.minAreaRect(c)
box = cv2.boxPoints(box)
box = np. array (box, dtype="int")
Hàm minAreaRect () của opencv cho kết quả là tọa độ điểm trên cùng bên
trái, chiều dài, chiều rộng, góc xoay của hình chữ nhật bao bé nhất của contour c.
Sau đó ta đưa vào hàm boxPoints () của opencv để từ các dữ liệu trên, tính ra tọa
độ 4 đỉnh của hình chữ nhật. Sau đó ta đưa vào array () của numpy để chuyển các
tọa độ thành mảng kiểu int.
# Sắp xếp các điểm theo trình tự
box = perspective. order_points(box)
cv2.drawContours(orig, [box. astype("int")], -1, (0,255,0), 2)
Do các điểm góc của hình chữ nhật bao bị xoay, ta dùng hàm order_points
() của thư viện imutils. perspective để sắp xếp các tọa độ theo thứ tự cùng chiều
kim đồng hồ, bắt đầu từ điểm trên cùng bên trái. Sau đó ta vẽ contour.
(tl, tr, br, bl) = box
(tltrX, tltrY) = midpoint(tl, tr)
(blbrX, blbrY) = midpoint(bl, br)
(tlblX, tlblY) = midpoint(tl, bl)
21
(trbrX, trbrY) = midpoint(tr, br)
Sau đó, ta tìm tọa độ trung điểm các cạnh bằng hàm midpoint().
dc_W = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))
dc_H = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
Cuối cùng ta tiến hành xử lý giá trị chiều dài 2 cạnh theo pixel có ở trên để
tìm được kích thước thật bên ngoài:
if P is None:
P = ref_wi
.dth / dc_H
dr_W = ref_width
dr_H = ref_width
else:
dr_W = dc_W * P
dr_H = dc_H * P
Cuối cùng ta xác định P – chiều dài 1-pixel tính theo đơn vị mm, với
ref_width là chiều dài vật tham chiếu được cho trước, dc_H là chiều dài vật tham
chiếu tính theo pixel. Và sau khi có được P ta tiến hành xác định chiều dài cần tìm
bằng các nhân P với chiều dài tính theo đơn vị pixel cảu vật cần xác định. (Việc
tìm P được tính lần đầu tiên khi chưa có số liệu của P, khi đã biết P ta chỉ đi tìm
chiều dài thực với P đã có)
23
Để xuất ảnh, ta dùng hàm cv2.imshow(winname, mat) trong thư viện cv2,
trong đó, winname là tên cửa sổ mở ra, mat là ma trận dữ liệu ảnh. Vì thực thi
xong chương trình sẽ đóng lại nên cần hàm cv2.waitKey() trong thư viện cv2 để
hệ thống chờ cho người dùng nhấn 1 nút bất kì từ bàn phím.
cap = cv2.VideoCapture(1)
if not cap.isOpened():
print("cannot open camera")
exit()
while True:
# Capture frame by frame
ret,frame = cap.read()
# if frame is read corectly ret is true
if not ret:
print("Can't receive frame (stream end?). Exiting ...")
break
Từ cơ sở lý thuyết và thực hành trên ta có một số nhận xét và đánh giá thuật toán
Canny Edge Detection với một số trường hợp ảnh sau:
- Đối với ảnh không nhiễu: Do quá trình làm trơn ảnh nên từ một ảnhkhông
nhiễu các biên mờ bớt đi và to ra. Do vậy, biên ảnh trong phương pháp Canny lớn
nhưng lại không đầy đủ, không nên áp dụng.
- Đối với ảnh có nhiều cạnh: Khi phát hiện biên các cạnh không quan trọng
nên được loại bỏ. Do quá trình “Non - maximum Suppression” và do quá trình áp
dụng ngưỡng mà các điểm biên phụ bị loại bớt đi, các biên chính được giữ lại nên
biên rõ nét hơn.
- Đối với ảnh có nhiều nhiễu: Do quá trình làm trơn ảnh cho bớt nhiễu và quá
trình “Non – maximum Suppression” giảm bớt các biên phụ nên ảnh kết quả của
phương pháp này rất rõ nét. Vì vậy phương pháp này rất thích hợp cho loại ảnh
này.
25
Hình 3.1 Kích thước của vật đo được
Tìm hiểu và nắm rõ được thuật toán Canny Edge Detection
Biết về thuật toán Find Coutour
Phân biết, nắm rõ một số thuật ngữ trong xử lý ảnh
Sử dụng OpenCv để thực hiện xử lý một bức ảnh
Trau dồi thêm kiến thức mới.
Mất nhiều thời gian sửa lỗi trong quá trình thực hiện
Project còn đơn giản
Ngoài việc đo kích thước những vật đơn giản, nhóm sẽ tiếp tục triển khai
nghiên cứu đề tài lớn hơn là đo kích thước bàn tay, ứng dụng trong nhà máy sản
xuất gang tay.
26
CHƯƠNG 5. TÀI LIỆU THAM KHẢO
27
28