CHƯƠNG 2. CƠ SỞ LÝ THUYẾT
2.5 Một số phương pháp trong xử lý ảnh
2.5.2 Làm trơn nhiễu bằng lọc tuyến tính
a. Lọc trung bình không gian
Với lọc trung bình, mỗi điểm ảnh được thay thế bằng trung bình trọng số của các điểm lân cận và được định nghĩa như sau:
v(m,n) = ∑ ∑( ) ( ) ( ) (2.4) Nếu trong kỹ thuật lọc trên, ta dùng các trọng số như nhau, phương trình trên sẽ trở thành:
v(m,n) = ∑ ∑( ) ( ) (2.5) với : y(m, n): ảnh đầu vào,
v(m, n): ảnh đầu ra, a(k, l) : là cửa sổ lọc.
với ak,l =
và Nw là số điểm ảnh trong cửa sổ lọc W.
b. Lọc đồng hình (Homomorphie Filter)
Kỹ thuật lọc này hiệu quả với ảnh có nhiễu nhân. Thực tế, ảnh quan sát được gồm ảnh gốc nhân với một hệ số nhiễu. Gọi X (m, n) là ảnh thu được, X(m, n) là ảnh gốc và η(m, n) là nhiễu, như vậy:
X(m, n) = X (m,n) * η(m, n ) (2.9) Lọc đồng hình thực hiện lấy logarit của ảnh quan sát. Do vậy ta có kết quả sau:
Log(X(m, n)) = log( X (m,n) ) + log( η(m, n)) (2.10) Rõ ràng, nhiễu nhân có trong ảnh sẽ bị giảm. Sau quá trình lọc tuyến tính, ta
chuyển về ảnh cũ bằng phép biến đổi hàm e mũ.
2.5.3 Nhị phân hóa ngƣỡng động
Nhị phân hóa theo ngưỡng tự động với ý tưởng sau:
- Chia tấm ảnh thành nhiều khu vực, cửa sổ khác nhau
- Dùng một thuật toán để tìm một giá trị T phù hợp với từng khu vực, cửa sổ (Region).
- Áp dụng phương pháp nhị phân hóa cho từngkhu vực, cửa sổ (Region) với T phù hợp.
Điều quan trọng trong kĩ thuật này là phải tìm một giá trị T phù hợp với từng khu vực, cửa sổ (Region) hoặc cả tấm ảnh. Có rất nhiều phương pháp để tìm T, ở nội dung tiếp theo tôi sẽ giới thiệu một số thuật toán giúp tìm kiếm giá trị T này.
Thuật toán Otsu
Bước 1: Xác định T1. Giá trị cho T1 ban đầu nên chọn là (0+255) / 2 = 128.
Bước 2: Phân loại thành 2 nhóm điểm ảnh.
Loại 1 (Type1): chứa tất cả các điểm ảnh có giá trị cường độ sáng (Intensity)
<= T.
Loại 2 (Type2): chứa tất cả các điểm ảnh có giá trị cường độ sáng (Intensity) > T.
Bước 3: Tính giá trị cường độ sáng trung bình (iAverage) cho Type1 (iAverage1) và Type2 (iAverage2).
Bước 4: Tính giá trị T2 theo công thức (iAverage1 + iAverage2) /2.
Bước 5: So sánh T1 và T2.
Nếu giá trị chênh lệch của T1 và T2 <= Delta (một giá trị cho trước) thì T2 chính là T cần tìm.
Nếu giá trị chênh lệch của T1 và T2 > Delta Deltal thì quay lại Bước 1.
Hình 2.8: Ngƣỡng tự động theo T1 và T2.
2.5.4 Phân vùng ảnh:
Là bước xác định vật thể trong ảnh, bằng cách trích lọc ra vùng có cùng tính chất dựa vào sự đồng nhất về mức xám giữa những pixel. Sau khi phân vùng ảnh, ta sẽ có được vật thể xác định trên ảnh tách biệt với các chi tiết thừa trong hình. Hạn chế là ta chỉ nhận được các vật tách biệt nhau còn với các ảnh nhiều chi tiết, kết quả phân vùng sẽ không chính xác.
Đối với cấu trúc ảnh nhị phân, các pixel chỉ mang giá trị 0 hoặc 1 nên việc phân vùng ảnh rất quan trọng nhằm loại bỏ nhiễu, phân tách các vật thể gần nhau hay định rõ một vật thể với các đường liên kết nhỏ.
Phương pháp khả thi nhất cho việc phân vùng ảnh nhị phân là làm mảnh và làm đầy:
- Làm mảnh: loại bỏ hoàn toàn các nhiễu trong vật thể hay trên biên, tách biệt các vật với nhau.
Tùy theo mục đích và yêu cầu hệ thống, ta có thể sử dụng một vài bước trên để lấy thông tin cần thiết cho việc xử lý ảnh. Đó có thể đơn giản là nhận biết sự khác nhau giữa 2 hình nhằm xác định chuyển động hoặc phức tạp cần đến độ chính xác cao như nhận biết dấu vân tay đối tượng định trước …
2.5.5 Phép toán Dilation.
Phép toán Dilation là thao tác giãn nở/ phình to các đối tượng ảnh đơn sắc A và B là hai tập hợp con trong Z2, thực hiện phép toán Dilation trong A theo B, kí hiệu là A B và được xác định như sau : A B = {z | ̂z A }.
Trong Matlab, ta có hàm Dilation như sau: imdilate.
B chính là nhân tạo hình. Trong Matlab, chương trình cũng cung cấp cho ta nhiều nhân tạo hình khác nhau, để biết them chí tiết gõ help strel. Trong thực tế, người ta chọn những nhân tạo ảnh sao cho B = ̂, tức là sử dụng nhân tạo ảnh có các phần tử trong nhân tạo ảnh đối xứng qua chính tâm của nó. Bên cạnh đó, với việc ta lê những cái tâm z của nhân tạo ảnh B ảnh đi khắp A và tìm những điểm nào mà B A thì ta có thể hiểu như A B = UbiAbi với Abi là những khu vực mà A Bi . Có thể xem hình minh họa dưới đây:
Hình 2.9.a.Đối tượng cần phình A và nhân tạo ảnh B b.Minh họa quét các b,khắp A
Hình 2.10. Kết quả của phép toán Dilation.
2.5.6 Phép toán Erosion.
Phép toán Erosion là thao tác xói mòn/ co hẹp các đối tượng ảnh đơn sắc. A và B là hai tập hợp con trong Zz , thực hiện phép toán Erosion trong A theo B, kí hiệu là A B và được xác định như sau: A B = { p }
Tương tự, trong Matlab ta cũng có hàm Eosion như sau: imerode
Để minh họa cách thức phép toán hoạt động có thể xem hình phía dưới với A và B tương tự như ví dụ ở phép toán Dilation.
Hình 2.11.Kết quả của phép toán Erosion.
2.5.7 Phép toán Openning.
Phép toán Openning của hình A theo nhân tạo hình B kí hiệu là A B = (A B ) B.
Theo một định nghĩa khác tương đương dựa vào hình học ta có:
A B = {Bz |BZ }.
Tác dụng của phép toán Openning là loại bỏ nhũng đối tượng không đủ lớn để nhân tạo hình (góc), làm trơn biên, tách rời mấu liên kết với những đối tượng lớn và nhánh con. Trong Matlab hàm hỗ trợ phép toán này là imopen
2.5.8 Phép toán closing
Phép toán Closing của hình A theo nhân tạo hinh B kí hiệu là:
A B = (A ) B.
Tác dụng của phép toán này là làm trơn biên, nối liền những mẫu rời nhau, lắp đầy các lỗ nhỏ. Trong Matlab hàm để sử dụng là imclose. Ngoài ra ta còn có một số tính chất cần lưu tâm sau đây:
2.4.9 Thuật toán đánh nhãn:
Khi nhận data hình, ta nhận từng pixel một theo chiều từ trái sang phải, từ trên xuống dưới. Việc xử lý có thể được thực hiện giữa các lines hoặc các frames hình. Do hạn chế về tài nguyên của các board xử lý hình ảnh, mà cụ thể là Ram, ta không thể lưu cả 1 frames ảnh để dành đến cuối khung hình mới xử lý, vậy ta chọn cách thực thi thuật toán giữa các lines.
Cấu trúc của đối tượng trong hình có thể đơn giản như hình vuông, chữ nhật … nhưng cũng có thể rất phức tạp như hình sao, hình lục giác…độ lớn cũng khác nhau, trải dài trên nhiều lines và ở mọi vị trí trên hình ảnh. Ta chỉ có thể nhận và xử lý lines từ trên xuống dưới, các lines đã qua xử lý không thể giữ lại nên nếu gặp một phần của đối tượng nằm ở lines bất kì bên dưới, không thể dùng so sánh để biết nó có thuộc đối tượng nào ở trên hay không.
Hình 2.12 : Vật có cấu trúc đơn giản-hình vuông và phức tạp và hình xoắn ốc.
Cách giải quyết vấn đề này là đánh nhãn đối tượng. Với mỗi pixel nhận được, ta đánh số cho pixel đó, các pixel ở cạnh nhau mà cùng thuộc vật thể( có giá trị “1” khi nhận từ bước tiền xử lý) sẽ được gán cùng một nhãn( nhãn là một giá trị nào đó theo thứ tự số).
Vậy cần lưu lại ít nhất 1 line ở trên để so sánh, điều này có thể thực hiện được bởi 1 line gồm 1024 Pixels, không quá nhiều. Do hạn chế của cách hoạt động trên phần cứng, ta chỉ có thể so sánh mỗi pixels ở trên và phía trước nó chứ không thể so sánh toàn bộ các pixels xung quanh.
Ví dụ với các hình vuông và chữ nhật ở trên, với hình vuông gồm 9 pixels, 9 pixels đó đều mang nhãn số 1, tương tự cho hình vuông 4 pixels, 4pixels đó đều mang nhãn là số 2…Nhưng với hình xoắn ốc, cách đánh nhãn này không chính xác, bởi càng xuống phía dưới, nhãn đánh lên các pixel càng khác nhau.
Nhằm thỏa vấn đề này, ta sử dụng cách đánh nhãn có giá trị. Với mỗi nhãn được đánh cho các pixels, ta đi đính kèm với nó có một giá trị. Tức con số gán lên pixel là địa chỉ, địa chỉ này tất nhiên sẽ chứa (hay chỉ đến, dạng con trỏ) một giá trị khác. Như vậy, mục đích là từ một vật thể mang nhiều nhãn khác nhau nhưng các nhãn đều có cùng 1 giá trị, xét theo giá trị thì chúng cùng một đối tượng. Nếu 2 nhãn khác nhau liền kề, ta chỉ cần cập nhật giá trị cho nhãn có số lớn hơn, do ưu tiên các số nhỏ.
Sau đây là sơ đồ giải thuật của thuật toán, với các ghi chú:
Pixel_in: pixel nhận vào theo thứ tự
Pixel_up: pixel ở bên trên pixel đang xét.
Pixel_focus: pixel đang đươc xử lý.
Pixel_pre: pixel phía trước pixel đang xét
Count: biến đếm dùng làm nhãn đối tượng.
Hình 2.13: Lưu đồ giải thuật cho thuật toán đánh nhãn
Thuật toán hoạt động cụ thể nhu sau: pixel lấy vào nếu có giá trị lơn hơn 127, tức là thuộc nền, thay bằng pixel_in có giá trị “0”, ngược lại là “1” như đã nói ở trên. Nếu là nền thì bỏ qua, nhưng nếu là vật thể thì xét pixel_up ở trên ở trên đã đánh nhãn rồi thì cứ theo đó mà gán giá trị vào, còn không phải vật thì xét pixel_pre ở trước, phía trước là vật thể thì theo đó mà đánh nhãn. Nếu cả trên và phía trước đều chưa có nhãn, ta đánh nhãn mới cho pixel này. Việc này thực thi tuần tự với mỗi pixel vào, không dừng lại cho đến khi dừng xử lý bởi người dùng. Việc cập nhật giá trị cho nhãn được thực thi khi
BEGIN
Pixel_in=1
Pixel_up=0 0
Pixel_pre=0
Pixel_focus=pixel_up
Pixel_focus=pixel_pre
Pixel_focus=count+
1 Pixel_in
N
N
N
Y Y
Y
pixel_forcus gán theo nhãn pixel_up nhưng pixel_pre đã có nhãn. Đến đâu pixel_focus và pixel_pre liền kề nhau mang nhãn khác nhau, vậy nhãn nào nhỏ hơn thì lấy giá trị nhãn đó chung cho cả hai. Nhãn là chuỗi số tăng dần có chứa giá trị, vậy trong phần cứng, đó chính là Ram. Còn để lưu lại cả một line rồi lấy dần ra làm pixel_up, bộ Fifo( First in first out) chính là lựa chọn tốt nhất. Việc sử dụng các pixel phía trên và phía trước này cụ thể như sau:
Hình 2.14. Lưu đồ giải thuật cho toán đánh nhãn Để dễ hiểu hơn việc cập nhật giá trị cho các nhãn, ta xem thử vật thể sau:
Hình 2.15: Vật thể màu đen đã được đánh nhãn
Các nhãn liền kề bị khác nhau và cần cập nhật giá trị lai tại các vị trí “2!” và “1!”.
Nhìn cách cập nhât giá trị này có vẻ phức tạp bởi ta có thể xét lại từ đầu line lần nữa và đổi giá trị các nhãn cần thay. Nhưng giả sử gặp phải vật thể kéo dài đến cuối mép phải
Pixel_up FIFO
VGA Pixel_in Pixel_focus
Pixel_pre Analysis
này là không thể đối với hệ thống xử lý thời gian thực. Ram được sử dụng trong trường hợp cụ thể này như sau:
Hình 2.16. : Mô phỏng thuật toán đánh nhãn.
Ô nhớ mang địa chỉ “0” trong Ram không được sử dụng bởi nó trùng giá trị với
“giá trị nền” của pixel_in. Đây là lý do ta chọn nền là “0”, vật thể là “1”, giúp sử dụng được hết các ô nhớ Ram. Số lượng vật thể đếm được cũng theo đó mà được tối ưu. Ví dụ như Ram sử dụng có độ dài 10bits ta theo đó đếm được 1022 vật thể
Thực tế nếu trong hình có nhiều đối tượng có cấu trúc phức tạp, hay nhiều đường cong, biết Count dùng để đánh nhãn sẽ nhanh chóng bị tràn cho dù có dùng độ dài bít lớn đến đâu đi nữa. Chẳng hạn với ví dụ trên ta có thể thấy một vật nhưng có đến 3 nhãn, điều này làm phung phí tài nguyên không cần thiết.Vấn đề ảy sinh tiếp theo là tìm cách sử dụng lại những nhãn không cần thiết nữa, một đối tượng dùng một nhãn là đủ.
Cách giải quyết hiệu quả nhất là dùng bộ Fifo. Các nhãn đã được cập nhật thay đổi giá trị sẽ đưa vào nó Fifo lưu trữ, khi cần sẽ lấy ra theo thứ tự, điều này giúp các nhãn được sử dụng dồn hẳng về đầu Ram, tức là các địa chỉ có giá trị nhỏ, theo kiểu sắp xếp, thuận lợi cho việc xác định vật thể sau này.
Để đếm số lượng vật thể trong ảnh, ta đếm dựa vào các ô nhớ trong RAM. Xét lần lượt các địa chỉ của RAM, nếu địa chỉ ô nhớ giống với các giá trị trong đó thì được một vật thể, trừ địa chỉ ô nhớ”0”. Việc này thực thi vào cuối mỗi Frame hình, khi có cạnh lên hoặc cạnh xuống của vsync tùy theo thuật toán sử dụng sao cho phù hợp giữa chốt lấy giá trị biến đếm number và reset các biến.
Theo ví dụ trên các nhãn 1, 2, 3 đều có chung giá trị 1, vậy chúng cùng thuộc một đối tượng, nhãn 4 đối tượng tiếp theo, cứ thế cho đến ô địa chỉ RAM cuối cùng.
Hình 2.17 : Số lượng vật được xác định dựa vào RAM 2.4 CÁC HÀM XỬ LÝ TRONG MATLAB[4].
Các hàm chính hiển thị ảnh trong matlab:
Hàm image(x,y,c): Hiển thị hình ảnh biểu diễn bởi ma trận c kích thước m x n lên hệ trục tọa độ, x,y là các vector xác định vị trí của các pixel c(m,n).
Hàm imagesc: Tương tự hàm image, dữ liệu ảnh sẽ được co giãn để sử dụng toàn bộ bản đồ màu hiện hành.
Hàm imshow: Cho phép hiển thị ảnh trên một figure và tự động thiết lập giá trị các đối tượng image, axes, figure để hiển thị hình ảnh.
Các hàm khác được sử dụng trong đề tài:
T=strcat(s1,s2,s3…): Ghép các chuỗi lại với nhau, trả về chuỗi nối tiếp s1s2s3…
length(): Lấy chiều dài.
T=dir(pathname): Lấy thông tin của một Folder bao gồm: Số file chứa trong folder, tên file, ngày tạo, kích thước file…
S=int2str(x): Chuyển đổi số kiểu integer thành chuỗi ký tự.
D=size(a): Trả về giá trị là ma trận có dạng [x,y] là kích thước của ma trận a.
rgb2gray(RGB) : Chuyển đổi ảnh màu sang ảnh xám
im2bw(I, level): Chuyển đổi hình ảnh xám sang hình ảnh nhị phân, dựa trên ngưỡng.
bw2 = bwareaopen(BW, P): Loại bỏ các đối tượng nhỏ khỏi hình ảnh nhị phân
imopen( IM,SE): thực hiện mở hình thái trên màu xám, IM là hình ảnh nhị phân, SE là phần tử cấu trúc
bwboundaries(BW): đánh dấu biên giới các vật thể, cũng như ranh giới của lỗ bên trong các đối tượng này(BW).
bwlabel(BW): kết nối các thành phần có trong hình ảnh nhị phân.
text(x,y,z,'string','PropertyName',PropertyValue): Tạo đối tượng văn bản trong các trục hiện tại.
length(X) : chiều dài lớn nhất của số nguyên X.
Các hàm chuyển đổi loại ảnh và kiểu dữ liệu ảnh Dither Tạo ảnh nhị phân hay ảnh RGB
gray2ind Chuyển ảnh trắng đen thành ảnh indexed im2bw Chuyển ảnh thành ảnh kiểu dữ liệu nhị phân im2double Chuyển ảnh thành ảnh kiểu dữ liệu double im2uint16 Chuyển ảnh thành ảnh kiểu dữ liệu uint16 ind2rgb Chuyển ảnh indexed thành ảnh RBG mat2gray Tạo ảnh gray scale từ ma trận
rgb2ind Chuyển ảnh RBG thành ảnh indexed rgb2gray Chuyển ảnh RBG thành ảnh gray scale Các hàm truy xuất dữ liệu ảnh
Imfinfo Truy xuất thông tin ảnh
Imread Đọc ảnh từ file và xuất ra ma trận ảnh Imwrite Lưu ma trận ảnh thành file ảnh
Các hàm biến đổi hình học
Imcrop Trích xuất một phần ảnh Imresize Thay đổi kích thước ảnh
Imdilate Phép toán giãn nở điểm ảnh nhị phân Imerode Phép toán xói mòi điểm ảnh nhị phân
Imopen Phép toán mở điểm ảnh nhị phân Imclose Phép toán đóng điểm ảnh nhị phân
Bảng 2.3 Các hàm xử lý hình ảnh khác trong Matlab.