You are on page 1of 20

BUỔI 1:

Bài 1: Xoay ảnh 1 góc anfa độ


Kết quả:

Ảnh gốc Ảnh xoay 1 góc 26 độ

Code:
import cv2
import math
import numpy as np

def rotateUpdate(image, anfa):


height = image.shape[0]
width = image.shape[1]
x0 = height // 2
y0 = width // 2
anfa = anfa*(math.pi)/180
imageRotated = np.zeros([height, width, 3], dtype=np.uint8)
for x in range(height):
for y in range(width):
xx = x0 + (x-x0)*math.cos(anfa) - (y-y0)*math.sin(anfa)
yy = y0 + (x-x0)*math.sin(anfa) + (y-y0)*math.cos(anfa)
xxx = round(xx)
yyy = round(yy)
if abs(xxx-xx) <= 0.1:
x1 = xxx
x2 = xxx
x3 = xxx
x4 = xxx
else:
x1 = math.floor(xx)
x2 = math.floor(xx)
x3 = math.ceil(xx)
x4 = math.ceil(xx)
if abs(yyy-yy) <= 0.1:
y1 = yyy
y2 = yyy
y3 = yyy
y4 = yyy
else:
y1 = math.floor(yy)
y2 = math.ceil(yy)
y3 = math.floor(yy)
y4 = math.ceil(yy)
for k in range(3):
if 0 <= x1 < height and 0 <= y1 < width:
imageRotated[x1][y1][k] = image[x][y][k]
if 0 <= x2 < height and 0 <= y2 < width:
imageRotated[x2][y2][k] = image[x][y][k]
if 0 <= x3 < height and 0 <= y3 < width:
imageRotated[x3][y3][k] = image[x][y][k]
if 0 <= x4 < height and 0 <= y4 < width:
imageRotated[x4][y4][k] = image[x][y][k]
return imageRotated

angle = 26
img = cv2.imread('image/12.JPG')
cv2.imwrite("Original.jpg", img)
k2 = rotateUpdate(img, angle)
cv2.imwrite("Rotated.jpg", k2)
Bài 2: Tạo ảnh GIF
Kết quả:
Code:
import imageio.v2 as imageio
import os
files = os.listdir('images')
image_path = [os.path.join('images',file) for file in files]
images = []
for img in image_path:
images.append(imageio.imread(img))
imageio.mimwrite('myfirsthwgif.gif', images, duration = 500)
BUỔI 2:
Bài 1: Chia 1 ảnh thành 16 ô rồi xếp random thành 1 ảnh
Kết quả:

Code:
import cv2
import math
import numpy as np
import random

def permImg():
arr = [*range(16)]
random.shuffle(arr)
image = cv2.imread('kodak\kodim07.png')
height = image.shape[0]
width = image.shape[1]
w16 = width // 4
h16 = height // 4
cnt = 0
img = np.zeros([16, h16, w16, 3], dtype=np.uint8)
for k in range(4):
for h in range(4):
for x in range(h16):
for y in range(w16):
img[cnt][x][y] = image[h16*k + x][w16 * h+y]
cnt += 1

ImgCreated = np.zeros([height, width, 3], dtype=np.uint8)


i = 0
for k in range(4):
for h in range(4):
for x in range(h16):
for y in range(w16):
ImgCreated[h16*k + x][w16 * h+y] = img[arr[i]][x][y]
i += 1
cv2.imwrite("Created.jpg", ImgCreated)

permImg()
BUỔI 3:
Câu 1: Viết Chương trình tìm & hiển thị Histogram 1 hình bất kỳ (xám & màu)
Kết quả:

Code:
import cv2
import math
import numpy as np
import random
from matplotlib import pyplot as plt

image = cv2.imread('image/4.JPG')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

plt.hist(gray.ravel(), 256, [0, 256])


plt.show()

cv2.waitKey(0)
cv2.destroyWindow()
Câu 2: Cân bằng histogram
Kết quả

Nhận xét :
- Khi sử dụng hàm có sẵn, histogram được trải dài với mật độ tốt hơn so với hàm
được viết
- Tuy nhiên, khi zoom lên, biểu đồ này lên xuống liên tục và không mượt bằng thuật
được viết
Code:
clc
clear all
close all
warning off

x= imread('http://nghiencuuquocte.org/wp-content/uploads/2018/03/14.jpg');
subplot(3,2,1);
imshow(x);
title('Original Image');
subplot(3,2,2);
imhist(x);
title('Histogram of Original Image using built in function');
axis tight;
h=zeros(1,256);
[r c]=size(x);
totla_no_of_pixels=r*c;
n=0:255;
j=histeq(x);
subplot(3,2,3);
imshow(j);
title('Histogram Equalization using built in function');
subplot(3,2,4);
imhist(j);
axis tight;
title('Histogram Equalization using built in function');
for i=1:r
for j=1:c
h(x(i,j)+1)=h(x(i,j)+1)+1;
end
end
for i=1:256
h(i)=h(i)/totla_no_of_pixels;
end
temp=h(1);
for i=2:256
temp=temp+h(i);
h(i)=temp;
end

for i=1:r
for j=1:c
x(i,j)=round(h(x(i,j)+1)*255);
end
end
subplot(3,2,5);
imshow(x);
title('Histogram Equalized image using own code');
subplot(3,2,6);
imhist(x);
axis tight;
title('Histogram Equalization using own code');

BUỔI 4:
H1 = ¼ . [1 ; 2 ; 1] ; H2 = H1’ (Chuyển vị); I : ảnh xám
a, Tính
Y1 = I * H1
Y2 = Y1 * H2
b, Gọi H = 1/16 [1 2 1;2 4 2;1 2 1]
Tính Y3 = I * H
c, So sánh Y2 & Y3. Nhận xét 2 thuộc tính Y2 & Y3
Kết quả:

Y1 Y2 Y3
Nhận xét:
- Ta thấy ảnh Y2 và Y3 là giống nhau vì bộ lọc H của Y3 chính là bộ lọc tách được
và tách thành 2 bộ lọc chính là H1 và H2
- Khi dùng lần lượt 2 bộ lọc H1 và H2 độ phức tạp sẽ là M.N.3.2, tốc độ sẽ nhanh
hơn khi dùng bộ lọc H với độ phức tạp là M.N.3.3
- Tổng quát khi hình ảnh có kích thước lớn, và bộ lọc tách được có kích thước lớn
thì thời gian chạy sẽ tối ưu hơn rất nhiều khi tách thành 2 bộ lọc con rồi đem đi
chập.
Code:
img = rgb2gray(imread('/MATLAB Drive/12.JPG'));
[h, w] = size(img);
H1 = [1 ;2 ;1] / 4;
H2 = transpose(H1);
% Cau A
Y1 = conv2(img, H1,'same');
Y2 = conv2(Y1, H2,'same');
subplot(2,2,1);
imshow(Y1,[]);
title('Y1');
subplot(2,2,2);
imshow(Y2,[]);
title('Y2');
% Cau B
H = [1 2 1; 2 4 2; 1 2 1] / 16;
Y3 = conv2(img, H, 'same');
size(Y3);
subplot(2,2,3);
imshow(Y3,[]);
title('Y3');
subplot(2,2,4);
imshow(img,[]);
title('Original');
max(abs(Y2-Y1));
max(abs(Y3-Y2));
Buổi 5: Dùng phương pháp nội suy song tuyến tính tìm giá trị ảnh từ ảnh mosaic
Kết quả:

Ảnh mosaic ban đầu Ảnh sau khi nội suy


Code:
% THUAT TOAN NOI SUY SONG TUYEN TINH
img = imread('/MATLAB Drive/19.jpg');
[h, w, t] = size(img);
I = img;
I(2:2:h,:,1) = 0;I(:,2:2:w,1) = 0;
I(1:2:h,1:2:w,2) = 0;I(2:2:h,2:2:w,2) = 0;
I(1:2:h,:,3) = 0;I(:,1:2:w,3) = 0;
imwrite(I,'res1.jpg')
WRB = [1 2 1;2 4 2;1 2 1] / 4;
WG = [0 1 0; 1 4 1; 0 1 0] / 4;
I(:,:,1) = imfilter(I(:,:,1),WRB,'replicate');
I(:,:,2) = imfilter(I(:,:,2), WG,'replicate');
I(:,:,3) = imfilter(I(:,:,3), WRB,'replicate');
imwrite(I,'res2.jpg')
Nhận xét:
- Có hiện tượng sai màu ở 1 số điểm, như ở hàng rào
Buổi 6: Dùng phương pháp Alleyson để giải quyết bài toán demosaicing
Kết quả:

Ảnh mosaic ban đầu Ảnh sau khi áp dụng thuật toán Alleysson
Nhận xét:
- Vấn đề sai màu được cải thiện hơn đôi chút
- Về vấn đề 'blurring', thuật toán Alleysson được cải thiện rõ rệt hơn so với thuật
toán nội suy song tuyến tính vì thuật toán này chỉ nội suy trên thành phần Chrominance,
trong khi Luminance được trích xuất từ hình ảnh mosaic 1 lớp đầu tiên.
Code:
% THUAT TOAN ALLEYSSON
img = imread('/MATLAB Drive/19.jpg');
[h, w, t] = size(img);
I = zeros(h,w);
I(1:2:h,1:2:w) = img(1:2:h,1:2:w,1);
I(1:2:h,2:2:w) = img(1:2:h,2:2:w,2);
I(2:2:h,1:2:w) = img(2:2:h,1:2:w,2);
I(2:2:h,2:2:w) = img(2:2:h,2:2:w,3);
FL = [-2 3 -6 3 -2;3 4 2 4 3;-6 2 48 2 -6;3 4 2 4 3;-2 3 -6 3 -2]/64;
lmn = conv2(I,FL,'same');
MC = I - lmn;
C = img;
mR = zeros(h,w);mG = zeros(h,w);mB = zeros(h,w);
mR(1:2:h,1:2:w) = 1;
mG(1:2:h,2:2:w) = 1;mG(2:2:h,1:2:w) = 1;
mB(2:2:h,2:2:w) = 1;
C1 = MC .* mR;
C2 = MC .* mG;
C3 = MC .* mB;
WRB = [1 2 1;2 4 2;1 2 1] / 4;
WG = [0 1 0; 1 4 1; 0 1 0] / 4;
res = img;
res(:,:,1) = conv2(C1,WRB,'same') + lmn;
res(:,:,2) = conv2(C2, WG,'same') + lmn;
res(:,:,3) = conv2(C3, WRB,'same') + lmn;
imwrite(res,'res.jpg')

BUỔI 7, 8: không có
BUỔI 9:
Chọn các hình: bãi biển, tòa nhà, nội thất, cây, người đi bộ
Trộn phổ biên độ của 5 hình trên, tìm cách tìm tương ứng
Kết quả:
Nhận xét cách tìm ảnh tương ứng với phổ nào:
- Những ảnh có nhiều góc cạnh thì khi chuyển sang biểu diễn ở miền tần số sẽ có
nhiều đường sáng chạy qua tâm, những đường đó thể hiện sự chuyển đổi mức
năng lượng (các góc cạnh) từ vùng này sang vùng khác trong ảnh.
Để dễ giải thích, ta đánh số tăng dần từ 1 đến 5 từ trái qua phải, từ trên xuống dưới
- Với ảnh bãi biến tương ứng với hình 4
- Với hình ảnh tòa nhà, phổ biên độ gồm nhiều đường gạch thẳng nên sẽ tương ứng
với hình 5
- Với hình ảnh nội thất tương ứng với hình 2
- Với hình ảnh người đi bộ tương ứng với hình 3
- Với hình ảnh cây cối tương ứng với hình 1
Code:
img1 = imread('/MATLAB Drive/beach.jpg');
img2 = imread('/MATLAB Drive/building.jpg');
img3 = imread('/MATLAB Drive/household.jpg');
img4 = imread('/MATLAB Drive/pedestrian.jpg');
img5 = imread('/MATLAB Drive/tree.jpg');
Arr = [2 4 6 8 10];
Arr = Arr(randperm(length(Arr)));
figure
subplot(3,4,1);imshow(img1,[]);
subplot(3,4,3);imshow(img2,[]);
subplot(3,4,5);imshow(img3,[]);
subplot(3,4,7);imshow(img4,[]);
subplot(3,4,9);imshow(img5,[]);
if size(img1, 3) == 3
img1 = rgb2gray(img1);
end
if size(img2, 3) == 3
img2 = rgb2gray(img2);
end
if size(img3, 3) == 3
img3 = rgb2gray(img3);
end
if size(img4, 3) == 3
img4 = rgb2gray(img4);
end
if size(img5, 3) == 3
img5 = rgb2gray(img5);
end
F1 = fft2(double(img1));
F2 = fft2(double(img2));
F3 = fft2(double(img3));
F4 = fft2(double(img4));
F5 = fft2(double(img5));
% Shift the zero-frequency component to the center of the spectrum
F1 = fftshift(F1);
F2 = fftshift(F2);
F3 = fftshift(F3);
F4 = fftshift(F4);
F5 = fftshift(F5);
% Compute the magnitude spectrum
F_mag1 = abs(F1);
F_mag2 = abs(F2);
F_mag3 = abs(F3);
F_mag4 = abs(F4);
F_mag5 = abs(F5);
% Display the magnitude spectrum
subplot(3,4,Arr(1));imshow(log(1+F_mag1), []);
subplot(3,4,Arr(2));imshow(log(1+F_mag2), []);
subplot(3,4,Arr(3));imshow(log(1+F_mag3), []);
subplot(3,4,Arr(4));imshow(log(1+F_mag4), []);
subplot(3,4,Arr(5));imshow(log(1+F_mag5), []);
Buổi 10: không có
Buổi 11:
Câu 1: Biến đổi Fourier

Câu 2: Gọi I là ảnh mosaic 1 lớp. Sử dụng các bộ lọc để lọc 1 cách hợp lý và nhận xét
Kết quả:

Thứ tự các bộ lọc lần lượt là lý tưởng, Butterworth, Gausian


Nhận xét:
- Bộ lọc thông thấp lý tưởng và Butterworth bị hiện tượng gợn sóng, rõ nhất ở mái
nhà, tăng dần theo bậc của lọc. Ngược lại, Gausian thì không bị vì trong miền tần
số hay không gian đều có dạng Gausian
- Tuy nhiên, tần số cắt càng tăng thì khoảng cách chuyển tiếp càng rộng. Do đó, nếu
ta muốn khoảng chuyển tiếp hẹp thì Butterworth sẽ tốt hơn nhưng chịu hiện tượng
gợn sóng.
Code:
img = imread('kodak/kodim19.png');
[h, w, t] = size(img);
I = zeros(h,w);
I(1:2:h,1:2:w) = img(1:2:h,1:2:w,1);
I(1:2:h,2:2:w) = img(1:2:h,2:2:w,2);
I(2:2:h,1:2:w) = img(2:2:h,1:2:w,2);
I(2:2:h,2:2:w) = img(2:2:h,2:2:w,3);
F = fft2(double(I));
[M, N] = size(I);
H1 = zeros(M, N);H2 = zeros(M, N);H3 = zeros(M, N);
D0 = 300;
n = 3;
F = fftshift(F);
for u = 1:M
for v = 1:N
d = sqrt((u - M/2)^2 + (v-N/2)^2);
if (d<=D0)
H1(u,v) = 1;
else
H1(u,v) = 0;
end
H2(u,v) = 1 / (1 + (d / D0)^(2*n));
H3(u,v) = exp(-d^2 / (2 * D0^2));
end
end

Sy1 = F .* H1;
Y1 = ifft2(ifftshift(Sy1));
Sy2 = F .* H2;
Y2 = ifft2(ifftshift(Sy2));
Sy3 = F .* H3;
Y3 = ifft2(ifftshift(Sy3));
subplot(1,3,1);
imshow(real(Y1), []);
subplot(1,3,2);
imshow(real(Y2), []);
subplot(1,3,3);
imshow(real(Y3), []);
Câu 3:

Kết quả:

Code:

Buổi 12: không có


Buổi 13:
Câu 1: Áp dụng thuật Kmeans cho ảnh
Kết quả:
Với n = 3 cụm, ta thu được hình ảnh như trên phía bên phải
Code:
function [idx, C] = kmeans_code(data, k)
C = [0 0; 0 9; 9 0; 9 9];
n = size(data, 1);
idx = zeros(1, n);
prev_idx = ones(1, n);
while ~isequal(prev_idx, idx)
prev_idx = idx;
for i = 1:n
t = zeros(1, k);
disp(size(t, 2));
for j = 1:size(t, 2)
t(j) = (data(i,1) - C(j,1))^2 + (data(i,2) - C(j,2))^2;
end
[~, idx(i)] = min(t);AA
end
for j = 1:k
points_in_cluster = data(idx == j, :);
C(j, :) = mean(points_in_cluster, 1);
end
end
end
—-----------------------

image = imread('kodak/kodim10.png');
[h, w, ~] = size(image);
data = reshape(image, h*w, 3);
num_clusters = 3;
[cluster_idx, cluster_center] = kmeans_code(double(data), num_clusters);
cluster_label = reshape(cluster_idx, h, w);
avg_colors = zeros(num_clusters, 3);
for i = 1:num_clusters
cluster_data = data(cluster_idx == i, :);
avg_color = mean(cluster_data, 1);
avg_colors(i, :) = avg_color;
end
figure;
subplot(1, 2, 1);
imshow(image);
title('Original');
subplot(1, 2, 2);
imagesc(cluster_label);
axis off;
title('Result’);
colormap(gca, avg_colors/255);

Câu 2: Tìm thêm 1 phương pháp segmentation

Tìm hiểu thuật toán Watershed:


- Bất kỳ hình ảnh thang độ xám nào cũng có thể được xem như một bề mặt địa hình
trong đó cường độ cao biểu thị các đỉnh và đồi trong khi cường độ thấp biểu thị các
thung lũng. Bắt đầu lấp đầy mọi thung lũng bị cô lập (cực tiểu cục bộ) bằng nước có
màu khác nhau (nhãn). Khi nước dâng lên, tùy thuộc vào các đỉnh (độ dốc) gần đó,
nước từ các thung lũng khác nhau, rõ ràng là có màu sắc khác nhau sẽ bắt đầu hợp
nhất. Để tránh điều đó, xây dựng các rào cản ở những nơi nước chảy vào. Tiếp tục
công việc đổ đầy nước và xây dựng các rào chắn cho đến khi tất cả các đỉnh đều chìm
trong nước. Sau đó, các rào cản sẽ cung cấp kết quả phân khúc. Đây là "philosophy"
đằng sau thuật toán Watershed.
Buổi 14: không có
Buổi 15: Nhận dạng biển số xe
Chọn phương pháp xử lý ảnh thuần, các bước của thuật toán như sau:
Bước 1: Định nghĩa vài thông số cho bài toán như: Kích thước biển số lớn nhất và
kích thước biển số nhỏ nhất. Các bạn tùy bài toán mà định nghĩa. Ví dụ bài toán trông
xe vào bãi thì camera để gần, kích thước biển số to hơn nhưng nếu bài toán nhận diện
xe đi qua cửa bằng camera trên cao chẳng hạn thì kích thước biển số sẽ nhỏ hơn.
Chúng ta tùy vào hiện trường thực tế mà tinh chỉnh cho phù hợp.
Bước 2: Load ảnh và thực hiện reszie về kích thước mong muốn.
Bước 3: Chuyển về đen trắng và thực hiện thuật toán tìm cạnh băng Canny
Bước 4: Tìm các contour có trong hình
Bước 5: Với các contour tìm được ở bước 4, chúng ta lặp qua 1 lượt và chọn contour
lớn nhất hội đủ các điều kiện:
- Có 4 cạnh (sau khi đã approx): vì biển số là đối tượng có 4 cạnh.
- Có kích thước nằm trong vùng kích thước đã định nghĩa ở bước 1.
- Contour đó sẽ là biển số chúng ta cần tìm.
Bước 6. Tiến hành tìm các điểm góc của contour nói trên và trích hình ảnh biển số ra
khỏi hình ảnh cả xe.
Kết quả:

Code:
import cv2
import imutils
import numpy as np

max_size = 5000
min_size = 900
img = cv2.imread('test.jpg', cv2.IMREAD_COLOR)

img = cv2.resize(img, (620, 480))


gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # convert to grey scale
gray = cv2.bilateralFilter(gray, 11, 17, 17) # Blur to reduce noise
edged = cv2.Canny(gray, 30, 200) # Perform Edge detection
cnts = cv2.findContours(edged.copy(), cv2.RETR_TREE,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
screenCnt = None
for c in cnts:
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.05 * peri, True)
if len(approx) == 4 and max_size > cv2.contourArea(c) > min_size:
screenCnt = approx
break
if screenCnt is None:
detected = 0
print ("No plate detected")
else:
detected = 1

if detected == 1:
cv2.drawContours(img, [screenCnt], -1, (0, 255, 0), 3)
mask = np.zeros(gray.shape, np.uint8)
new_image = cv2.drawContours(mask, [screenCnt], 0, 255, -1, )
new_image = cv2.bitwise_and(img, img, mask=mask)
(x, y) = np.where(mask == 255)
(topx, topy) = (np.min(x), np.min(y))
(bottomx, bottomy) = (np.max(x), np.max(y))
Cropped = gray[topx:bottomx + 1, topy:bottomy + 1]
cv2.imshow('Input image', img)
cv2.imshow('License plate', Cropped)
cv2.waitKey(0)
cv2.destroyAllWindows()

You might also like