Professional Documents
Culture Documents
Báo Cáo NNLT
Báo Cáo NNLT
Ngày nay, khoa học công nghệ ngày càng phát triển, cùng với đó các cảm biến ảnh,
xử lí ảnh ngày càng trở nên đa dạng. Việc sử dụng hình ảnh khuôn mặt không chỉ sử
dụng trong xác thực, định danh mà còn có thể hướng đến các ứng dụng khác về sức
khỏe như xác định chỉ số BMI, ứng dụng vào y học. Đề tài này chúng em chọn hướng
đến ước lượng chỉ số BMI từ hình ảnh khuôn mặt thông qua việc xây dựng một mô hình
hồi quy tuyến tính.
Bài báo cáo được hoàn thành nhằm mục đích tìm hiểu, củng cố và trang bị cho bản
thân kiến thức về ngôn ngữ lập trình C++ với thư viện opencv. Qua đó vận dụng những
kiến thức thu thập được để có thể vận dụng làm bài tập, ứng dụng vào dự án được đề ra.
Xin chân thành cảm ơn cô Trần Thị Thanh Hải đã tạo môi trường giúp chúng em có
thể làm project này cũng như trang bị kiến thức, tài liệu cho chúng em!
1
Báo cáo bài tập lớn NNLT Nhóm 6
MỤC LỤC
LỜI NÓI ĐẦU...........................................................................................................................1
DANH MỤC HÌNH ẢNH.........................................................................................................3
DANH MỤC KÝ HIỆU VÀ CHỮ VIẾT TẮT.......................................................................4
Đóng góp của từng thành viên.................................................................................................5
CHƯƠNG 1. LÝ THUYẾT CHUNG......................................................................................5
1.3 Xử lí cơ sở dữ liệu.............................................................................................................6
1.3.1 Tính toán đặc trưng histogram RGB........................................................................7
1.3.2 Tính toán đặc trưng HOG.........................................................................................7
2
Báo cáo bài tập lớn NNLT Nhóm 6
TÀI LIỆU THAM KHẢO.....................................................................................................20
3
Báo cáo bài tập lớn NNLT Nhóm 6
DANH MỤC KÝ HIỆU VÀ CHỮ VIẾT TẮT
4
Báo cáo bài tập lớn NNLT Nhóm 6
Để phát huy ưu thế của từng thành viên đồng thời để các thành viên đều hiểu được chương
trình, phát huy tối đa lợi thế làm việc nhóm, chúng em có bảng phân chia nhiệm vụ như
sau:
Và như đề án project này thì cũng đã thể hiện được mục đích của nó. Thông qua hình
ảnh về khuôn mặt một người, chúng em đi ước tính chỉ số BMI của người đó thông qua
hồi quy tuyến tính sử dụng thư viện OpenCV lập trình ngôn ngữ C++.
5
Báo cáo bài tập lớn NNLT Nhóm 6
Việc chọn môi trường lập trình ảnh hưởng rất nhiều đến quá trình làm, thực hiện dự
án, và từ những mặt lợi ích đã nêu thì chúng em đã dùng ngôn ngữ C++ với thư viện
Opencv trên Visual Studio (Hình 1. 2. Môi trường lập trình).
6
Báo cáo bài tập lớn NNLT Nhóm 6
1.3 Xử lí cơ sở dữ liệu
Để thực hiện đề án này thì trước tiên ta phải xử lí ảnh. Trước tiên ta phải đọc ảnh,
từ dữ liệu ảnh đầu vào là ảnh ta thu được 1 ma trận Mat của ảnh đó. Trong OpenCV
với giao diện C++, tất cả các kiểu dữ liệu ảnh, ma trận đều được lưu dưới dạng
cv::Mat. Hàm imread sẽ đọc ảnh đầu vào và lưu vào biến.
Sau đó, ta tính toán ra vector đặc trưng của ảnh để ước tính BMI. Bằng cách sử
dụng các phương pháp rút trích đặc trưng ảnh ta sẽ thu được vector đặc trưng của ảnh.
Nói một cách khác đó chính là bạn mã hóa hình ảnh thành một vector, và vector này
mang những đặc trưng (các số thực) đại diện cho ảnh đó. Một vector biểu diễn ảnh có
thể tính toán đặc trưng histogram RGB của ảnh, histogram of gradient (HOG), đặc trưng
sift.. và có thể sử dụng các hàm của OpenCV. Trước tiên chúng ta đi tìm hiểu về một số
tính toán để ra vector dặc trưng.
7
Báo cáo bài tập lớn NNLT Nhóm 6
Từ một ảnh đầu vào ta thu được biểu đồ thể hiện màu ảnh như ở Hình 1. 3. Ví dụ về
histogram RGBNhưng do đây là biểu đồ về màu ảnh nên khi chụp ở độ sáng, phông nền
khác nhau cũng ảnh hưởng khá nhiều đến kết uqar thu được và khi ước tính có thể sẽ sai
số lớn. Vì vậy nhóm chúng em sẽ thực hiện biểu diễn vector đặc trưng của ảnh dựa vào
HOG.
Bản chất của phương pháp HOG là sử dụng thông tin về sự phân bố của các cường
độ gradient (intensity gradient) hoặc của hướng biên (edge directins) để mô tả các đối
tượng cục bộ trong ảnh. Các toán tử HOG được cài đặt bằng cách chia nhỏ một bức ảnh
thành các vùng con, được gọi là “tế bào” (cells) và với mỗi cell, ta sẽ tính toán một
histogram về các hướng của gradients cho các điểm nằm trong cell. Ghép các histogram
lại với nhau ta sẽ có một biểu diễn cho bức ảnh ban đầu. Để tăng cường hiệu năng nhận
dạng, các histogram cục bộ có thể được chuẩn hóa về độ tương phản bằng cách tính một
ngưỡng cường độ trong một vùng lớn hơn cell, gọi là các khối (blocks) và sử dụng giá
trị ngưỡng đó để chuẩn hóa tất cả các cell trong khối. Kết quả sau bước chuẩn hóa sẽ là
một vector đặc trưng có tính bất biến cao hơn đối với các thay đổi về điều kiện ánh sáng
như trong Hình 1. 4. Đặc trưng HOG của ảnh
8
Báo cáo bài tập lớn NNLT Nhóm 6
Với mỗi hình ảnh đầu vào kích thước 64x128, chia thành các block 16x16 chồng
nhau, sẽ có 7 block ngang và 15 block dọc, nên sẽ có 7x15 = 105 blocks. Mỗi block
gồm 4 cell. Khi áp dụng biểu đồ 9-bin cho mỗi cell, mỗi block sẽ được đại diện bởi một
vector có kích thước 36x1. Vì vậy, khi nối tất cả các vector trong một block lại với
nhau, ta sẽ thu được vector đặc trưng HOG của ảnh có kích thước 105x36x1 = 3780x1.
Theo như sơ đồ tính toán HOG (Hình 1. 5. Sơ đồ tính toán HOG) ta gồm các bước làm
sau:
Chuẩn hóa mức sáng và màu sắc của ảnh: việc dùng ảnh màu và các chuẩn hóa trên ảnh
cho kết quả tốt hơn.
Tính gradient của ảnh.
Vote hướng vào cell (histogram): Ở bước 2, ta đã tính được ảnh gradient theo trục x (dx)
và gradient theo trục y (dy). Và ta tính góc và biên độ tương ứng của từng pixel đang
xét như Hình 1. 6. Vote hướng vào cell
9
Báo cáo bài tập lớn NNLT Nhóm 6
Chuẩn hóa theo block: Vì hiện tại mỗi cell đang mang trong mình histogram trên vùng
ảnh 8x8, các thông tin này mang tính chất cục bộ. Vì vậy tác giả đã đưa ra nhiều cách
chuẩn hóa khác nhau dựa trên các khối (block) chồng lấn (overlap) nhau.
Trích vector đặc trưng của các block đã chuẩn hóa cho ảnh 64x128.
Sau khi đã tính toán vector đặc trưng của ảnh, ta biểu diễn vector này cho từng ảnh
trong cơ sở dữ liệu tương ứng với các chỉ số BMI của nó, một CSDL sẽ có 1 vector đặc
trung và 1 chỉ số BMI tương ứng.
Mục tiêu của giải thuật hồi quy tuyến tính là dự đoán giá trị của một hoặc nhiều
biến mục tiêu liên tục (continuous target variable) y dựa trên một ma trận đầu vào ma
trận x. Linear hay tuyến tính hiểu một cách đơn giản là thẳng, phẳng. Trong không gian
hai chiều, một hàm số được gọi là tuyến tính nếu đồ thị của nó có dạng một đường
thẳng. Trong không gian ba chiều, một hàm số được goi là tuyến tính nếu đồ thị của nó
có dạng một mặt phẳng. Trong không gian nhiều hơn 3 chiều, khái niệm mặt phẳng
không còn phù hợp nữa, thay vào đó, một khái niệm khác ra đời được gọi là siêu mặt
phẳng (hyperplane).
Y = Xω = ŷ (1. 1)
10
Báo cáo bài tập lớn NNLT Nhóm 6
Trong đó:
[] [ ] []
y1 ω1
1 … x1 k
y ω
Y= 2 , X= ⋮ ⋱ ⋮ , ω= 2
⋮ ⋮
1 … x nk
yn ωk
Y là giá trị thực của output (dựa trên số liệu thống kê chúng ta có trong tập training
data), trong khi ŷ là giá trị mà mô hình Linear Regression dự đoán được. Nhìn chung, Y
và ŷ là hai giá trị khác nhau do có sai số mô hình, tuy nhiên, chúng ta mong muốn rằng
sự khác nhau này rất nhỏ. Chúng ta cần đi xác định hệ số ω.
Ví dụ khi ta ước tính cân nặng dựa vào chiều cao như trên Hình 1. 7. Ước tính cân
nặng dựa vào chiều caoCác chấm đỏ là dữ liệu đầu vào (cơ sở dữu liêu) gồm chiều cao
và cân nặng, đường màu xạnh chính là đường sau khi ước tính, tính được ω và biễn diễn
y = ω.x, ta thấy các chấm đỏ gần với các đường xanh vậy là kết quả của việc ước tính
khá sát với thực
Với dữ liệu vào ma trận X (vector biểu diễn ảnh) và ma trận Y (chỉ số BMI) ta sẽ
tính được ma trận β.
ω = Y.X-1 (1. 2)
ω = (XT.X)-1.XT.Y (1. 3)
Như vậy từ đây ta đã xác định được ma trận ω và với dữ liệu mới (vector hog của ảnh
khác CSDL) ta sẽ thu được giá trị y (chỉ số BMI).
11
Báo cáo bài tập lớn NNLT Nhóm 6
Nhưng điều gì xảy ra nếu (X T.X) không thể đảo ngược (số ít hoặc suy biến). Đến đây,
vì để xác định một cách chính xác, nhóm chúng em sử dụng một phương pháp khác để
xác định các hệ số mà không phải tính nghịch đảo ma trận. Đó là phương pháp sử dụng
Gradient desent.
Hàm mất mát của thuật toán có dạng: (trong đó: m là số lượng giá trị đúng. )
Nhiệm vụ của chúng ta là tìm vector w sao cho hàm mất mát J(w) nhỏ nhất. Giờ cần
một thuật toán để tìm giá trị nhỏ nhất của hàm J. Đó chính là gradient descent.
∂ J ( ω)
Dựa vào đạo hàm theo từng biến của hàm mất mát, ta sẽ xác định w i=w i−α ∂ w
i
m
α
Với hàm mất mát dạng như trên, ta có: ω i=ω i− ∑
m i=1
( x (i) ω− y (i) ) x (ji)
12
Báo cáo bài tập lớn NNLT Nhóm 6
Với các giá trị w tìm được, chúng ta tính giá trị hàm mất mát. Lặp lại điều này đến
khi hàm mất mát đủ nhỏ, từ đó chúng ta xác định được ma trận w và hàm ŷ=x . ω.
Việc số lần lặp lại ảnh hưởng đến giá trị hàm mất mát rất nhiều, lặp lại cang nhiều thì
độ chính xác càng cao (Hình 1. 8. Hàm mất mát phụ thuộc vào số lần lặp lại ), nhưng
lặp lại nhiều ảnh hưởng tới tốc dộ xử lí của chương trình cũng như bộ nhớ khi thực hiện
chương trình.
Hình 1. 8. Hàm mất mát phụ thuộc vào số lần lặp lại
Hình 1. 8. Hàm mất mát phụ thuộc vào số lần lặp lại ta thấy, số lần lặp lại từ 0 – 1000
có sự thay đổi rất lớn đến hàm mất mát, độ chính xác cao hơn và càng tăng số lần lặp thì
hàm mất mát càng gần với 0.
Chúng ta mong muốn rằng sự sai khác e giữa giá trị thực y và ŷ giá trị dự đoán là nhỏ
nhất. Nói cách khác, chúng ta muốn giá trị sau đây càng nhỏ càng tốt:
1 e2 = 1 1
( y − ŷ) = (y – x.ω) (1. 8)
2 2
2 2 2
13
Báo cáo bài tập lớn NNLT Nhóm 6
Sau khi tính được sai số của bài toán, ta sẽ tiến hành đánh giá về độ chính xác khi
ước lượng BMI thông qua khuôn mặt dựa vào chỉ số sai số.
Sau khi tìm hiểu qua về lý thuyết chung, chúng ta sẽ thự hành tìm hiểu về đề tài này.
14
Báo cáo bài tập lớn NNLT Nhóm 6
}
Đồng thời khi đọc ảnh xong cũng đọc luôn giá trị BMI của người có trong CSDL và
lưu vào 1 vector, thứ tự BMI trong vetor này sẽ tương ứng thứ tự với ảnh trong vector
đọc ảnh. Trong CSDL, ảnh của một người chụp theo các góc khác nhau cùng chứa trong
một thư mục con, các ảnh sẽ được gán cùng một giá trị BMI. Vì thế, để thuận tiện, hàm
đọc và lấy giá trị BMI (get _Y) có biến “inter” để lấy cùng một giá trị BMI “inter” lần
của các ảnh trong cùng một thư mục con.
15
Báo cáo bài tập lớn NNLT Nhóm 6
2.1.3 Tính toán một vector biểu diễn ảnh
Có thể tính trực tiếp như công thức, các bước đã đề trên lý thuyết nhưng để thuận
lợi cho việc tính toán sau thì nhóm chúng em sử dụng hàm có sẵn trong thư viện
OpenCV.
ŷ=ω0 +ω 1 x 1+ ω2 x2 +... … .+ω n x n
Hàm đa tuyến tính ŷ n biến có chứa hệ số tự do ω 0, nên ta cần tạo vector đầu vào n
+ 1 chiều với giá trị đầu của vector là 1.
//Tính vector đặc trưng hog của 1 ảnh đã đọc để ước lượng
template<typename T>
vector<T> get_hogImage(Mat input) {
resize(input, input, Size(64, 128)); //Đặt lại size của ảnh
HOGDescriptor hog;
vector<float> ders;
vector<T> Hog;
vector<Point> locs;
Hog.push_back(1);
hog.compute(input, ders, Size(32, 32), Size(0, 0), locs); //Tính HOG
for (int i = 0; i < ders.size(); i++) {
Hog.push_back((T)ders.at(i));
}
return Hog;
}
2.1.4 Biểu diễn các dữ liệu ảnh như đã thu thập bằng vector đặc trưng biểu diễn
Ảnh sau khi đọc sẽ được lưu dưới dạng ma trận và sau khi sử dụng vector đặc trưng
và tính ở bước trên ta sẽ thu được vector biểu diễn cho ảnh. Khi làm bài, để chương
trình được đơn giản hơn, chúng em tính hog và đọc ảnh trong cùng một bước.
16
Báo cáo bài tập lớn NNLT Nhóm 6
cout << "readImgs...." << endl;
glob(src_path + pattern + pattern1, fileNames, true); //Đọc file
for (auto file : fileNames)
{
cout << file << endl;
img = imread(file);
input.push_back(get_hogImage<T>(img)); //Tính hog và lưu vào cuối vector
i++;
}
cout << "Complete.." << i << " image" << endl;
return input;
}
2.1.5 Cài đặt thuật toán hồi qui đa tuyến tính(Multiple linear regression) để tìm
mô hình dự toán BMI của một khuôn mặt từ ảnh
Bước quan trọng trong việc ước lượng đó chính là xác định chỉ số của phương trình
tuyến tính. Theo như công thức = (XT.X)-1.XT.Y (1. 3) ta cần xác
định ma trậnω. Có thể có nhiều cách: tính trực tiếp, sử dụng thư viện của bên thứ ba,
dựa vào gradient... Để thuận tiện cho việc tính toán, chúng em tạo class để thực hiện và
gắn vào thư viện “Mlr.h”. Kí hiệu ma trận ω là B.
// Tính hàm chi phí đo sai số bình phương trung bình gốc giữa các giá trị dự đoán
(trước)(X*B) và các giá trị thực (Y) tương úng
double Mlr::cost_fuction(vector<vector<double> > X,vector<double>
Y,vector<double> B){
double loss = 0;
int n = 2 * rows;
for (int i = 0; i < rows; i++) {
double temp = 0;
for (int j = 0; j < colums; j++) {// X(i)*B
temp += X[i][j] * B[j];
}
loss += (Y[i] - temp) * (Y[i] - temp);// tổng {(Y(i) - X(i)*B)^2}
}
return loss / n ;// cost fuction
}
//cập nhật các hệ số, dựa trên đạo hàm theo từng biến của hàm mất mát khi thử
nghiệm trước đó
void Mlr::update(vector<vector<double> > X, vector<double> Y, vector<double>
17
Báo cáo bài tập lớn NNLT Nhóm 6
&B,double learning_rate){
vector<double> B_temp;
for (int i = 0; i < rows; i++) {
double temp = 0;
for (int j = 0; j < colums; j++) {//X(i)*B
temp += X[i][j] * B[j];
}
B_temp.push_back(temp - Y[i]); //X(i)* B - Y(i)
}
for (int i = 0; i < colums; i++) {
double temp1 = 0;
for (int j = 0; j < rows; j++) {
temp1 += B_temp[j] * X[j][i];//tổng {(X(i)*B - Y(i)]*X(i)[j]}
}
B[i] -= learning_rate * (temp1 / rows);//learning rate: tốc độ học
}
}
//Tính hàm chi phí và cập nhật các hệ số sau “inter” lần lặp(khi độ lớn hàm cost
fuction đủ nhỏ)
vector<double> Mlr::train(vector<vector<double> > X, vector<double> Y,
vector<double>& B, double learning_rate, int inter) {
vector<double> cost_hist;
for (int i = 0; i < inter; i++) {
update(X, Y, B, learning_rate);
cost_hist.push_back(cost_fuction(X, Y, B));
cout << cost_fuction(X, Y, B) << endl; // in ra giá trị hàm mất mát
}
return cost_hist; // trả về vector lưu các giá trị hàm mất mát}
Sau khi xác định được hệ số (ma trận B), ta lưu các giá trị của B vào file text và
tiến hành ước lượng. Biến “inter” chính là số lần lặp lại để xác định hàm mất mát nhỏ
nhất, nhưng ảnh hưởng tới tốc độ hay thời gian chạy chương trình (1000 lần mất gần
2’, 10000 lần mất tầm 7’).
//Lưu B
template<typename T>
void set_bias(string name, vector<T> B) {//name: đường dẫn lưu B
ofstream bias(name); // mở file
bias << B.size() << " ";// lưu kích thước của B
for (int i = 0; i < B.size(); i++) {
18
Báo cáo bài tập lớn NNLT Nhóm 6
bias << B[i] << " ";// lưu từng phần tử của B
}
bias.close();
}
//Ước lượng BMI
//Đầu vào: value:
//B: ma trận hệ số của hàm Y = X*B
//size: size của B
template<typename T>
T predic(vector<T> value, vector<T> B, size_t size) {
T y = 0;
for (int i = 0; i < size; i++) {
y += (T)(value[i] * B[i]);
}
return y;
}
#include<iostream>
#include<fstream>
#include<vector>
#include"loadImage.h";
#include"Mlr.h";
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include<opencv2/objdetect.hpp>
#include<opencv2/opencv.hpp>
using namespace img;
using namespace std;
using namespace cv;
int main() {
//Tính ma trận B bằng thuật toán Gradient desent: Y = X*B
vector<vector<double> > X = readHOGImgs<double>("D:\\test1\\");
19
Báo cáo bài tập lớn NNLT Nhóm 6
// Tính ma trận X chứa giá trị biến đầu vào của ảnh trong CSDL(140 ảnh)
vector<double> Y = get_Y<double>("D:/BMI/",Y, 7);// Lấy giá trị BMI
Mlr b1(X, Y, 3781, 20);// thiết lập ma trận X, Y
vector<double> B = b1.setB_zeros();// thiết lập ma trận B
vector<double> cost = b1.train(X, Y, B, 0.001, 1000);
set_bias("D:/test/B_1000_nn.txt", B);// lưu B vào text}
2.1.7 Thực hiện đánh giá với tối thiểu 10 người mới không có trong CSDL đã thu,
và đánh giá sai số ước lượng
Với dữ liệu vào của 10 người ta sẽ xác định được chỉ số BMI tương ứng và từ đấy
đánh giá ước lượng sai số. Đây là đánh giá đối với 1 người:
20
Báo cáo bài tập lớn NNLT Nhóm 6
Hình 2. 1. Kết quả ước lượng là kết quả của ước lượng BMI với 2 người không có
trên cơ sở dữ liệu. Trên mỗi ảnh có nhận diện khuôn mặt và tính chỉ số BMI của khuôn
mặt vừa nhận diện. Chỉ số BMI được ghi lên tương ứng. Đây là ước lượng dựa vào
linaer regression và có giá trị sai số nhất định.
Mặc dù chương trình của nhóm em đã chạy và ước lượng BMI từ mặt người,
Nhưng từ giá trị sai số ta thấy, tuy đây là ước lượng nên vẫn còn sai số nhưng sai số
khá nhiều và chưa hẳn tối ưu bài toán. Để chính xác hơn, ta phải sử dụng nhiều hơn
vector biểu diễn ảnh và kĩ thuật machine learning cần được nâng cao hơn. Và dự án
này vẫn có rất nhiều hướng có thể phát triển và ứng dụng vào y học hay cuộc sống
hàng ngày của chúng ta để có thể có một cơ thể khỏe mạnh nhất.
KẾT LUẬN
Thông qua đề tài này: “Ước lượng BMI của người dựa trên ảnh khuôn mặt” chúng
em đã tìm hiểu thêm về những kỹ năng chuyên môn (sử dụng thông thạo hơn ngôn ngữ
lập trinh, sử dụng thư viện OpenCV, tạo thư viện, xử lí ảnh,..) cũng như kỹ năng mềm
21
Báo cáo bài tập lớn NNLT Nhóm 6
(kỹ năng giao tiếp, kỹ năng truyền đạt, kỹ năng làm việc nhóm...). Nhóm em cảm ơn cô
Trần Thị Thanh Hải đã tạo điều kiện cho chúng em làm đề tài này. Cách làm và báo cáo
có thể có nhiều điều thiếu sót mong cô có thể phản hồi lại với chúng em đê lần làm bài
lần sau của chúng em tốt hơn.
PHỤ LỤC
2. https://machinelearningcoban.com/2016/12/28/linearregression/
3. https://www.programmersought.com/article/54454971788/
22