0
E
BÀI TẬP LỚN MÔN HỌC
Xử Lý Ảnh
Nội dung
Tìm hiểu định dạng ảnh *.BMP
Các thao tác với file *.BMP trên C++
Chuyển ảnh màu sang ảnh đa mức xám
Phân ngưỡng ảnh
Phép mở ảnh
Một số nhận xét
Nhóm bài tập lớn 5 - Nhóm học 4
Mục lục
I.Thông tin nhóm ----------------------------------------------------------------------------------------------------------------------- 2
II.Nội dung báo cáo -------------------------------------------------------------------------------------------------------------------- 3
1.Tìm hiểu định dạng file ảnh *.BMP ------------------------------------------------------------------------------------------ 3
1.1.File ảnh *.BMP được hiểu như thế nào?------------------------------------------------------------------------------ 5
1.2.Định dạng Bitmap là gì ? -------------------------------------------------------------------------------------------------- 5
1.3.Cấu trúc tập tin ảnh bitmap (File structure) -------------------------------------------------------------------------- 7
1.4.Kích thước lưu trữ file *.bmp ------------------------------------------------------------------------------------------- 10
1.5.Kỹ thuật nén ảnh bitmap ------------------------------------------------------------------------------------------------ 10
1.6.Ví dụ cụ thể 1 file bmp --------------------------------------------------------------------------------------------------- 11
1.7.Ưu, khuyết điểm và ứng dụng của *.BMP --------------------------------------------------------------------------- 12
2.Các thao tác với file *.bmp trên C++ ---------------------------------------------------------------------------------------- 13
2.1.Chuyển ảnh màu sang ảnh đa mức xám ----------------------------------------------------------------------------- 20
2.2.Phân ngưỡng ảnh(Nhị phân hóa) -------------------------------------------------------------------------------------- 24
2.1.1.Thuật toán đẳng liệu ------------------------------------------------------------------------------------------------ 25
2.1.2.Thuật toán đối xứng ------------------------------------------------------------------------------------------------ 30
2.1.3.Thuật toán tam giác ------------------------------------------------------------------------------------------------- 31
2.3.Các Phép Toán Hình Thái Học------------------------------------------------------------------------------------------- 33
2.3.1.Phép mở ảnh(Opening) -------------------------------------------------------------------------------------------- 33
2.3.2.Phép co(Erosion) ----------------------------------------------------------------------------------------------------- 33
2.3.3.Phép giãn nở(Dilation) ---------------------------------------------------------------------------------------------- 35
3.Một số nhận xét từ kết quả thu được: ------------------------------------------------------------------------------------- 44
3.1.Phân ngưỡng --------------------------------------------------------------------------------------------------------------- 44
3.2.Phép mở ảnh --------------------------------------------------------------------------------------------------------------- 49
Báo cáo bài tập lớn môn học: Xử Lý Ảnh
I.Thông tin nhóm
Môn học Xử Lý Ảnh
Giảng viên Phạm Văn Sự
Nhóm học tín chỉ Nhóm 4 – Học phòng 102 A2- Kíp 5- Thứ 5
Nhóm bài tập lớn Nhóm số 5
Danh sách sinh viên trong nhóm
Họ và tên
Mã sinh viên
1. Nguyễn Hữu Hiếu
B15LDCN003
2. An Thị Kim Huệ
B15LDCN008
3. Nguyễn Trịnh Thị Huyền
B15LDCN007
II.Nội dung báo cáo
1.Tìm hiểu định dạng file ảnh *.BMP
1.1.File ảnh *.BMP được hiểu như thế nào?
BMP là viết tắt của “BitMap Picture”. Một file ảnh *.bmp được hiểu là một ảnh có định dạng bitmap.
1.2.Định dạng Bitmap là gì ?
●
Bitmap là một định dạng file để lưu trữ hình ảnh kỹ thuật số dưới dạng lưới (Raster)
●
Định dạng bitmap được Microsoft Corp tạo ra vào năm 1994. Nó là một định dạng ổn định và
được sử dụng phổ biến trên Windows kể từ phiên bản Windows 3.0.
●
Các thuộc tính tiêu biểu của một tập tin bitmap:
○
Bit per pixel (Số bit trên mỗi điểm ảnh) hay độ sâu màu thường được ký hiệu bởi n. Một
ảnh BMP n-bit có 2𝑛 màu. Giá trị n càng lớn thì ảnh càng có nhiều màu. Một số giá trị
tiêu biểu của n:
■
n= 1: Ảnh 2 màu, ảnh nhị phân, điển hình là ảnh trắng đen.
■
n= 4: Ảnh 16 màu
■
n= 8: Ảnh 256 màu.Điển hình là ảnh đa mức xám.
■
n= 16 (ảnh 65536 màu)
■
n= 24 (ảnh 16 triệu màu). Ảnh BMP 24-bit có chất lượng hình ảnh trung thực
nhất:
○
Chiều cao của ảnh (height) xác định bởi số điểm ảnh (pixel).Ví dụ ảnh có chiều cao 10px
○
Chiều rộng của ảnh (width) xác định bởi số điểm ảnh (pixel).Ví dụ: ảnh có chiều rộng 5px
1.3.Cấu trúc tập tin ảnh bitmap (File structure)
(en.wikipedia.org)
Giải thích sơ bộ
Tên cấu trúc
Độ lớn
Mục đích
Chú thích
Bitmap file header
14 bytes
Để lưu trữ các
Cho biết định dạng file là bitmap,
thông tin chung
kích thước file, và vị trí bắt đầu của
về các tập tin hình
nội dung file
ảnh bitmap
Không cần thiết sau khi các tập tin
được nạp vào bộ nhớ của thiết bị
hiển thị
Bitmap Information
40 bytes
Lưu một số thông
Cho biết chiều rộng, chiều cao, số
tin chi tiết giúp
lượng màu sắc sử dụng.
hiển thị ảnh
Color Palette
4*x bytes
Định nghĩa các
Gồm nhiều bộ có kích thước 4 bytes
màu sử dụng
xếp liền nhau theo cấu trúc: Blue –
trong ảnh
Green – Red – Reserved
x là số màu sử dụng trong ảnh
Bitmap Data
Tùy thuộc
Dùng để lưu dữ
Chứa giá trị màu của các điểm ảnh
vào file
liệu ảnh
trong * .bmp
Các điểm ảnh được lưu theo thứ tự
từ trái qua phải trên 1 dòng và các
dòng được lưu theo thứ tự dưới lên
trên.
Mỗi byte trong vùng bitmap data
biểu diễn 1 hoặc nhiều điểm ảnh tùy
theo số bits trên 1 pixel.
Xem phần 2: Các thao tác cơ bản trong C++ với file bmp để hiểu chi tiết hơn về phần cấu trúc file
bitmap
Khái niệm Padding bytes( bộ nhớ đệm): Thực tế khi một mảng các pixel được nạp vào bộ nhớ, mỗi hàng
phải bắt đầu tại một địa chỉ bộ nhớ mà địa chỉ đó là bội số của 4. Nhưng do ta chỉ có sử dụng 3 bytes cho
mỗi pixel nên mỗi dòng có thể kết thúc với địa chỉ không chia hết cho 4. Vì vậy trong mỗi dòng sẽ có
những padding bytes để hạn chế/bù đắp số byte thiếu và đảm bảo rằng kết thúc mỗi dòng địa chỉ bộ
nhớ luôn là bội số của 4. Ví dụ như ảnh có kích thước 10x14 (14 là width) thì padding sẽ là 2 bytes vì:Số
byte= 14 x 3 = 42 (nhân 3 vì 3 là số byte trong mỗi pixel) và 42mod4 = 2(42 chia 4 được 10 dư 2). Còn
nếu bức ảnh có kích thước 3x4 (4 là width) thì padding sẽ là 0 vì 4x3 = 12 và 12mod4 = 0.
1.4.Kích thước lưu trữ file *.bmp
Như đã nói ở phần Padding bytes, kích thước của mỗi hàng(width) sẽ được làm tròn tới bội số của 4
byte. Đối với hình ảnh có chiều cao(height) > 1, nhiều padding bytes sẽ được lưu trữ liên tục và tạo
thành Pixel array. Tổng số byte cần thiết để lưu trữ trên một hàng pixel có thể được tính như sau:
(en.wikipedia.org)
Lưu ý: Dấu ngoặc này có nghĩa là lấy phần nguyên dưới.
Tổng số lượng byte cần thiết để lưu trữ một mảng các điểm ảnh.Với n bit trên mỗi điểm ảnh
(bpp), với 2𝑛 màu sắc, có thể được tính bằng cách như sau
(en.wikipedia.org)
Dễ dàng hiểu: Dung lượng thật sự để lưu trữ ảnh sẽ bé hơn hoặc bằng dung lượng file trong bộ
nhớ.
1.5.Kỹ thuật nén ảnh bitmap
Ảnh có thể được nén 4-bit hoặc 8-bit bằng thuật toán RLE hoặc Huffman1D.
Các ảnh có độ sâu màu là 16bpp và 32bpp luôn được lưu trữ không nén
Ảnh có thế hoàn toàn lưu trữ mà không sử dụng kỹ thuật nén nào nếu muốn
1.6.Ví dụ cụ thể 1 file bmp
(en.wikipedia.org)
1.7.Ưu, khuyết điểm và ứng dụng của *.BMP
Ưu Điểm
●
Định dạng file này mang toàn bộ các ưu điểm của phương thức lưu trữ ảnh dạng raster. Ngoài
ra, do sử dụng công nghệ nén không tổn hao nên ảnh *.BMP có độ sắc nét và màu sắc tươi tắn
cao.
●
Dễ dàng dịch ra thành định dạng điểm (dot-format) để xuất ra các thiết bị như màn hình CRT,
máy in. Và thích hợp để sử dụng trong in ấn.
●
Độ tương thích cao trên nền tảng Windows
Khuyết điểm
●
Như trên, do là lưu trữ ảnh dạng raster và không sử dụng công nghệ nén hiệu quả nên *.BMP sẽ
bị vỡ ảnh, nhòe ảnh nếu ta thay đổi kích thước và cần có dung lượng rất lớn để lưu trữ. Ngày
nay những hình ảnh chúng ta trông thấy trên internet là hình ảnh có công nghệ nén gây tổn hao
để giảm không gian lưu trữ như *.jpeg.
●
Định dạng *.BMP không hỗ trợ chế độ nền trong suốt, có nghĩa là: Ảnh *.BMP chỉ có thể hiển thị
dạng hình chữ nhật, nên ngày nay với yêu cầu đồ họa luôn ưu tiên hàng đầu cho các phần mềm,
website. Chúng ta hay sử dụng các định dạng khác như *.PNG trong việc thiết kế.
2.Các thao tác với file *.bmp trên C++
Xây dựng cấu trúc riêng để thao tác đọc file *.bmp
Hàm chuyển ảnh bmp sang ảnh đa mức xám
Phân ngưỡng ảnh
Phép mở ảnh
Như đã đề cập ở phần tìm hiểu về file *.bmp, chúng ta biết được cấu trúc của tập tin ảnh bitmap. Vì thế
cần xây dựng các struct để lưu lại dữ liệu về file bitmap
Cấu trúc Pixel
struct Pix
{
unsigned char B;
unsigned char G;
unsigned char R;
};
B,G,R là giá trị của 3 màu Blue, Green, Red tại mỗi điểm ảnh.
Cấu trúc bitmap
struct BitMap
{
short
m_signature;
long
m_reserved1;
long
m_reserved2;
long
m_dataOffSet;
long
m_size;
long
m_width;
long
m_height;
short
m_planes;
short
m_bpp;
long
m_compression;
long
m_sizeImage;
long
m_xPixelsPreMeter;
long
m_yPixelsPreMeter;
long
m_colorsUsed;
long
m_colorsImportant;
};
Mô tả
(Xem lại hình ảnh cấu trúc ở phần 1.3 để hiểu rõ hơn)
m_signature Kiểu file (File bitmap thì sẽ có giá trị BM)
m_size Kích thước của file (byte)
m_reserved Phần dự trữ, có giá trị được quyết định bởi phần mềm tạo ra file
bitmap
_data_Offset offset của dữ liệu của hình ảnh (Tính từ vị trí bắt đầu của file bitmap
là 0)
m_width, m_height Chiều dài và chiều rộng của bức ảnh (tính theo pixel)
m_planes Đối với bitmap, giá trị buộc phải bằng 1
m_bpp Số bit trên mỗi pixel của ảnh, thông dụng có giá trị 24 (8bits cho mỗi
kênh R-G-B)
m_compression Kiểu nén của ảnh
m_sizeImage Kích thước của ảnh
m_xPixelsPreMeter Độ phân giải ngang của ảnh
m_yPixelsPreMeter Độ phân giải dọc của ảnh
m_color_used Số màu có trong color table (Thường là 0 do color table không được
sử dụng)
m_color_important Số index cần để hiện thị hình ảnh (Đối với index color table)
Hàm đọc file bitmap
void readBMP(const char* filePath, BitMap &header, char* &data)
{
FILE* f = fopen(filePath, "rb");
if (!f)
{
printf("Cannot open file for reading!!!");
exit(-1);
}
fread(&header, sizeof(header), 1, f);
int _padding = header.m_width % 4;//Đọc phần Padding bytes ở trên để hiểu tại sao lại chia 4 lấy
dư.
int _size = header.m_width * header.m_height * (header.m_bpp / 8) + _padding *
header.m_height;
data = new char[_size];
fread(data, sizeof(char), _size, f);
fclose(f);
}
Hàm ghi file bitmap
void writeBMP(const char* filePath, BitMap &header, char* &data)
{
FILE* f = fopen(filePath, "wb");
if (!f)
{
printf("Cannot open file for writing!!!");
exit(-1);
}
fwrite(&header, sizeof(header), 1, f);
int _padding = header.m_width % 4;
int _size = header.m_width * header.m_height * (header.m_bpp / 8) + _padding *
header.m_height;
fwrite(data, sizeof(char), _size, f);
fclose(f);
}
Chuyển data của 1 ảnh bitmap vào một mảng các Pixel
Pix* convertDataToPixelArray(char* &data, BitMap &header)
{
int _size = header.m_width * header.m_height;
Pix* _pixels = new Pix[_size];
int _padding = header.m_width % 4;
char* _temp = data;
for (int i = 0; i < header.m_height; i++)
{
for (int j = 0; j < header.m_width; j++)
{
_pixels[i * header.m_height + j].B = *(_temp++);
_pixels[i * header.m_height + j].G = *(_temp++);
_pixels[i * header.m_height + j].R = *(_temp++);
}
_temp += _padding;
}
return _pixels;
}
Chuyển dữ liệu từ mảng các Pixel vào data của 1 ảnh bitmap
char* convertPixelArrayToData(Pix* &pixels, BitMap &header)
{
int _padding = header.m_width % 4;
int _size = header.m_width * header.m_height * (header.m_bpp / 8) + _padding *
header.m_height;
char* _data = new char[_size];
char* _temp = _data;
for (int i = 0; i < header.m_height; i++)
{
for (int j = 0; j < header.m_width; j++)
{
*(_temp++) = pixels[i * header.m_height + j].B;
*(_temp++) = pixels[i * header.m_height + j].G;
*(_temp++) = pixels[i * header.m_height + j].R;
}
for (int k = 0; k < _padding; k++)
{
*(_temp++) = 0;
}
}
return _data;
}
2.1.Chuyển ảnh màu sang ảnh đa mức xám
Giải thích về thuật toán: Như đã tìm hiểu phần trên, ảnh bitmap sử dụng bảng màu RGB và dĩ nhiên
tuân theo luật phối màu cộng. Hay rõ hơn, để có được màu như ý trên mỗi điểm ảnh, thường dùng 8bits
để quy định cho mỗi kênh màu, và mỗi kênh màu với cường độ sáng thích hợp khi phối lại với nhau sẽ
cho ra màu như ý muốn.Vậy tổng cường độ sáng của 3 kênh chính là cường độ sáng tại điểm đó. Đây là ý
tưởng chính để chúng ta xây dựng thuật toán chuyển từ ảnh màu sang ảnh đa mức xám. Và dễ thấy,
đơn giản nhất. Chỉ cần lấy cường độ sáng của mỗi kênh cộng lại với nhau rồi chia 3 ta sẽ có kết quả
mong muốn.
Ix, y = ( Redx, y + Greenx, y + Bluex, y ) / 3
●
I(x, y): Là cường độ sáng tại điểm ảnh (x, y) của ảnh xám.
●
Red(x, y): Là giá trị của kênh màu Red(Đỏ) tại điểm ảnh (x, y) của ảnh màu(RGB).
●
Green(x, y): Là giá trị của kênh màu Green(Xanh lá cây) tại điểm ảnh (x, y) của ảnh màu(RGB).
●
Blue(x, y): Là giá trị của kênh màu Blue(Xanh lơ) tại điểm ảnh (x, y) của ảnh màu(RGB).
Tuy nhiên mặt khác theo khoa học đã chứng minh thì mắt người nhạy cảm hơn với thành phần màu
xanh lá cây và màu đỏ so với xanh da trời nên ta có công thức sau:
Ix, y = 0.3086 * Redx, y + 0.6094 * Greenx, y + 0.0820 * Bluex, y
Ix, y = 0.299 * Redx, y + 0.587 * Greenx, y + 0.114 * Bluex, y
Hoặc cũng có thể sử dụng công thức:
Ix, y = ( 2 * Redx, y + 5 * Greenx, y + 1 * Bluex, y ) / 8
(Thực hiện phép nhân trong miền số nguyên thì nhanh hơn rất nhiều trong miền số thực)
Tuỳ theo yêu cầu nên có thể linh hoạt trong việc sử dụng các công thức trên.
Hàm chuyển ảnh màu sang đa mức xám:
void rgb2gray()
{
for (int i = 0; i < size; i++)//Duyệt tất cả các điểm ảnh
{
int dosang = (pixels[i].R + pixels[i].G + pixels[i].B) / 3;//Để đẩy nhanh tốc độ tính toán và
mức độ của chương trình là đơn giản nên tôi sử dụng công thức này, có thể dùng công thức khác tùy vào
yêu cầu.
pixels[i].R = pixels[i].G = pixels[i].B = dosang;// luật phối màu cộng: 3 kênh màu R, G, B có
giá trị bằng nhau sẽ cho ra màu xám
}
}
Hình ảnh minh họa
Ảnh minh họa được tạo từ phần mềm Paint trên Win10 và save lại ở định dạng 24bits bitmap
Ảnh màu 24bits
Ảnh sau khi xử lý
2.2.Phân ngưỡng ảnh(Nhị phân hóa)
Là quá trình biến đổi một ảnh đa mức xám thành ảnh chỉ còn 2 mức là trắng và đen.
Tôi gọi giá trị cường độ sáng tại một điểm ảnh là I(x,y) .
INP(x,y) là cường độ sáng của điểm ảnh trên ảnh nhị phân .
(Với 0 < x < image.width) và (0 < y < image.height).
Để biến đổi ảnh xám thành ảnh nhị phân. Ta so sánh giá trị cường độ sáng của điểm ảnh với một
ngưỡng nhị phân T.
Nếu I(x,y) > T thì INP(x, y) = 0 (0).
Nếu I(x,y) > T thì INP(x, y) = 255 (1).
Hàm phân ngưỡng
void phannguong()
{
for (int i = 0; i < size; i++)//Duyệt tất cả các điểm ảnh
{
int dosang = pixels[i].R;//lấy ra giá trị của mỗi điểm
if(dosang<=t)//Nếu giá trị bé hơn hoặc bằng ngưỡng T
{
pixels[i].R = pixels[i].G = pixels[i].B =0;//Thay đổi giá trị tại các điểm ảnh đó thành
0
}
if(dosang>t) //Nếu giá trị lớn hơn ngưỡng T {
pixels[i].R = pixels[i].G = pixels[i].B =255; ;//Thay đổi giá trị tại các điểm ảnh đó
thành 255
}
}
}