Câu 1: Cân bằng histogram.
a. Viết công thức
·
Mục
đích của cân bằng histogram là làm cho histogram đồng đều. Khi đó ta làm tăng
được độ tương phản của ảnh.
·
Cân
bằng histogram được cho bằng phương trình: s=T(r)=(L-1)
với
pr(w) : Xác suất xảy ra mức
xám w
·
Trong
xác suất, tích phân của hàm mật độ là hàm phân phối. Công thức trên có w là biến liên tục, ta không thể lập
trình nó. Ta phải dùng công thức rời rạc: sk=T(rk)=(L-1)
với k=
0,1,2,…,L-1
b. Lập trình
void HistogramEqulization(Mat imgin, Mat imgout)
{
int
M=imgin.size().height;
int
N=imgin.size().width;
int x,y;
int r, h[L];
for(r=0;r<L;r++)
h[r]=0;
for(x=0;x<M;x++)
for(y=0;y<N;y++)
{
r=imgin.at<uchar>(x,y);
h[r]++;
}
double p[L];
for(r=0;r<L;r++)
p[r]=1.0*h[r]/(M*N);
double s[L];
int j,k;
for(k=0;k<L;k++)
{
s[k]=0;
for(j=0;j<=k;j++)
s[k]+=p[j];
}
for(x=0;x<M;x++)
for(y=0;y<N;y++)
{
r=imgin.at<uchar>(x,y);
imgout.at<uchar>(x,y)=uchar((L-1)*s[r]);
}
return;
}
c. Hàm trong
openCV.
equalizeHist(imgin,
imgout);
Câu
2: Lọc median. (lọc trung vị)
a. Viết công thức
Mô tả thuật toán như sau: rê ma trận trên ảnh đến
khi nào đủ 9 giá trị trên ma trận 3x3thì tiến hành sắp xếp ma trận này tăng dần
từ trái qua phải từ trên xuống dưới, vào thay phần tử chính giữa cũ bằng phần tử
chính giữa mới.

b. Lập trình
void Sort(Mat w)
{
int
size=w.size().height*w.size().width;
int i,j;
uchar temp;
for(i=0;i<size-1;i++)
for(j=i+1;j<size;j++)
if(w.data[i]>w.data[j])
{
temp=w.data[i];
w.data[i]=w.data[j];
w.data[j]=temp;
}
}
void MedianFilter(Mat imgin,Mat imgout)
{
int
M=imgin.size().height;
int
N=imgin.size().width;
int x,y,s,t;
uchar r,sd;
int m=5,n=5;
int a=m/2,b=n/2;
Mat w=Mat(m,n,CV_8UC1,CV_RGB(0,0,0));
for(x=a;x<M-a;x++)
for(y=b;y<N-b;y++)
{
for(s=-a;s<=a;s++)
for(t=-b;t<=b;t++)
w.at<uchar>(s+a,t+b)=imgin.at<uchar>(x+s,y+t);
Sort(w);
imgout.at<uchar>(x,y)=w.at<uchar>(a,b);
}
}
c. Hàm trong
openCV.
medianBlur(imgin,imgout,5);
Câu 3: Lọc tuyến tính
a. Viết công thức
Tổng
quát lọc trong không gian được cho bằng phương trình :
g(x,y)=


Trong
đó :
mxn là kích
thước của bộ lọc, m và n thường là số lẻ để bộ lọc có phần tử trung tâm.
a=m/2
và b=n/2 là kích thước nữa bộ lọc.
Phép toán lọc
trong không gian được gọi là tổng chập (convolution).
Đối với lọc
tuyến tính, mặt nạ lọc thường là bộ lọc trung bình.
Ví dụ: mặt nạ
lọc trung bình và mặt nạ Gauss:
|
|
1
|
1
|
1
|
|
1
|
1
|
1
|
|
|
1
|
1
|
1
|
|
|
1
|
2
|
1
|
|
2
|
4
|
2
|
|
|
1
|
2
|
1
|
b. Lập trình
void MyFilter2D(Mat imgin, Mat imgout,
Mat w)
{
int
m = w.size().height;
int
n = w.size().width;
int
a=m/2, b=n/2;
int
M = imgin.size().height;
int
N = imgin.size().width;
int
x, y, s, t;
float
r;
for
(x=a; x<M-a; x++)
for
(y=b; y<N-b; y++)
{
r
= 0;
for
(s=-a; s<=a; s++)
for
(t=-b; t<=b; t++)
r
+= w.at<float>(s+a,t+b)*imgin.at<uchar>(x+s,y+t);
imgout.at<uchar>(x,y)
= (uchar)r;
}
return;
}
void MySmooth(Mat imgin, Mat imgout)
{
int
m=35, n=35;
Mat
w = Mat(m,n,CV_32F);
int
x, y;
for
(x=0; x<m; x++)
for
(y=0; y<n; y++)
w.at<float>(x,y)
= 1.0/(m*n);
MyFilter2D(imgin,imgout,w);
Or
filter2d(imgin,imgout,CV_8U,w);
return;
}
Câu 4: Các bước lọc trong miền tần
số
Lọc
ảnh trong miền tần số gồm 7 bước sau đây:
Bước
1: Cho ảnh đầu vào f(x,y) có kích thước MxN. Mở rộng ảnh có kích thước là PxQ.
Cụ thể P=2M, Q=2N.
Bước
2: Thêm zero vào phần mở rộng, ta được ảnh fp(x,y).
Bước
3: Nhân fp(x,y) với (-1)x+y để dời F(0,0) vào tâm ảnh.
Bước
4: Biến đổi Fourier của ảnh ở Bước 3 ta được F(u,v).
Bước
5: Cho hàm lọc có giá trị thực H(u,v) đối xứng qua tâm (P/2,Q/2). Thực hiện
phép nhân
G(u,v)
= F(u,v)H(u,v).
Bước
6: Thu được ảnh đã xử lý bằng biến đổi Fourier ngược, lấy phần thực và dời trở
lại gốc tọa độ
Bước
7: Bỏ phần đã mở rộng, ta thu được ảnh g(x,y) có kích thước MxN.
Biểu
diễn bằng sơ đồ khối:

Câu 5: Lọc khe để xoá nhiễu Moire
void NotchFiltering(Mat imgin, Mat imgout)
{
int M =
imgin.size().height;
int N =
imgin.size().width;
// Buoc
1, 2, 3
int P =
getOptimalDFTSize(M);
int Q =
getOptimalDFTSize(N);
Mat f =
Mat(P,Q,CV_32FC2,CV_RGB(0,0,0));
int x,
y;
for
(x=0; x<M; x++)
for
(y=0; y<N; y++)
if
((x+y)%2 == 0)
f.at<Vec2f>(x,y)[0]
= imgin.at<uchar>(x,y);
else
f.at<Vec2f>(x,y)[0]
= -imgin.at<uchar>(x,y);
// Buoc
4
Mat F =
Mat(P,Q,CV_32FC2,CV_RGB(0,0,0));
dft(f,F);
// Buoc
5
Mat H =
Mat(P,Q,CV_32FC2,CV_RGB(0,0,0));
double
D01 = 12, D02 = 12, D03 = 5, D04 = 5;
double
Dk, D_k;
int u,
v;
int u1
= 164, v1 = 121;
int u2
= 168, v2 = 61;
int u3
= 210, v3 = 61;
int u4
= 206, v4 = 122;
int n =
4;
for
(u=0; u<P; u++)
for
(v=0; v<Q; v++) {
Dk = sqrt(1.0*(u-u1)*(u-u1)+1.0*(v-v1)*(v-v1));
D_k =
sqrt(1.0*(u-(P-u1))*(u-(P-u1))+1.0*(v-(Q-v1))*(v-(Q-v1)));
H.at<Vec2f>(u,v)[0]
= 1.0/(1.0+pow(D01/Dk,2*n))*1.0/(1.0+pow(D01/D_k,2*n));
Dk =
sqrt(1.0*(u-u2)*(u-u2)+1.0*(v-v2)*(v-v2));
D_k
= sqrt(1.0*(u-(P-u2))*(u-(P-u2))+1.0*(v-(Q-v2))*(v-(Q-v2)));
H.at<Vec2f>(u,v)[0] *=
1.0/(1.0+pow(D02/Dk,2*n))*1.0/(1.0+pow(D02/D_k,2*n));
Dk = sqrt(1.0*(u-u3)*(u-u3)+1.0*(v-v3)*(v-v3));
D_k
= sqrt(1.0*(u-(P-u3))*(u-(P-u3))+1.0*(v-(Q-v3))*(v-(Q-v3)));
H.at<Vec2f>(u,v)[0]
*= 1.0/(1.0+pow(D03/Dk,2*n))*1.0/(1.0+pow(D03/D_k,2*n));
Dk = sqrt(1.0*(u-u4)*(u-u4)+1.0*(v-v4)*(v-v4));
D_k
= sqrt(1.0*(u-(P-u4))*(u-(P-u4))+1.0*(v-(Q-v4))*(v-(Q-v4)));
H.at<Vec2f>(u,v)[0]
*= 1.0/(1.0+pow(D04/Dk,2*n))*1.0/(1.0+pow(D04/D_k,2*n));
}
Mat G =
Mat(P,Q,CV_32FC2,CV_RGB(0,0,0));
mulSpectrums(F,H,G,DFT_ROWS);
// Buoc
6, 7
Mat g =
Mat(P,Q,CV_32FC2,CV_RGB(0,0,0));
idft(G,g,DFT_SCALE);
float
r;
for
(x=0; x<M; x++)
for
(y=0; y<N; y++) {
if
((x+y)%2 == 0)
r
= g.at<Vec2f>(x,y)[0];
else
r
= -g.at<Vec2f>(x,y)[0];
if
(r < 0)
r
= 0;
if
(r > L-1)
r
= L-1;
imgout.at<uchar>(x,y)
= (uchar)r;
}
return;
}
Câu 6: Đếm số hạt gạo và phân ngưỡng
Code đếm số hạt gạo
void CountRice(Mat imgin,Mat imgout)
{
Mat temp = Mat(imgin.size(),CV_8UC1);
Mat w = getStructuringElement(MORPH_ELLIPSE,Size(81,81));
morphologyEx(imgin,temp,MORPH_TOPHAT,w);
double max;
minMaxLoc(temp,0,&max);
threshold(temp,temp,0.4*max,255,THRESH_BINARY);
// 0.9*max danh cho diem suong
medianBlur(temp,temp,5);
int fromTo[] = {0,0,0,1,0,2};
mixChannels(&temp,1,&imgout,1,fromTo,3);
int x, y, M, N;
M = imgout.size().height;
N = imgout.size().width;
Vec3b p;
uchar r, g, b;
int color = 100;
for (x=0; x<M; x++)
for (y=0; y<N; y++) {
p =
imgout.at<Vec3b>(x,y);
if (p[0] == L-1 &&
p[1] == L-1 && p[2] == L-1) {
r = color%256;
g = (color/256)%256;
b =
((color/256)/256)%256;
floodFill(imgout,Point(y,x),CV_RGB(r,g,b));
color++;
}
}
int k, mang[1000];
for (k=0; k<1000; k++)
mang[k] = 0;
for (x=0; x<M; x++)
for (y=0; y<N; y++) {
p =
imgout.at<Vec3b>(x,y);
r = p[2];
g = p[1];
b = p[0];
k = r + g*256 + b*256*256;
if (k > 0)
mang[k]++;
}
FILE *fp =
fopen("ThongKe.txt","wt");
fprintf(fp,"Co %d hot
gao\n",color-100);
for (k=0; k<1000; k++)
if (mang[k] > 0)
fprintf(fp,"Mau %3d co
%3d pixel\n",k,mang[k]);
fclose(fp);
char buffer[256];
sprintf(buffer,"Co %d hot
gao",color-100);
putText(imgout,buffer,Point(0,25),FONT_HERSHEY_DUPLEX,0.7,CV_RGB(0,255,0));
return;
}
Câu 7: Xây dựng và cài đặt thuật
toán biến đổi Hough
Mục đích của biến đổi Hough là để phát hiện ra đường thẳng
và đường tròn, hoặc đường bất kì. Thông thường nhất là dùng biến đổi Hough để phát hiện đường
thẳng.
Cho điểm xi,
yi ở trong mặt phẳng x, y.
Phương trình đường
thẳng y=ax+b.
Nếu đường thẳng đi
qua điểm (xi,yi) thì nó sẽ là yi=axI +b.
Khi cho a, b thay đổi
thì có rất nhiều đường thẳng đi qua
(xi,yi).
Ta có thêm một điểm (xj,yj) nữa thì cũng có vô số đường
thẳng đi qua (xj,yj).
Như vậy sẽ có một
đường thẳng đi qua hai điểm (xi,yi) và (xj,yj).
Và đường thẳng đó sẽ
có a, b giống nhau.
Yi= axi+b
Yj= axj+b


Dùng mặt phẳng a, b
không biết được kích thước ảnh là bao nhiêu vì cho ảnh chạy từ -∞, ∞
và b: -∞, ∞
Để khắc phục a, b
có thể ra tới ∞, thì ta chuyển phương trình đường thẳng qua tọa độ cực:
Do các điểm ảnh có
tọa độ x dương, y dương nên
chạy từ -900 đến 900 và phạm vi của
là
, trong đó D là khoảng cách xa nhất giữa 2 góc đối diện ở
trong ảnh.
Lập
trình:
void
ImageRotation(Mat imgin, Mat imgout)
{
vector<Vec2f> s_lines;
HoughLines(imgin, s_lines, 1,
CV_PI/180, 100, 0, 0 );
/// Show the result
float r, t, rmax, tmax;
rmax = s_lines[0][0];
tmax = s_lines[0][1];
for( size_t i = 0; i <
s_lines.size(); i++ ) {
r = s_lines[i][0];
t = s_lines[i][1];
if (r > rmax) {
rmax = r;
tmax = t;
}
}
int M = imgin.size().height;
int N = imgin.size().width;
int x, y;
int xr = 0, yr = 0;
for (x=0; x<M; x++)
for (y=0; y<N; y++) {
r =
imgin.at<uchar>(x,y);
if (r ==
L-1)
if
(x > xr) {
xr
= x;
yr
= y;
}
}
Mat rot_mat(2,3,CV_32FC1);
Point center = Point(yr,xr);
double angle =
(tmax-CV_PI/2)*180/CV_PI;
double scale = 1;
rot_mat = getRotationMatrix2D(center,angle,scale);
warpAffine(imgin,imgout,rot_mat,imgout.size());
return;
}
Câu 8: Nhận dạng khuôn mặt
Các bước nhận dạng
khuôn mặt.
Bước 1: Phát hiện khuôn
măt dùng thuật toán và file xml có sẳn trong openCV. Dùng Detect and
Display().
Bước 2: Tạo cơ sở dữ liệu
gồm 15 mặt, trong đó 10 mặt dùng để học, 5 mặt dùng để nhận dạng.
Bước 3: nhận dạng dùng eigenface.
Lập
trình
int
RecognitionOffLine(void)
{
vector<Mat> images;
vector<int> labels;
char filename[64];
for (int i=1; i<=10; i++) {
sprintf(filename,"data\\ThayDuc\\%02d.jpg",i);
Mat img =
imread(filename,CV_LOAD_IMAGE_GRAYSCALE);
resize(img,img,Size(150,150));
images.push_back(img);
labels.push_back(1);
}
for (int i=1; i<=11; i++) {
sprintf(filename,"data\\Thuong\\%02d.jpg",i);
Mat img =
imread(filename,CV_LOAD_IMAGE_GRAYSCALE);
resize(img,img,Size(150,150));
images.push_back(img);
labels.push_back(2);
}
for (int i=1; i<=10; i++) {
sprintf(filename,"data\\Minh\\%02d.jpg",i);
Mat img =
imread(filename,CV_LOAD_IMAGE_GRAYSCALE);
resize(img,img,Size(150,150));
images.push_back(img);
labels.push_back(3);
}
Ptr<FaceRecognizer> model =
createEigenFaceRecognizer();
model->train(images,labels);
Mat test = imread("test\\ThayDuc\\01.jpg",CV_LOAD_IMAGE_GRAYSCALE);
resize(test,test,Size(150,150));
int predictedLabel =
model->predict(test);
return 0;
}
.jpg)
Không có nhận xét nào:
Đăng nhận xét