You are on page 1of 34

1.

Cho hình sau:

0 0 0 0 0 0 0
0 2 4 5 0 0 0
0 6 0 7 8 0 0
3 5 9 0 10 12 0
4 6 0 0 0 8 0
5 7 0 0 3 8 0
0 9 2 14 3 0 0
Matrix (b)
a) Reconstruct lại hình sử dụng 3 và 5 eigen value lớn nhất bằng tay , so sánh sự khác
biệt (2đ)
b) Lập trình Reconstruct lại hình sử dụng 3 và 5 eigen value lớn nhất sử dụng hàm
opencv (1.5đ)
Bài làm
a. Reconstruct lại hình sử dụng 3 và 5 eigen value lớn nhất bằng tay
Bước 1: Tính kỳ vọng của dữ liệu theo hàng
N
1
x= ∑x
N n=1 n

Tại hàng 1
1
x 1= ( 0 ×7 )=0
7

Tại hàng 2
1
x 2= ( 2+ 4+5+ 4 × 0 )=1,5714
7

Tại hàng 3
1
x 3= ( 6+ 7+8+0 × 4 )=3
7

Tại hàng 4
1
x 4 = ( 3+5+9+10+ 12+ 0× 2 )=5,5714
7

1
Tại hàng 5
1
x 5= ( 4+6+ 8+0 × 4 ) =2,5714
7

Tại hàng 6
1
x 6= ( 5+7 +3+8+0 × 3 )=3,2857
7

Tại hàng 7
1
x 7= ( 9+ 2+ 14+3+ 0× 3 )=4
7
x
0 0 0 0 0 0 0 0
0 2 4 5 0 0 0 1,5714
0 6 0 7 8 0 0 3
3 5 9 0 10 12 0 5,5714
4 6 0 0 0 8 0 2,5714
5 7 0 0 3 8 0 3,2857
0 9 2 14 3 0 0 4

Bước 2: Trừ mỗi điểm của dữ liệu với vector kỳ vọng x , ta được A
x n=x n−x
^

Tại hàng 1 cột 1


^x (1,1)=0−0=0

Tại hàng 2 cột 1


^x (2,1)=0−1,5714=−1,5714

Tại hàng 3 cột 1


^x (3,1)=0−3=−3

Tại hàng 4 cột 1


^x (4,1)=3−5,5714=−2,5714

2
0 0 0 0 0 0 0
-1,5714 0,4286 2,4286 3,4286 -1,5714 -1,5714 -1,5714
-3 3 -3 4 5 -3 -3
-2,5714 -0.5714 3,4286 -5,5714 4,4286 6,4286 -5,5714
1,4286 3,4286 -2,5714 -2,5714 -2,5714 5,4286 -2,5714
1,7143 3,7143 -3,2857 -3,2857 -0,2857 4,7143 -3,2857
-4 5 -2 10 -1 -4 -4

Bước 3: Tính ma trận Covariance S


Từ ma trận A, chuyển vị ta được AT
0 -1,5714 -3 -2,5714 1,4286 1,7143 -4
0 0,4286 3 -0.5714 3,4286 3,7143 5
0 2,4286 -3 3,4286 -2,5714 -3,2857 -2
0 3,4286 4 -5,5714 -2,5714 -3,2857 10
0 -1,5714 5 4,4286 -2,5714 -0,2857 -1
0 -1,5714 -3 6,4286 5,4286 4,7143 -4
0 -1,5714 -3 -5,5714 -2,5714 -3,2857 -4

Ta thu được ma trận Covariance S


T
S= A . A
Tại hàng 2 cột 1
S(2,1)=0

Tại hàng 3 cột 3


S ( 3,3 )=(−3 ) × (−3 ) +3 ×3+ (−3 ) × (−3 ) +4 × 4 +5 ×5+ (−3 ) × (−3 )+ (−3 ) × (−3 )=86

3
0 0 0 0 0 0 0
0 27.7142 14 -15.2857 -16.2857 -22.1428 52
0 14 86 -7 -18 -3 92
0 -15.2857 -7 141.714 37.7142 47.8571 -63
2
0 -16.2857 -18 37.7142 69.7142 66.8571 -18
0 -22.1428 -3 47.8571 66.8571 71.4285 -20
0 52 92 -63 -18 -20 178

Bước 4: Tìm Eigen Value và Eigen Vector


Ta thu được Eigen Vector từ ma trận Covariance S (dùng hàm opencv)
0 0,2154 0,3577 -0.4601 -0,2514 -0,2596 0,6953
0 0,0284 0,4057 0,5001 0,4058 0,4771 0,4383
0 -0,1218 -0,2843 -0,6659 0,5319 0,4123 0,0896
0 -0,5840 0,6575 -0,2477 -0,1778 0,1792 -0,3186
0 -0,6381 -0.1189 0,1443 0,3774 -0,5838 0,2729
0 0,4355 0,4244 0,1444 0,3774 -0,5838 0,2729
1 0 0 0 0 0 0

Eigen Value
297.108
6
156,213
4
84,6468
35,673

4
5
0,9128
0,016
5
0

Chọn Eigen Vector (3 vector lớn nhất và 5 vector lớn nhất)

Uk 3 Uk 5

0 0 0 0 0 0 0 0
0,2154 0,0284 -0,1218 0,2154 0,0284 -0,1218 -0,5840 -0,6381
0,3577 0,4057 -0,2843 0,3577 0,4057 -0,2843 0,6575 -0.1189
-0,4601 0,5001 -0,6659 -0,4601 0,5001 -0,6659 -0,2477 0,1443
-0,2514 0,4058 0,5319 -0,2514 0,4058 0,5319 -0,1778 0,3774
-0,2596 0,4771 0,4123 -0,2596 0,4771 0,4123 0,1792 -0,5838
0,6953 0,4383 0,0896 0,6953 0,4383 0,0896 -0,3186 0,2729

Bước 5:
Với 3 vector lớn nhất: Z3 =U Tk 3 × A

-3,1835 3,0785 -2,0186 13,1847 -0,5626 -9,7389 -0,1297


-2,9034 6,2988 -2,9214 0,7060 2,5804 4,6523 -8,4127
3,8651 3,2781 -4,6275 0,3282 -5,7541 1,2364 1,6738

Với 5 vector lớn nhất


Z3 =U Tk 5 × A

5
-3,1835 3,0785 -2,0186 13,1847 -0,5626 -9,7389 -0,1297
-2,9034 6,2988 -2,9214 0,7060 2,5804 4,6523 -8,4127
3,8651 3,2781 -4,6275 0,3282 -5,7541 1,2364 1,6738
0,9099 0,3271 -3,7349 -1,3098 3,8326 -1,4929 1,4679
-0,5646 -0,2224 -0,2964 0,2096 -0,0301 0,4922 0,4118

Bước 6: Tính xấp xỉ giá trị ban đầu


Với 3 vector lớn nhất
x 3 ≈ U k3 × Z 3+ x

0 0 0 0 0 0 0
0,1964 2,0143 1,6173 4,3919 2,2246 -0,5449 1,1003
-0,6408 5,7245 2,4008 7,9087 5,4817 1,0527 -0,9354
3,0034 5,1221 8,1207 -0,3607 10,9524 11,5558 0,3093
4,4075 6,0973 -0,5679 -0,2821 0,6999 7,5654 0,0804
4,4839 6,8436 0,5078 0,3557 2,2904 8,5430 -0,0044
0,4222 9,1949 0,9016 13,5056 4,2245 -0,6211 0,3722

Với 5 vector lớn nhất


x 5 ≈ U k5 × Z 5+ x

0 0 0 0 0 0 0
0,0253 1,9652 3,9877 5,0231 0,0054 0,0129 -0,0197
0,0246
7 5,9661 -0,0120 7,0256 8,0053 0,0126 -0,0192
2,9935 5,0089 9,0031 -0,0059 9,9985 11,996 0,0051
6
7
4,0326 5,9552 -0,0159 0,0298 0,0070 8,0167 -0,0254
4,9766 7,0321 0,0114 -0,0214 2,9949 7,9881 0,0182
-0,0218 9,0299 2,0106 13,9800 2,9953 -0,0111 0,0169

Threshold với T = 2
Với 3 vector lớn nhất
0 0 0 0 0 0 0
0 255 0 255 255 0 0
0 255 255 255 255 0 0
255 255 255 0 255 255 0
255 255 0 0 0 255 0
255 255 0 0 255 255 0
0 255 0 255 255 0 0

Với 5 vector lớn nhất


0 0 0 0 0 0 0
0 0 255 255 0 0 0
0 255 255 255 255 0 0
255 255 255 0 255 255 0
255 255 0 0 0 255 0
255 255 0 0 255 255 0
0 255 255 255 255 0 0

b. Lập trình Reconstruct lại hình sử dụng 3 và 5 eigen value lớn nhất sử dụng hàm
opencv

7
Code:
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;

int main()
{
//khai báo ma trận đầu vào
Mat src = (Mat_<float>(7, 7) <<
0, 0, 0, 0, 0, 0, 0,
0, 2, 4, 5, 0, 0, 0,
0, 6, 0, 7, 8, 0, 0,
3, 5, 9, 0, 10, 12, 0,
4, 6, 0, 0, 0, 8, 0,
5, 7, 0, 0, 3, 8, 0,
0, 9, 2, 14, 3, 0, 0);
cout << "Ma tran dau vao\n" << src << endl;
//B1: Tính kỳ vọng của dữ liệu theo hàng
Mat mean = Mat::zeros(src.rows, 1, CV_32F);
for (int i = 0; i < src.rows; i++)
{
float x = 0;
for (int j = 0; j < src.cols; j++)
{
x += src.at<float>(i, j);
}
mean.at<float>(i, 0) = x / src.cols;
}
cout << "Vector ky vong x\n" << mean << endl;
//B2: Trừ mỗi điểm của dữ liệu với vector kỳ vọng, ta được A
Mat A = Mat::zeros(src.rows, src.cols, CV_32F);
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
A.at<float>(i, j) = src.at<float>(i, j) - mean.at<float>(i, 0);
}
}
cout << "Ma tran A\n" << A << endl;
//Tìm ma trận chuyển vị của ma trận A
Mat AT = Mat::zeros(A.cols, A.rows, CV_32F);
for (int i = 0; i < A.rows; i++)
{
for (int j = 0; j < A.cols; j++)
{
AT.at<float>(i, j) = A.at<float>(j, i);
}
}
//B3: Tính ma trận Covariance S
Mat S = Mat::zeros(A.rows, AT.cols, CV_32F);
S = A * AT;
cout << "Ma tran Covarience S\n" << S << endl;
//B4: Tìm eigen vector và eigen value
Mat eigenvalue, eigenvector;
eigen(S, eigenvalue, eigenvector);
cout << "eigenvalue\n"<< eigenvalue << endl;
cout << "eigenvetor\n" << eigenvector << endl;

8
//Chọn eigen vector (3 vector lớn nhất)
Mat Uk3 = Mat::zeros(eigenvector.rows, 3, CV_32F);
float max3_eigenvalue[] = { eigenvalue.at<float>(0, 0) , eigenvalue.at<float>(1, 0) , eigenvalue.at<float>(2,
0) };
int max3_ident[] = { 0, 1, 2 }; //Lưu ident của 3 eigenvalue lớn nhất
for (int i = 3; i < eigenvalue.rows; i++)
{
if (eigenvalue.at<float>(i, 0) > max3_eigenvalue[0])
{
max3_eigenvalue[0] = eigenvalue.at<float>(i, 0);
max3_ident[0] = i;
}
else if (eigenvalue.at<float>(i, 0) > max3_eigenvalue[1])
{
max3_eigenvalue[1] = eigenvalue.at<float>(i, 0);
max3_ident[1] = i;
}
else if (eigenvalue.at<float>(i, 0) > max3_eigenvalue[2])
{
max3_eigenvalue[2] = eigenvalue.at<float>(i, 0);
max3_ident[2] = i;
}
}
//Lưu Uk3
for (int i = 0; i < eigenvector.rows; i++)
{
for (int j = 0; j < eigenvector.cols; j++)
{
if (i == max3_ident[0])
Uk3.at<float>(j, 0) = eigenvector.at<float>(i, j);
else if (i == max3_ident[1])
Uk3.at<float>(j, 1) = eigenvector.at<float>(i, j);
else if (i == max3_ident[2])
Uk3.at<float>(j, 2) = eigenvector.at<float>(i, j);
}
}
cout << "Uk3\n" << Uk3 << endl;
//Chọn eigen vector (5 vector lớn nhất)
Mat Uk5 = Mat::zeros(eigenvector.rows, 5, CV_32F);
float max5_eigenvalue[] = { eigenvalue.at<float>(0, 0) , eigenvalue.at<float>(1, 0) , eigenvalue.at<float>(2,
0),eigenvalue.at<float>(3, 0), eigenvalue.at<float>(4, 0) };
int max5_ident[] = { 0, 1, 2, 3, 4 }; //Lưu ident của 5 eigenvalue lớn nhất
for (int i = 5; i < eigenvalue.rows; i++)
{
if (eigenvalue.at<float>(i, 0) > max5_eigenvalue[0])
{
max5_eigenvalue[0] = eigenvalue.at<float>(i, 0);
max5_ident[0] = i;
}
else if (eigenvalue.at<float>(i, 0) > max5_eigenvalue[1])
{
max5_eigenvalue[1] = eigenvalue.at<float>(i, 0);
max5_ident[1] = i;
}
else if (eigenvalue.at<float>(i, 0) > max5_eigenvalue[2])
{
max5_eigenvalue[2] = eigenvalue.at<float>(i, 0);
max5_ident[2] = i;
}

9
else if (eigenvalue.at<float>(i, 0) > max5_eigenvalue[3])
{
max5_eigenvalue[3] = eigenvalue.at<float>(i, 0);
max5_ident[3] = i;
}
else if (eigenvalue.at<float>(i, 0) > max5_eigenvalue[4])
{
max5_eigenvalue[4] = eigenvalue.at<float>(i, 0);
max5_ident[4] = i;
}
}
//Lưu Uk5
for (int i = 0; i < eigenvector.rows; i++)
{
for (int j = 0; j < eigenvector.cols; j++)
{
if (i == max5_ident[0])
Uk5.at<float>(j, 0) = eigenvector.at<float>(i, j);
else if (i == max5_ident[1])
Uk5.at<float>(j, 1) = eigenvector.at<float>(i, j);
else if (i == max5_ident[2])
Uk5.at<float>(j, 2) = eigenvector.at<float>(i, j);
else if (i == max5_ident[3])
Uk5.at<float>(j, 3) = eigenvector.at<float>(i, j);
else if (i == max5_ident[4])
Uk5.at<float>(j, 4) = eigenvector.at<float>(i, j);
}
}
cout << "Uk5\n" << Uk5 << endl;
//B5: Tính Z3, Z5
//Tính Uk3T, Uk5T

Mat Uk3T = Mat::zeros(Uk3.cols, Uk3.rows, CV_32F);


for (int i = 0; i < Uk3T.rows; i++)
{
for (int j = 0; j < Uk3T.cols; j++)
{
Uk3T.at<float>(i, j) = Uk3.at<float>(j, i);
}
}
Mat Uk5T = Mat::zeros(Uk5.cols, Uk5.rows, CV_32F);
for (int i = 0; i < Uk5T.rows; i++)
{
for (int j = 0; j < Uk5T.cols; j++)
{
Uk5T.at<float>(i, j) = Uk5.at<float>(j, i);
}
}
//Tính Z3, Z5
Mat Z3 = Mat::zeros(Uk3T.rows, A.cols, CV_32F);
Z3 = Uk3T * A;
cout << "Z3\n" << Z3 << endl;
Mat Z5 = Mat::zeros(Uk5T.rows, A.cols, CV_32F);
Z5 = Uk5T * A;
cout << "Z5\n" << Z5 << endl;
//B6: Tính xấp xỉ giá trị ban đầu
Mat UA3 = Mat::zeros(A.rows, A.cols, CV_32F);
UA3 = Uk3 * Z3;

10
Mat UA5 = Mat::zeros(A.rows, A.cols, CV_32F);
UA5 = Uk5 * Z5;
Mat X3 = Mat::zeros(A.rows, A.cols, CV_32F);
Mat X5 = Mat::zeros(A.rows, A.cols, CV_32F);
for (int i = 0; i < A.rows; i++)
{
for (int j = 0; j < A.cols; j++)
{
X3.at<float>(i, j) = UA3.at<float>(i, j) + mean.at<float>(i, 0);
X5.at<float>(i, j) = UA5.at<float>(i, j) + mean.at<float>(i, 0);
}
}

cout << "Ma tran sau khi xap xi (voi 3 vector lon nhat)\n" << X3 << endl;
cout << "Ma tran sau khi xap xi (voi 5 vector lon nhat)\n" << X5 << endl;
Mat X5final, X3final;
//Chọn ngưỡng T = 2 cho cả 2 trường hợp
threshold(X5, X5final, 2, 255, THRESH_BINARY);
threshold(X3, X3final, 2, 255, THRESH_BINARY);

cout << "Ma tran sau khi phan nguong (voi 3 vector lon nhat)\n" << X3final << endl;
cout << "Ma tran sau khi phan nguong (voi 5 vector lon nhat)\n" << X5final << endl;
waitKey();
}

Kết quả

Kết quả Reconstruct bằng tay trùng với kết quả lập trình.

11
2. Cho hình sau:

2 3 3 7 6 1 3 5 6 8
8 2 3 4 9 2 4 5 4 6 2
4 0 0 0 10 6 7 8 5 7 3
5 0 0 0 6 3 5 9 1 12 8 2 7
8 0 0 0 10 0 5 7 9 9
6 7 8 4 6 4 6 8 3 6 7 2 4
5 7 3 8 1 10 13
9 2 14 3
Matrix (a) Matrix (b) matrix (c)
a) Sử dụng giải thuật PCA để training và nhận dạng template giống với hình nào nhất
bằng tay tương ứng với nhóm trên bài 1 (2đ)

Các ô để trống ta đặt 0 vào để lắp đầy matrix:

0 2 3 3 7 6 0 a. 0 0 0 0 0 0 0 0 0 1 3 5 6 8
0 8 2 3 4 9 0 0 2 4 5 0 0 0 0 4 6 0 0 0 2
0 4 0 0 0 1 0 0 6 0 7 8 0 0 5 7 0 0 0 0 3
0 3 5 9 0 10 12 0 8 2 0 0 0 0 7
0 5 0 0 0 6 0 4 6 0 0 0 8 0 5 7 0 0 0 9 9
0 8 0 0 0 1 0 5 7 0 0 3 8 0 0 3 6 7 2 4 0
0 0 9 2 14 3 0 0 0 0 1 10 13 0 0
0 6 7 8 4 6 0 Giải thuật huấn luyện
0 0 0 0 0 0 0
Biểu diễn các ảnh dưới dạng vector Γ i
Γ1 Γ2 Γ3

0 0 0
0 0 0
0 0 5
0 3 8
0 4 5
0 5 0
0 0 0

12
2 0 0
8 2 4
4 6 7
5 5 2
8 6 7
6 7 3
0 9 0
2 0 0
… … …
0 0 7
0 0 9
0 0 0
0 0 0

Tính vector trung bình:


M 3
1 1
¿ ∑ Γ i= ∑ Γ i
M i=1 3 i=1
Từ công thức trên ta tính được
¿ ¿0 0 1,66 3,66 3 1,66 0 0,66 4,66 5,66 … 3 0 0 ¿T
Tính sai số của các ảnh
ϕ i=Γ i−¿

Với ϕ i là vector sai số tương ứng với mỗi ảnh, khi đó:
ϕ 1=¿ 0,00 0,00 -1,66 -3,66 -3,00 -1,66 0,00 1,34… 0,00 ¿T
ϕ 2=¿ 0,00 0,00 -1,66 -0,66 1,00 3,34 0,00 -0,66 … 0,00 ¿T
ϕ 3=¿0,00 0,00 3,34 4,34 2,00 -1,66 0,00 -0,66 … 0,00 ¿T

Tính ma trận hiệp phương sai


T
C= A A

13
Với A=[ϕ 1 ϕ 2 ϕ3 ¿

[ ]
Suy ra

0 0 0
0 0 0
−1,66 −1,66 3,34
−3,66 −0,66 4,34
−3,00 1,00 2,00
A= −1,66 3,34 −1,66
0 0 0
1,34 −0,66 −0,66
… … …
0 0 0
0 0 0

Suy ra

[ ]
330.6561 −204.2739 −126.5639
T
M = A A= −204.2739 409.7961 −205.4939
−126.5639 −205.4939 332.2161

Trị riêng và vector riêng của ma trận M: ta tiến hành nhập ma trận M vào
matlab và tiến hành tính toán Eigen Vector và Eigen Value.

14
Kết quả thu được sắp xếp Eigen Vector ( vi ¿ theo thứ tự giảm dần của Eigen
Value (λ i) là:
v1 =[ −0.4030 0.8165−0.4134 ] , λ 1=614.6752
v 2=[ 0.7099−0.0062−0.7043 ] , λ 2=457.9915
v3 =[ −0.5776−0.5773−0.5771 ] , λ3=0.0016

Tìm vector đặc trưng PCA theo công thức


ui = A v i

Với:
A=[ ϕ 1 ϕ2 ϕ 3 ]

vi : Eigen Vector

v1 =[ −0.4030 0.8165−0.4134 ]; v 2=[ 0.7099−0.0062−0.7043 ];

[ ]
v3 =[ −0.5776−0.5773−0.5771 ]

0 0 0
0 0 0
−1,66 −1,66 3,34
−3,66 −0,66 4,34
−3,00 1,00 2,00 T
→ u1= A v 1 = −1,66 3,34 −1,66 × [−0.4030 0.8165−0.4134 ]
T

0 0 0
1,34 −0,66 −0,66
… … …
0 0 0
0 0 0

[]
0
0
−2.0672
−0.8581
1.1987
4.0823
0
−0.8061

0
0

15
[]
Tương tự ta tính được

0
0
−3.5205
−5.6508
−3.5445
u2= −0.0300
0
1.4202

0
0

[]
0
0
−0.0104
−0.0096
0.0013
u3= −0.0114
0
−0.0121

0
0

Ta chuyển các vector đặc trưng ui về vector đơn vị ¿∨ui∨¿=1theo công thức:
ui
ui=
¿∨ui∨¿

Trong đó ¿∨ui∨¿=√∑ u2ij nghĩa là ¿∨ui∨¿bằng căn bậc 2 của tổng bình phương các phần
tử trong vector ui
Ta có

¿∨u1∨¿=√ 0 +0 + (−2.0672 ) + (−0.8581 ) + … ( 0 ) =24.79


2 2 2 2 2

¿∨u2∨¿=√ 0 +0 + (−3.5205 ) + (−5.6508 ) +… ( 0 ) =21.40


2 2 2 2 2

¿∨u2∨¿=√ 0 +0 + (−0.0104 ) + (−0.0096 ) +… ( 0 ) =0.04


2 2 2 2 2

Suy ra

16
[]
0
0
−0.0834
−0.0346
u1 u1 0.0483
u1 = = = 0.1647
¿∨u1∨¿ 24.79
0
−0.0325

0
0

[]
0
0
−0.1645
−0.2640
u2 u −0.1656
u2 = = 2 = −0.0014
¿∨u2∨¿ 21.40
0
0.0664

0
0

[]
0
0
−0.2602
−0.2401
u3 u 0.0326
u3= = 3 = −0.2852
¿∨u3∨¿ 0.04
0
−0.3028

0
0

Giải thuật nhận dạng:


Template của nhóm 0 0 0 0 0 0 0
0 2 4 5 0 0 0
0 6 2 7 8 0 0
3 5 9 2 10 12 0
4 6 2 3 4 8 0
5 7 2 3 3 8 0
0 9 2 1417 3 0 0
Biểu diễn các ảnh dưới dạng vector Γ temp
Γ temp =¿ 0 0 0 3 4 5 0 0 2 6 5 6 7 9 … 0 0 ¿T

Tính vector sai số trung bình của ảnh nhận diện: ϕ temp=Γ temp −¿
Với đã tính ở trên ¿ ¿0 0 1,66 3,66 3 1,66 0 0,66 4,66 5,66 … 3 0 0 ¿T
→ ϕ temp =¿

Biểu diễn các ảnh trong không gian vector trị riêng
Ta chọn trường hợp chỉ xét theo Eigen Vector có Eigen Value lớn nhất

[]
T
Ωi=u ϕ i

0
0
−0.0834
−0.0346
0.0483
Ta có vector u có Eigen Value lớn nhất là: u1= 0.1647
0
−0.0325

0
0

Suy ra
Ωtemp=u T1 ϕ temp=19.0749

Ω1=u T1 ϕ 1=−9.9919
T
Ω3=u1 ϕ 2=20.2430
T
Ω3=u1 ϕ 3=−10.2499

18
Khoảng cách trong không gian cơ sở;
e r 1=||Ωtemp−Ω1||=√ ¿ ¿

e r 2=||Ωtemp −Ω2||=√ ¿ ¿

e r 3=||Ωtemp −Ω2||=√ ¿ ¿

Từ đó ta thấy giá trị của e r 2 là nhỏ nhất nên ta kết luận ảnh 2 giống template nhất.
b) Lập trình training và nhận dạng
#include <opencv2/opencv.hpp>
#include<iostream>
#include <math.h>
using namespace std;
using namespace cv;
int main()
{
//Khai bao cac ma tran anh va template
float img1[7][7] = {
0, 2, 3, 3, 7, 6, 0,
0, 8, 2, 3, 4, 9, 0,
0, 4, 0, 0, 0, 10, 0,
0, 5, 0, 0, 0, 6, 0,
0, 8, 0, 0, 0, 10, 0,
0, 6, 7, 8, 4, 6, 0,
0, 0, 0, 0, 0, 0, 0
};
float img2[7][7] = {
0, 0, 0, 0, 0, 0, 0,
0, 2, 4, 5, 0, 0, 0,
0, 6, 0, 7, 8, 0, 0,
3, 5, 9, 0, 10, 12, 0,
4, 6, 0, 0, 0, 8, 0,
5, 7, 0, 0, 3, 8, 0,
0, 9, 2, 14, 3, 0, 0
};
float img3[7][7] = {
0, 0, 1, 3, 5, 6, 8,
0, 4, 6, 0, 0, 0, 2,
5, 7, 0, 0, 0, 0, 3,
8, 2, 0, 0, 0, 0, 7,
5, 7, 0, 0, 0, 9, 9,
0, 3, 6, 7, 2, 4, 0,
0, 0, 1, 10, 13, 0, 0,
};
float temp[7][7] = {
0, 0, 0, 0, 0, 0, 0,
0, 2, 4, 5, 0, 0, 0,
0, 6, 2, 7, 8, 0, 0,
3, 5, 9, 2, 10, 12, 0,
4, 6, 2, 3, 4, 8, 0,
5, 7, 2, 3, 3, 8, 0,
0, 9, 2, 14, 3, 0, 0
};

19
float tau1[49], tau2[49], tau3[49], psi[49], tem[49], phi1[49], phi2[49],
phi3[49], phitem[49], at[49][3], a[3][49], c[3][3], u[49], uu[49];
float sum = 0, omg = 0, omg1 = 0, omg2 = 0, omg3 = 0;
for (int i = 0; i < 7; i++) {
for (int j = 0; j < 7; j++) {
//bieu dien cac ma tran anh duoi dang vector tau_i
tau1[7 * i + j] = img1[j][i];
tau2[7 * i + j] = img2[j][i];
tau3[7 * i + j] = img3[j][i];
tem[7 * i + j] = temp[j][i];
//tinh vector trung binh psi
psi[7 * i + j] = (img1[j][i] + img2[j][i] + img3[j][i]) / 3;
//tinh sai so cua cac anh bang cach lay vector tau_i-psi
phi1[7 * i + j] = tau1[7 * i + j] - psi[7 * i + j];
phi2[7 * i + j] = tau2[7 * i + j] - psi[7 * i + j];
phi3[7 * i + j] = tau3[7 * i + j] - psi[7 * i + j];
phitem[7 * i + j] = tem[7 * i + j] - psi[7 * i + j];
//tinh ma tran a=[phi1 phi2 phi3]
a[0][7 * i + j] = phi1[7 * i + j];
a[1][7 * i + j] = phi2[7 * i + j];
a[2][7 * i + j] = phi3[7 * i + j];
//tu ma tran a ta suy ra duoc aT
at[7 * i + j][0] = phi1[7 * i + j];
at[7 * i + j][1] = phi2[7 * i + j];
at[7 * i + j][2] = phi3[7 * i + j];
}
}
cout << "Ma tran hiep phuong sai C:" << endl;
//tinh ma tran hiep phuong sai C=AT*A
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
c[i][j] = 0;
for (int k = 0; k < 49; k++) {
c[i][j] = c[i][j] + at[k][i] * a[j][k];
}
cout << c[i][j] << " ";
}
cout << endl;
}
//khai bao cac bien eigenvector va eigenvalue
Mat eivec, eival;
//chuyen ma tran c tu dang mang sang mat de dua vao ham tinh toan
Mat src(3, 3, CV_32FC1, c);
//dung ham de tinh eigen vector va eigen value
//voi src la ma tran dau vao, eival la eigen value, eivec la eigen vector
eigenNonSymmetric(src, eival, eivec);
cout << "Eigen Value: " << endl << eival << endl << "Eigen Vector: " << endl
<< eivec << endl;
vector<float> eva, eve;
//copy eigen value vua tim duoc vao mang eva
eival.col(0).copyTo(eva);
//chon eigen vector co eigen value lon nhat, sau do lay eigen vector tim duoc
copy vao mang eve
cout << "Chon Eigen Vector theo Eigen Value lon nhat" << endl;
if (eva[0] >= eva[1]) {
eivec.row(0).copyTo(eve);
cout << "Eigen Value : " << eva[0] << endl << "Eigen Vector : " <<
eve[0] << " " << eve[1] << " " << eve[2] << " " << endl;

20
}
else {
eivec.row(1).copyTo(eve);
cout << "Eigen Value : " << eva[1] << endl << "Eigen Vector : " <<
eve[0] << " " << eve[1] << " " << eve[2] << " " << endl;
}
//tim vector dat trung theo cong thuc ui=at*v_i
cout << "Vecto dac trung:" << endl << "[ ";
for (int i = 0; i < 49; i++) {
u[i] = 0;
for (int j = 0; j < 3; j++) {
u[i] = u[i] + at[i][j] * eve[j];
}
cout << u[i] << " ";
//tinh tong binh phuong cac phan tu trong vector dat trung
sum = sum + u[i] * u[i];
}
cout << " ]T" << endl;
//tinh ||u_i|| bang can bac 2 cua tong binh phuong cac phan tu
sum = sqrt(sum);
cout << "Vec to dac trung trong khong gian dac trung: " << endl << "[ ";
//bieu dien anh trong khong gian vector tri rieng theo cong thuc
omega_i=u_iT*phi_i
//trong do u_i la u_i chuyen ve vector don vi theo cong thuc u_i=u_i/||u_i||
for (int i = 0; i < 49; i++) {
cout << u[i] / sum << " ";
omg = omg + phitem[i] * u[i] / sum;
omg1 = omg1 + phi1[i] * u[i] / sum;
omg2 = omg2 + phi2[i] * u[i] / sum;
omg3 = omg3 + phi3[i] * u[i] / sum;
}
cout << " ]T" << endl;
cout << " Bieu dien anh trong khong gian vecto tri rieng:" << endl;
cout << "Omega: " << omg << endl << "Omega1: " << omg1 << endl << "Omega2: "
<< omg2 << endl << "Omega3: " << omg3 << endl;
//tinh khoang cach trong khong gian co so theo cong thuc er_i=||omega-
omgega_i||
float er1, er2, er3;
er1 = sqrt((omg - omg1) * (omg - omg1));
er2 = sqrt((omg - omg2) * (omg - omg2));
er3 = sqrt((omg - omg3) * (omg - omg3));
cout << "Khoang cach khong gian co so: " << endl;
cout << "Er1: " << er1 << endl << "Er2: " << er2 << endl << "Er3: " << er3 <<
endl;
//Ket luan anh dua tren er_i, neu er_i nao nho nhat thi giong anh goc nhat
if (er1 <= er2 && er1 <= er3) {
cout << "Hinh 1 giong hinh mau nhat" << endl;
}
else if (er2 <= er1 && er2 <= er3) {
cout << "Hinh 2 giong hinh mau nhat" << endl;
}
else {
cout << "Hinh 3 giong hinh mau nhat" << endl;
}
waitKey(0);

21
Kết quả sử dụng giải thuật PCA để training và nhận dạng template bằng tay giống với kết
quả lập trình.

22
3. Cho hình sau có tọa độ pixel như sau
7 8 9 1 1
0 1 2 3 4 5 6 0 1
1
2
3
4 1 2
1 3 4 5
5 4
1 6
6 3
1 9 8 7
7 2
1 1
8 1 0
9
1
0
1
1

a) Xoay hình bằng tay này 700 độ và dịch chuyển (u=+1,v=+2) pixel (1.5đ)
b) Giả sử sau khi xoay 700 độ và tịnh tiến ta có bộ tọa độ mới , Hãy tìm lại ma trận xoay
và tịnh tiến này dựa trên bộ data đã xoay và chưa xoay. Lập trình tính câu b sử dụng hàm
opencv (1.5đ)
Bài làm:
a. Ta có thể hiểu câu a như sau:

23
Xoay hình gồm các điểm sau: (4,4), (5,4), (6,5), (7,5), (8,5), (8,6), (8,7), (7,7), (6,7),
(5,8), (4,8), ( 4,7), (4,6), (4,5) một góc 70 độ quanh trọng tâm và tịnh tiến theo phương u
1 đơn vị và phương v 2 đơn vị :
 Tìm các vùng blob sử dụng conectivity 8

Ta thực hiện quét lần lượt lên hình đề cho để tìm ra các vùng blob :
+ Lần quét đầu tiên

1 1
1 1 1 1
1 1
1 1 1 1
1 1

 Bước 2: Tìm moment để tính trọng tâm và góc


Ta có các công thức tính như sau:
M 0,0=∑ ∑ A i , j
i j

M 1,0=∑ ∑ i1 j 0 A i , j
i j

24
M 0,1=∑ ∑ i j A i , j
0 1

i j

M 1,1=∑ ∑ i 1 j 1 A i , j
i j

Ta có công thức tính tọa độ trọng tâm:


M 1,0 M
xc= , y c = 0,1 Ta tính được tọa độ tâm và góc thông qua các giá trị moment.
M 0,0 M 0,0
M 0,0=14

M 1,0=¿ 80

M 0,1=¿ 84

Ta có tâm của blob 1


M 1,0 80
xc= = =5,714
M 0,0 14
M 0,1 84
yc= = =6
M 0,0 14

[]
Ta có ma trận biểu diễn tọa độ cho hình trên :

4 4 1
5 4 1
6 5 1
7 5 1
8 5 1
8 6 1
8 7 1
P=
7 7 1
6 7 1
5 8 1
4 8 1
4 7 1
4 6 1
4 5 1

Ta có ma trận chuyển vị :


T = T0 * R * T * T0-1

25
[ ][ ][ ][ ]
1 0 0 cos ( 70 ° ) sin ( 70 ° ) 0 1 0 0 1 0 0
T= 0 1 0 * −sin ( 70° ) cos ( 70 ° ) 0 * 0 1 0 * 0 1 0
−5,714 −6 1 0 0 1 1 2 1 5,714 6 1

[ ]
cos ( 70 ° ) sin ( 70 ° ) 0
= −sin ( 70° ) cos ( 70 ° ) 0
10,586 0,31 1

Với :

[ ]
cos ( 70 ° ) sin ( 70 ° ) 0
- Ma trận xoay : −sin ( 70° ) cos ( 70 ° ) 0
0 0 1

[ ]
1 0 0
- Ma trận tịnh tiến : 0 1 0
1 2 1

[ ]
1 0 0
- Dời tâm quay về gốc tọa độ và đưa tâm quay về vị trí ban đầu : 0 1 0 và
−5,714 −6 1

[ ]
1 0 0
0 1 0
5,714 6 1

[] [ ]
Vậy hệ tọa độ của hình sau khi xoay và tịnh tiến :

4 4 1 8,007 5,705 1
5 4 1 8,349 6,645 1
6 5 1 7,752 7,926 1
7 5 1 8,094 8,866 1
8 5 1 8,436 9,806 1

[ ]
8 6 1 7,496 10,148 1
cos ( 70 ° ) sin ( 70 ° ) 0
8 7 1 6,556 10,498 1
P* = P * T = * −sin ( 70° ) cos ( 70 ° ) 0 =
7 7 1 6,214 9,55 1
10,586 0,31 1
6 7 1 5,872 8,611 1
5 8 1 4,591 8,013 1
4 8 1 4,249 7,073 1
4 7 1 5,188 6,731 1
4 6 1 6,218 6,389 1
4 5 1 7,068 5,047 1

b. Lập trình
26
Đầu vào : Hệ tọa độ trước và sau khi chuyển đổi, được tính ở câu a.
Đầu ra : Ma trận xoay, ma trận tịnh tiến và góc xoay.
Code :
#include <iostream>
#include <opencv2/imgproc.hpp>
#include <opencv2/core.hpp>
#include <opencv2/calib3d.hpp>

using namespace std;


using namespace cv;

int main()
{
// Tọa độ các điểm trước và sau khi chuyển đổi
vector<Point2f> points1 = {
Point2f(4, 4),
Point2f(5, 4),
Point2f(6, 5),
Point2f(7, 5),
Point2f(8, 5),
Point2f(8, 6),
Point2f(8, 7),
Point2f(7, 7),
Point2f(6, 7),
Point2f(5, 8),
Point2f(4, 8),
Point2f(4, 7),
Point2f(4, 6),
Point2f(4, 5) };

vector<Point2f> points2 = {
Point2f(8.007, 5.705),
Point2f(8.349, 6.645),
Point2f(7.752, 7.926),
Point2f(8.094, 8.866),
Point2f(8.436, 9.806),
Point2f(7.496, 10.148),
Point2f(6.556, 10.498),
Point2f(6.214, 9.55),
Point2f(5.872, 8.611),
Point2f(4.591, 8.013),
Point2f(4.249, 7.073),
Point2f(5.188, 6.731),
Point2f(6.218, 6.389),
Point2f(7.068, 5.047) };

vector<Point2f> points1_r = { // dùng để tính ma trận xoay, vì hàm getAffineTransform chỉ lấy 3 điểm
Point2f(4, 4),
Point2f(5, 4),
Point2f(6, 5) };

vector<Point2f> points2_r = {
Point2f(8.007, 5.705),
Point2f(8.349, 6.645),

27
Point2f(7.752, 7.926) };

// Tìm tâm của các điểm trước và sau khi chuyển đổi
Scalar C1 = mean(points1);
Scalar C2 = mean(points2);

// Tính ma trận tịnh tiến giữa hai tâm


Mat T = (Mat_<double>(3, 3) << 1, 0, 0,
0, 1, 0,
C2[0] - C1[0], C2[1] - C1[1], 1);
Mat T_inv = T.inv();

// Tính ma trận affine


Mat affine = getAffineTransform(points1_r, points2_r);

// Tính ma trận xoay từ ma trận affine


Mat R = affine.rowRange(0, 2).colRange(0, 2);

// Tính góc quay


double goc = atan2(R.at<double>(1, 0), R.at<double>(0, 0)) * 180 / 3.141592654;

// Hiển thị ma trận xoay, ma trận tịnh tiến và góc xoay


cout << "Ma tran tinh tien:\n" << T << endl;
cout << "Ma tran xoay:\n" << R << endl;
cout << "Goc xoay\n" << goc << endl;

return 0;
}

Kết quả thu được :

BÀI TẬP LỚN SỐ 2


Ý tưởng:
Trong hình có 4 ảnh xe lửa, trong đó có 3 ảnh xe lửa match với template, ảnh còn lại đối
xứng với ảnh templae gốc qua trục y. Sau đó xử lí Generalized Hough transform như
thường

28
Giải thuật:
Tính trọng tâm của template theo công thức:

Từ trọng tâm và template lập bảng R –table là vector chứa vector, trong đó vector cha là
vector index –edgde orientation trong khoảng 0 đến 2pi, vector con là cặp r và alpha được
tính theo công thức:

Từ bảng R-table, tiến hành voting các điểm pixel trong ma trận ảnh target và lưu lại dưới
dạng ma trận voting – accumalator.

Đối với scales, nhân 0.5 cho

29
Từ accumalator, chọn những điểm pixel có giá trị cao, được nhiều lượt vote , đó là các
điểm trọng tâm
Code:
#include "opencv2/highgui.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
#include <vector>
#include <cmath>
// ma trận tính sobel ảnh

Mat find_edge_orientation(const Mat& image) {


Mat dx, dy;
Sobel(image, dx, CV_32F, 1, 0);
Sobel(image, dy, CV_32F, 0, 1);
Mat edge_orientation = Mat::zeros(image.size(), CV_32F);
for (int i = 0; i < image.rows; ++i) {
for (int j = 0; j < image.cols; ++j) {
edge_orientation.at<float>(i, j) = atan2(dy.at<float>(i, j), dx.at<float>(i, j))+CV_PI;
}
}

return edge_orientation;
}

// ma trận tạo r-table


vector<vector<pair<float, float>>> build_r_table(const Mat& template_image, Point center_point, int row_count)
{
Mat orientations = find_edge_orientation(template_image);

vector<vector<pair<float, float>>> r_table(row_count);

for (int i = 0; i < template_image.rows; ++i) {


for (int j = 0; j < template_image.cols; ++j) {
if (template_image.at<uchar>(i, j) >0) {

float r = sqrt(pow(center_point.x - j, 2) + pow(center_point.y - i, 2));


float alpha = atan2(i - center_point.y, j - center_point.x) + CV_PI;
int index = row_count * orientations.at<float>(i, j) / (2 * CV_PI);
index = max(0, min(row_count - 1, index)); // giới hạn index để không bị lỗi vector out of range
r_table[index].push_back(make_pair(r, alpha));
}
}
}

return r_table;
}

// ma trận tạo accumalator


Mat accumulator_mat(const Mat& target_image, const vector<vector<pair<float, float>>>& r_table, float scale)

30
{

Mat orientations = find_edge_orientation(target_image);


Mat accumulator = Mat::zeros(target_image.size(), CV_32S);
int r_table_row_count = r_table.size();
for (int i = 0; i < target_image.rows; ++i) {
for (int j = 0; j < target_image.cols; ++j) {
if (target_image.at<uchar>(i, j) > 0) {
int index = r_table_row_count * orientations.at<float>(i, j) / (2*CV_PI);
index = max(0, min(r_table_row_count - 1, index)); // clamp index value to be within valid range
auto r_row = r_table[index];
for (auto& p : r_row) {

int accum_i = i + p.first * sin(p.second)*scale;


int accum_j = j + p.first * cos(p.second)*scale;

if (accum_i >= 0 && accum_i < accumulator.rows && accum_j >= 0 && accum_j < accumulator.cols) {
accumulator.at<int>(accum_i, accum_j) += 1;
}
}
}
}
}

return accumulator;
}

int main() {

// Load the target and template images


Mat Target = imread("C:\\Users\\Administrator\\Desktop\\target.png", IMREAD_GRAYSCALE);
Mat Template_match = imread("C:\\Users\\Administrator\\Desktop\\reference.png", IMREAD_GRAYSCALE);
Mat Target_result = imread("C:\\Users\\Administrator\\Desktop\\target.png", IMREAD_GRAYSCALE);
// Tạo 2 template, do ảnh template gốc là ảnh phải lấy đối xứng qua trục so với ảnh trong hình target
Mat Template_1;
Mat Template_2;

// Tìm edge của ảnh


Canny(Template_match, Template_1, 50, 200);
Canny(Template_match, Template_2, 50, 200);
Canny(Target, Target, 50, 200);

// Template ảnh đối xứng

for (int i = 0; i < Template_2.rows; i++) {


for (int j = 0; j < Template_2.cols / 2; j++) {
// Hoán đổi giá trị của hai phần tử cùng cặp trên hai bên của trục y
int temp = Template_2.at<uchar>(i, j);
Template_2.at<uchar>(i, j) = Template_2.at<uchar>(i, Template_2.cols - j - 1);
Template_2.at<uchar>(i, Template_2.cols - j - 1) = temp;

}
}

31
// Trọng tâm ảnh template gốc
int sum_x = 0;
int sum_y = 0;
int count = 0;

for (int i = 0; i < Template_1.rows;i++)


{
for (int j = 0;j < Template_1.cols;j++)
{
if (Template_1.at<uchar>(i, j) >0)
{

sum_x = sum_x + j;
sum_y = sum_y + i;
count++;
}
}
}
float centroidX1 = static_cast<float>(sum_x) / static_cast<float>(count);
float centroidY1 = static_cast<float>(sum_y) / static_cast<float>(count);
circle(Template_1, Point(centroidX1, centroidY1), 5, Scalar(255, 255, 255), -1);
Point center1(centroidX1, centroidY1);

// Trọng tâm ảnh template lấy đối xứn


sum_x = 0;
sum_y = 0;
count = 0;
for (int i = 0; i < Template_2.rows;i++)
{
for (int j = 0;j < Template_2.cols;j++)
{
if (Template_2.at<uchar>(i, j) > 0)
{

sum_x = sum_x + j;
sum_y = sum_y + i;
count++;
}
}
}
float centroidX2 = static_cast<float>(sum_x) / static_cast<float>(count);
float centroidY2 = static_cast<float>(sum_y) / static_cast<float>(count);
circle(Template_2, Point(centroidX2, centroidY2), 5, Scalar(255, 255, 255), -1);
Point center2(centroidX2, centroidY2);
// Số hàng , lấy trong khoảng từ 0 đến 360, egde orietation
int rowCount = 360;

// tạo bảng rtable, với rtable là 1 vector chứa 1 vector là 1 cặp r và alpha
vector<vector<pair<float, float>>> rTable1 = build_r_table(Template_1, center1, rowCount);
vector<vector<pair<float, float>>> rTable2 = build_r_table(Template_2, center2, rowCount);
//// Tạo ma trận để voting xc, yc
// scale là 0.5
Mat accumulatorArray1 = accumulator_mat(Target, rTable1,0.5);
Mat accumulatorArray2 = accumulator_mat(Target, rTable2, 0.5);

// phân ngưỡng voting, vẽ hình tròn điền đầy lên các điểm này
int threshold = 120;
for (int i = 0; i < accumulatorArray1.rows;i++)

32
{
for (int j = 0;j < accumulatorArray1.cols;j++)
{
if (accumulatorArray1.at<int>(i, j) > threshold)
{
Point center1(j, i);
circle(Target_result, center1, 5, Scalar(255, 255, 255), -1);
}

}
}
threshold = 100;

for (int i = 0; i < accumulatorArray2.rows;i++)


{
for (int j = 0;j < accumulatorArray2.cols;j++)
{
if (accumulatorArray2.at<int>(i, j) > threshold)
{
Point center2(j, i);
circle(Target_result, center2, 5, Scalar(255, 255, 255), -1);
}

}
}

imshow("Target Image", Target_result);


imshow("Template_1", Template_1);
imshow("Template_22", Template_2);
waitKey(0);

return 0;
}

Output:

33
34

You might also like