Bước 1: Chuẩn bị dữ liệu chuyển ảnh và gán nhãn Trước khi xây dựng và huấn luyện các mô hình phân loại lá cây, bước đầu tiên và quan trọng nhất là chuẩn bị dữ liệu.. Trong đề tài này, c
Trang 1TRƯỜNG ĐẠI HỌC BÁCH KHOA – ĐẠI HỌC ĐÀ NẴNG
KHOA ĐIỆN TỬ - VIỄN THÔNG
- -
TIỂU LUẬN CUỐI KỲ HỌC PHẦN: TRÍ TUỆ NHÂN TẠO
ĐỀ TÀI: Xây dựng hệ thống nhận dạng lá cây dựa vào
hình dạng
Thành viên : Dương Trần Minh Toàn – 20DTCLC3 STT : 3
Nhóm : 10
Nhóm học phần : 20.39
Giảng viên hướng dẫn: TS Hoàng Lê Uyên Thục
Đà Nẵng, 2024
Trang 2PHƯƠNG PHÁP THỰC HIỆN
2.1 Bước 1: Chuẩn bị dữ liệu chuyển ảnh và gán nhãn
Trước khi xây dựng và huấn luyện các mô hình phân loại lá cây, bước đầu tiên và quan trọng nhất là chuẩn bị dữ liệu Quá trình này bao gồm việc thu thập dữ liệu, xử lý và làm sạch dữ liệu, gán nhãn dữ liệu tương ứng với mỗi thư mục
Trong đề tài này, chúng tôi sử dụng dữ liệu đầu vào là 5 thư mục chứa hình ảnh các loài lá cây khác nhau: Lá bồ đề, lá hoa sữa, lá trầu, lá xoài, lá rau dền Mỗi thư mục chứa
30 ảnh với nhiều góc chụp khác nhau, trong đó 3 loài lá bồ đề là của em thực hiện chụp, còn lại lá hoa sữa và lá rau dền được lấy của nhóm khác Sau đó thực hiện một số thủ thuật chỉnh sửa hình ảnh sao cho lá cây đạt độ chân thực và có hình dáng nhất định
Hình1 : Các thư mục ảnh dữ liệu để huấn luyện các mô hình
Đoạn code được sử dụng
Trang 3Kết quả
Hình 6: Thu được ảnh nhị phân của lá sau khi qua các bước xử lý
Bước 2: Trích đặc trưng Hu’s Moment
Sau khi thu thập dữ liệu ảnh của 5 loại lá cần thiết, bước tiếp theo là viết chương trình thực hiện việc trích đặc trưng cho chúng Ở đề tài này, nhóm sử dụng phương pháp trích đặc trưng phổ biến trong học máy là Hu moments Mục tiêu là trích xuất các đặc trưng
từ hình ảnh lá cây và lưu các đặc trưng này vào một tệp Excel, kèm theo nhãn được gán cho từng ảnh trong mỗi thư mục Các đặc trưng sẽ được sử dụng làm đầu vào cho các mô hình học máy nhằm phân loại các loại lá cây khác nhau
Trang 4Đối với đặc trưng Hu moments, thực hiện đọc ảnh từ tệp rồi chuyển chúng qua ảnh xám, sau đó đổi sang ảnh trắng nền đen để phù hợp với việc tính toán và cũng như sử dụng hàm để tính các đặc trưng Hu moments
Đoạn code được sử dụng
% Tính toán các moment
[height, width] = size(binary_matrix);
xgrid = repmat((-floor(height/2):1:ceil(height/2)-1)', 1, width);
ygrid = repmat(-floor(width/2):1:ceil(width/2)-1, height, 1);
m00 = sum(binary_matrix(:));
[x_bar, y_bar] = Centroid(binary_matrix, xgrid, ygrid, m00);
xnorm = x_bar - xgrid;
ynorm = y_bar - ygrid;
m11 = central_moments(binary_matrix, xnorm, ynorm, 1, 1);
m20 = central_moments(binary_matrix, xnorm, ynorm, 2, 0);
m02 = central_moments(binary_matrix, xnorm, ynorm, 0, 2);
m21 = central_moments(binary_matrix, xnorm, ynorm, 2, 1);
m12 = central_moments(binary_matrix, xnorm, ynorm, 1, 2);
m03 = central_moments(binary_matrix, xnorm, ynorm, 0, 3);
m30 = central_moments(binary_matrix, xnorm, ynorm, 3, 0);
% Tính toán các moment trung tâm chuẩn hóa
M11 = m11 / m00^(1 + (1+1)/2);
M20 = m20 / m00^(1 + (2+0)/2);
M02 = m02 / m00^(1 + (0+2)/2);
M21 = m21 / m00^(1 + (2+1)/2);
M12 = m12 / m00^(1 + (1+2)/2);
M03 = m03 / m00^(1 + (0+3)/2);
M30 = m30 / m00^(1 + (3+0)/2);
% Tính toán các moment Hu
S1 = M20 + M02;
S2 = (M20 - M02)^2 + 4*(M11)^2;
S3 = (M30 - 3*M12)^2 + (M03 - 3*M21)^2;
S4 = (M30 + M12)^2 + (M03 + M21)^2;
S5 = (M30 - 3*M12)*(M30 + M12)*((M30 + M12)^2 - 3*(M21 + M03)^2) + (3*M21 - M03)*(M21 + M03)*(3*(M30 + M12)^2 - (M03 + M21)^2);
S6 = (M20 - M02)*((M30 + M12)^2 - (M21 + M03)^2) + 4*M11*(M30 + M12)*(M21 + M03);
S7 = (3*M21 - M03)*(M30 + M12)*((M30 + M12)^2 - 3*(M21 + M03)^2) - (M30 - 3*M12)*(M21 + M03)*(3*(M30 + M12)^2 - (M03 + M21)^2);
% Chuyển đổi log các moment Hu
hu_moments_vector = [S1, S2, S3, S4, S5, S6, S7];
hu_moments_vector_norm = -sign(hu_moments_vector) *
(log10(abs(hu_moments_vector)));
% Lưu trữ tên hình ảnh, các moment Hu chuẩn hóa và nhãn
image_names{end+1} = imageFiles(k).name; % Lưu tên hình ảnh
hu_moments_all = [hu_moments_all; hu_moments_vector_norm]; % Lưu các moment vào mảng
labels = [labels; f]; % Gán nhãn theo thứ tự thư mục
Trang 5end
end
% Tạo bảng từ dữ liệu moment Hu
hu_moments_table = array2table(hu_moments_all, 'VariableNames', {'S1', 'S2', 'S3',
'S4', 'S5', 'S6', 'S7'});
hu_moments_table.ImageName = image_names'; % Thêm tên hình ảnh vào cột cuối cùng
hu_moments_table.Label = labels; % Thêm nhãn vào cột cuối cùng
% Đổi vị trí cột tên hình ảnh thành cột đầu tiên
hu_moments_table = movevars(hu_moments_table, 'ImageName', 'Before', 1);
% Xuất bảng ra file Excel
excelFilePath = fullfile("C:\Users\VI TINH BACH KHOA\Desktop\AI\FINAL", 't1.xlsx'); % Đường dẫn lưu file Excel
writetable(hu_moments_table, excelFilePath, 'Sheet', 1, 'WriteRowNames', true); % Lưu bảng vào file Excel
disp(['Đã xuất bảng Hu moments ra file: ', excelFilePath]); % Thông báo khi xuất xong
Kết quả:
Xuất được file Excel đặc trưng Hu moments của tất cả các lá và thứ tự gán nhãn của mỗi lá như sau:
- Lá hoa sữa: 1
- Lá rau dền: 2
- Lá trầu: 3
Hình 7: Bảng Excel đặc trưng Hu moments của lá cây
Trang 6Bước 3 Huấn luyện và kiểm tra mô hình nhận dạng lá cây nói trên dùng KNN với K = 5 Hiển thị kết quả Biểu diễn kết quả bằng ma trận nhầm lẫn (có ghi chú đầy đủ) Nhận xét Cho biết phương pháp đánh giá là hold-out cross validation, với số mẫu trong tập train là 70%, số mẫu trong tập test là 30%; tiêu chí đánh giá là độ chính xác
Code được sử dụng
% Đọc dữ liệu từ file CSV
data = readtable('t1.xlsx');
X = data{:, 2:8}; % 7 giá trị Hu moments
y = data.Label;
% Chuẩn hóa dữ liệu
scaler = @(X) (X - mean(X)) / std(X);
X = scaler(X);
% Các tham số cho KNN và phân chia chéo
k_values = [1, 3, 5, 7, 9]; % Các giá trị K để kiểm tra
num_classes = length(unique(y));
cv = cvpartition(y, 'KFold', 5);
% Theo dõi các chỉ số tổng quan cho mỗi K
all_metrics = struct();
for k_idx = 1:length(k_values)
K = k_values(k_idx);
disp(['Đang kiểm tra với K = ' num2str(K)]);
total_conf_matrix = zeros(num_classes, num_classes);
for fold = 1:cv.NumTestSets
disp(['Fold ' num2str(fold)]);
% Chia dữ liệu thành tập huấn luyện và tập kiểm tra cho fold này
trainIdx = training(cv, fold);
testIdx = test(cv, fold);
X_train = X(trainIdx, :);
y_train = y(trainIdx);
X_test = X(testIdx, :);
y_test = y(testIdx);
% Huấn luyện mô hình KNN
mdl = fitcknn(X_train, y_train, 'NumNeighbors', K);
% Kiểm tra mô hình KNN
y_pred = predict(mdl, X_test);
% Ma trận nhầm lẫn cho fold này
conf_matrix = confusionmat(y_test, y_pred);
total_conf_matrix = total_conf_matrix + conf_matrix;
end
% Hiển thị ma trận nhầm lẫn
Trang 7disp(['Ma trận nhầm lẫn cho K = ' num2str(K)]);
disp(total_conf_matrix);
% Tạo và lưu biểu đồ ma trận nhầm lẫn
figure;
confusionchart(total_conf_matrix,
'RowSummary','row-normalized',
'ColumnSummary','column-normalized');
title(['Ma trận nhầm lẫn cho K = ' num2str(K)]);
% Lưu hình ảnh ma trận nhầm lẫn
saveas(gcf, ['Confusion_Matrix_K_' num2str(K) '.png']);
% Tính toán Precision, Recall, F1-score tổng thể (trung bình cho tất cả lớp)
precision = mean(diag(total_conf_matrix) / sum(total_conf_matrix, 2));
recall = mean(diag(total_conf_matrix) / sum(total_conf_matrix, 1)');
f1_score = 2 * (precision * recall) / (precision + recall);
% Độ chính xác tổng thể
accuracy = sum(diag(total_conf_matrix)) / sum(total_conf_matrix(:));
% Hiển thị các chỉ số tổng quan
disp(['Độ chính xác tổng thể cho K = ' num2str(K) ': ' num2str(accuracy * 100)
'%']);
disp(['Precision tổng thể cho K = ' num2str(K) ': ' num2str(precision)]); disp(['Recall tổng thể cho K = ' num2str(K) ': ' num2str(recall)]);
disp(['F1-score tổng thể cho K = ' num2str(K) ': ' num2str(f1_score)]);
% Lưu trữ các chỉ số
all_metrics.(['K_' num2str(K)]) = struct('conf_matrix', total_conf_matrix,
'accuracy', accuracy,
'precision', precision,
'recall', recall,
'f1_score', f1_score);
end
disp('Xuất hình ảnh ma trận nhầm lẫn hoàn tất.');
Kết quả
Trang 8Ma trận nhầm lẫn
Bước 4
Huấn luyện và kiểm tra mô hình nhận dạng lá cây nói trên dùng ANN 1 lớp ẩn, 10 neuron lớp ẩn, hàm kết nối là hàm tuyến tính, hàm kích hoạt là hàm sigmoid, tốc độ học 0.1 Hiển thị kết quả Biểu diễn kết quả bằng ma trận nhầm lẫn (có ghi chú đầy đủ) Nhận xét
Trang 9Đoạn code sử dụng
% Đọc dữ liệu từ file CSV
data = readtable("C:\Users\VI TINH BACH KHOA\Desktop\AI\FINAL\New folder\t1.xlsx");
X = data{:, 2:8}; % 7 Hu moments
y = data.Label;
% Chuẩn hóa dữ liệu
scaler = @(X) (X - mean(X)) / std(X); % Hàm chuẩn hóa
X = scaler(X);
% Chuyển đổi labels thành one-hot encoding
labels_unique = unique(y);
num_classes = length(labels_unique);
y_encoded = zeros(length(y), num_classes);
for i = 1:length(y)
y_encoded(i, y(i) == labels_unique) = 1;
end
% Khởi tạo các tham số
hidden_size = 1;
learning_rate = 0.1;
epochs = 2000;
fold_num = 1;
% K-fold cross-validation (5 fold)
k = 5;
cv = cvpartition(y, 'KFold', k);
total_conf_matrix = zeros(num_classes, num_classes);
all_metrics = [];
for fold = 1:k
disp(['=' repmat('=', 1, 50)]);
disp(['Fold ' num2str(fold)]);
disp(['=' repmat('=', 1, 50)]);
% Chia tập huấn luyện và kiểm tra cho fold này
trainIdx = training(cv, fold);
testIdx = test(cv, fold);
X_train = X(trainIdx, :);
y_train = y_encoded(trainIdx, :);
X_test = X(testIdx, :);
y_test = y_encoded(testIdx, :);
% Huấn luyện mô hình
[W1, b1, W2, b2] = train_model(X_train, y_train, hidden_size, learning_rate, epochs);
% Dự đoán và đánh giá
[conf_matrix, accuracy, precision, recall, f1] = predict_and_evaluate(X_test, y_test, W1, b1, W2, b2, labels_unique);
Trang 10total_conf_matrix = total_conf_matrix + conf_matrix;
% Kiểm tra các chỉ số và lưu trữ kết quả
assert(isscalar(accuracy), 'Accuracy is not a scalar');
assert(isscalar(precision), 'Precision is not a scalar');
assert(isscalar(recall), 'Recall is not a scalar');
assert(isscalar(f1), 'F1-score is not a scalar');
all_metrics = [all_metrics; [fold, accuracy, precision, recall, f1]];
% Hiển thị kết quả cho fold
disp(['Accuracy: ' num2str(accuracy)]);
disp(['Precision: ' num2str(precision)]);
disp(['Recall: ' num2str(recall)]);
disp(['F1-score: ' num2str(f1)]);
disp('Confusion Matrix:');
disp(conf_matrix);
% Vẽ ma trận nhầm lẫn cho mỗi fold
plot_confusion_matrix(conf_matrix, fold);
fold_num = fold_num + 1;
end
% Hiển thị ma trận nhầm lẫn tổng hợp
disp('Confusion Matrix after 5 folds:');
disp(total_conf_matrix);
figure;
heatmap(total_conf_matrix, 'Title', 'Confusion Matrix after 5 folds', 'XLabel',
'Predicted Labels', 'YLabel', 'True Labels');
% Tính toán các chỉ số trung bình
mean_metrics = mean(all_metrics(:, 2:end), 1);
disp('Average metrics after 5 folds:');
disp(mean_metrics);
%% Hàm huấn luyện mô hình
function [W1, b1, W2, b2] = train_model(X, y, hidden_size, learning_rate, epochs) [m, input_size] = size(X);
output_size = size(y, 2);
% Khởi tạo tham số
W1 = randn(input_size, hidden_size) * 0.01;
b1 = zeros(1, hidden_size);
W2 = randn(hidden_size, output_size) * 0.01;
b2 = zeros(1, output_size);
% Huấn luyện mô hình
for epoch = 1:epochs
% Forward propagation
[~, a1, ~, a2] = forward_propagation(X, W1, b1, W2, b2);
% Tính toán đạo hàm (backpropagation)
[dW1, db1, dW2, db2] = backward_propagation(X, y, a1, a2, W2);
% Cập nhật trọng số
Trang 11W1 = W1 - learning_rate * dW1;
b1 = b1 - learning_rate * db1;
W2 = W2 - learning_rate * dW2;
b2 = b2 - learning_rate * db2;
if mod(epoch, 100) == 0
loss = mean(sum((y - a2).^2, 2));
disp(['Epoch ' num2str(epoch) '/' num2str(epochs) ', Loss: '
num2str(loss)]);
end
end
end
%% Hàm truyền trực tiếp (forward propagation)
function [z1, a1, z2, a2] = forward_propagation(X, W1, b1, W2, b2)
z1 = X * W1 + b1;
a1 = 1 / (1 + exp(-z1)); % Sigmoid activation
z2 = a1 * W2 + b2;
a2 = 1 / (1 + exp(-z2)); % Sigmoid activation for output layer end
%% Hàm lan truyền ngược (backward propagation)
function [dW1, db1, dW2, db2] = backward_propagation(X, y, a1, a2, W2)
m = size(X, 1);
dz2 = a2 - y;
dW2 = (a1' * dz2) / m;
db2 = sum(dz2, 1) / m;
da1 = dz2 * W2';
dz1 = da1 * (a1 * (1 - a1)); % Derivative of sigmoid
dW1 = (X' * dz1) / m;
db1 = sum(dz1, 1) / m;
end
%% Hàm dự đoán và đánh giá
function [conf_matrix, accuracy, precision, recall, f1] =
predict_and_evaluate(X_test, y_test, W1, b1, W2, b2, labels_unique) y_pred = predict(X_test, W1, b1, W2, b2);
[~, y_test_orig] = max(y_test, [], 2);
% Tính toán ma trận nhầm lẫn
conf_matrix = confusionmat(y_test_orig, y_pred);
% Tính các chỉ số
accuracy = sum(diag(conf_matrix)) / sum(conf_matrix(:));
precision = precision_recall_fscore(conf_matrix, 'precision'); recall = precision_recall_fscore(conf_matrix, 'recall');
f1 = precision_recall_fscore(conf_matrix, 'f1');
% Ensure these values are scalars, not arrays
assert(isscalar(accuracy), 'Accuracy is not a scalar');
assert(isscalar(precision), 'Precision is not a scalar');
assert(isscalar(recall), 'Recall is not a scalar');
assert(isscalar(f1), 'F1-score is not a scalar');
Trang 12% Convert numeric predictions and ground truth back to labels
y_pred_labels = labels_unique(y_pred);
y_test_labels = labels_unique(y_test_orig);
% Print detailed comparison
disp('Ground Truth:');
disp(y_test_labels');
disp('Predicted:');
disp(y_pred_labels');
end
%% Hàm dự đoán
function y_pred = predict(X, W1, b1, W2, b2)
[~, ~, ~, a2] = forward_propagation(X, W1, b1, W2, b2);
[~, y_pred] = max(a2, [], 2);
end
%% Hàm tính các chỉ số precision, recall và F1-score
function score = precision_recall_fscore(conf_matrix, metric)
% Số lớp
num_classes = size(conf_matrix, 1);
% Tính true positives, false positives, false negatives
tp = diag(conf_matrix); % True Positives
fp = sum(conf_matrix, 1)' - tp; % False Positives
fn = sum(conf_matrix, 2) - tp; % False Negatives
% Tính precision, recall, F1-score cho mỗi lớp
precision_per_class = tp / (tp + fp);
recall_per_class = tp / (tp + fn);
f1_per_class = 2 * (precision_per_class * recall_per_class) / (precision_per_class + recall_per_class);
% Loại bỏ NaN (trường hợp khi TP + FP = 0 hoặc TP + FN = 0)
precision_per_class(isnan(precision_per_class)) = 0;
recall_per_class(isnan(recall_per_class)) = 0;
f1_per_class(isnan(f1_per_class)) = 0;
% Tính kết quả cho từng metric
if strcmp(metric, 'precision')
score = mean(precision_per_class); % Macro-average precision
elseif strcmp(metric, 'recall')
score = mean(recall_per_class); % Macro-average recall
elseif strcmp(metric, 'f1')
score = mean(f1_per_class); % Macro-average F1-score
end
end
%% Hàm vẽ ma trận nhầm lẫn
function plot_confusion_matrix(conf_matrix, fold_num)
figure;