Tìm hiểu và khảo sát ứng dụng của kỹ thuật làm mảnh đối tượng ảnh nhị phân - Pdf 29


1
Bài tập lớn xử lý ảnh

( Nhóm tin 2-K49 : Hoàng Tuấn Khánh & Hoàng Thanh Tùng )
Giới thiệu qua đề tài

Phần I : Kiến thức cơ bản

Phần II : Áp dụng một số thuật toán

Phần III : Ứng dụng trong hệ thống nhận dạng mẫu

Giới thiệu qua đề tài
Đề tài
Đề 23: Tìm hiểu và khảo sát ứng dụng của kỹ thuật làm mảnh đối tượng ảnh nhị
phân
Giáo viên hướng dẫn: Nguyễn Thị Hoàng Lan
Nhóm sinh viên thực hiện : Hoàng
Tuấn Khánh
Hoàng
Thanh Tùng
Lời nói đầu

Xử lý ảnh là một môn học có rất nhiều ứng dụng trong thực tế. Để có thể vận dụng các
kiến thức được học trên lớp, chúng em phải hoàn thành một project nhất định. Chúng em
đã chọn đề tài "Tìm hiểu và khảo sát ứng dụng của kỹ thuật làm mảnh đối tượng
ảnh nhị phân" vì thấy đây là một đề tài rất hay, đặc biệt có liên quan đến vấn đề phục
hồi và nhận dạng, một kỹ thuật rất được quan tâm bây giờ.
Chính nhờ quá trình nỗ lực làm bài tập lớn, chúng em đã xây dựng được những mô đun
và tích luỹ được những kinh nghiệm hết sức quý báu. Và vì vậy nên do nhận thấy sự liên


Chương trình cuối cùng được quyết định viết bằng Java, giao diện đơn giản dễ dùng, và
đã chạy thành công một số giải thuật cốt yếu. Chương trình có các tính năng như dò biên,
làm mảnh ảnh nhị phân, biểu đồ histogram, biến đổi ảnh màu và xám, biến đổi furier và
cosin rời rạc, ngoài ra đang phát triển thêm bộ công cụ cho phép vẽ và thao tác trực tiếp
lên ảnh nhờ các phép toán vị trí trên ma trận, nhưng hiện tại chúng em chưa có thời gian
để thực hiện.
Chúng em xin giới thiệu qua giao diện của chương trình :
3
Kiến thức cơ bản
Xử lý ảnh là môn khoa học còn mới mẻ nhưng ứng dụng khá nhiều trong thực tế, đặc biệt
là hệ thống nhận dạng. Một hệ thống xử lý ảnh cơ bản thực hiện việc thu nhận ảnh + phân
tích ảnh + trích chọn đặc tính + lưu trữ để phục vụ cho các mục đích khác nhau. Vì ảnh
trong tự nhiên có lượng thông tin rất lớn, do đó ta phải biết lưu trữ sao cho tốn ít dung
lượng mà vẫn đảm bảo ảnh lưu trữ được những đặc tính cơ bản nhất. Muốn đọc được
ảnh, trước tiên đòi hỏi bạn phải có kiến thức căn bản về C, và cách tổ chức file. Bạn cần
phải biết đọc các header để biết dạng ảnh, đọc các pixel ảnh và chuyển đổi chúng thành
dữ liệu thích hợp để thực hiện việc xử lý. Chẳng hạn việc đọc ảnh màu bạn phải biết đổi
màu ra mức xám và sau khi thực hiện xử lý bạn đổi ngược lại, điều này cần một sự phân
ngưỡng chẳng hạn như ma trận dither. Hay việc phóng to thu nhỏ ảnh chỉ đơn thuần là ta
chèn thêm hàng và cột hoặc bỏ đi theo cách nội suy, vì thế khi phóng to hết cỡ ảnh bạn
thấy những ô vuông có duy nhất một mầu, là vì các điểm ảnh giống nhau tập hợp lại do
phép chèn. Ví dụ một ảnh : 1 2 3
4 5 6

Trích chọn đặc tính

Lấy biên hoặc vùng ảnh phục vụ cho các mục đích nhận dạng, trước khi trích chọn đặc
tính cần cải thiện ảnh, đó là các phép xử lý như lọc, tăng độ tương phản Lưu trữ

Ảnh được lưu trữ dưới các mảng, khi hiển thị thì dùng thuật toán cắt tỉa để hiện vùng ảnh
xuất hiện, giải thuật cohen dùng 4 bít từ phải sang trái để mã hoá cho vị trí trái phải dưới
trên. Để giảm dung lượng thường dùng cách lưu trữ dưới dạng nén, chẳng hạn định dạng
gif cho việc mã hoá khối lượng màu lớn, jpeg cho đồ hoạ kỹ xảo, và nén không mất
thông tin như huffman
Áp dụng một số thuật toán Biến đổi từ ảnh đa mức xám sang ảnh màu

Biến đổi Cosin rời rạc

Biểu đồ xám Histogram và co giãn biểu đồ làm tăng độ tương phản ảnh:

Phép lọc số để cải thiện ảnh

Phát hiện và tách biên

Ứng dụng của việc phát hiện biên ảnh

Kỹ thuật lọc Wiener


vào một màu nào đó thì nó sẽ nhanh chóng bão hoà

Còn nếu muốn biến ảnh màu thành ảnh đa mức xám để phục vụ cho việc xử lý ảnh bạn
làm như sau: một màu 32 bit chia làm 8 cụm hexa, bạn dùng các mặt nạ và phép dịch bit
để tính giá trị 2 cụm một tương ứng với các màu, sau đó lấy giá trị trung bình chuyển
sang mức xám. Lớp này có thể thực hiện như sau:

//lấy màu đỏ từ pixel

public class RGB {
public static int getRed(int pix){
return (pix&0x00ff0000)>>16;
}

//lấy màu lục từ pixel

public static int getGreen(int pix){
return (pix&0x0000ff00)>>8;
}

//lấy màu lam từ pixel

public static int getBlue(int pix){
return pix&0x000000ff;
}

//tính trung bình

public static int getColorAverage(int pixel) {
int red = pixel & 0x00ff0000;

//lớp DCT decrete cosin transform

public class CompressDCT extends Component {
public CompressDCT(){
int [][]F=new int [DrawImage.width][DrawImage.height];
//DrawImage là đối tượng ma trận ảnh
for (int i=0;i<DrawImage.height;i++){
for (int k=0;k<DrawImage.width;k++){

F[k][i]=RGB.getColorAverage(DrawImage.pixels[i*DrawImage.width+k]);
}
}

F=compute(F); //phương thức tính ra biến đổi

for (int i=0;i<DrawImage.height;i++){
for (int k=0;k<DrawImage.width;k++){
DrawImage.pixels[i*DrawImage.width+k]=F[k][i];
}
}

ProcessImageView.image=createImage
(new
MemoryImageSource(DrawImage.width,DrawImage.height,DrawImage.pixels,0,D
rawImage.width));
}

public int[][] compute(int f[][]){

7

for (int n=0;n<N;n++){
if (k==0) tg=(float) (tg +1/Math.sqrt(2)* x[n] *
Math.cos((2 * n + 1) / (2 * N)));
else
tg=(float) (tg + x[n] * Math.cos((2 * n + 1) / (2 *
N)));
}
X[k]=(float) (Math.sqrt(2 / N) * tg);
}
tg=0;
for (int n=0;n<N;n++ ){
for (int k=0;k<N;k++){
if (k==0) tg=(float) (tg +1/Math.sqrt(2)* X[k] *
Math.cos((2*n+1)/2/N));
else
tg=(float) (tg + X[k] * Math.cos((2*n+1)/2/N));
}
x[n]=(int) (Math.sqrt(2 / N) + tg);
}
return x;
}
}

Biểu đồ xám Histogram và co giãn biểu đồ làm tăng độ tương phản ảnh:

8 Việc tính ra biểu đồ histogram thực chất là tính tần xuất xuất hiện các điểm có mức xám
từ 0 đến một ngưỡng nào đó, tối đa là 255. Lớp tính Histogram như sau:

pix[i]*scale));
if (pix[i]!=0) System.out.println("i="+i+" "+pix[i]); }

}
// sự kiện khi di chuột

9

class MouseMoved extends java.awt.event.MouseMotionAdapter{
public void mouseMoved(MouseEvent event){
if (event.getX()>19 && event.getX()<256+20){
lab.setText("Point:"+(event.getX()-20)+"
Value:"+pix[event.getX()-20]);
}
}
}
bạn muốn hiệu ứng xảy ra khi co giãn biểu đồ thì có thể dùng một thanh slider để gán sự
kiện cho nó
Lớp co giãn biểu đồ xám

public class ExpandHistogram {
public int[] transform(int [] pixel,float lmax,float lmin){
int max=0;
int min=255;
for (int i=0 ;i<pixel.length;i++){
pixel[i]=RGB.getColorAverage(pixel[i]);
if (pixel[i]>max)max=pixel[i];

result[i][j]=0;
for(int I=-size; I<=size; I++)
for(int J=-size; J<=size; J++)
result[i][j]+=(short)((F[i+I][j+J]*h[I+1][J+1]));
result[i][j]=(short)(result[i][j]/fact);
if (result[i][j]<min) min=result[i][j];
if (result[i][j]>max) max=result[i][j];

}
}
if (min<0) {
if (max-min<256){//khi gia tri chua vuot khoang 255
for (int i=1;i<DrawImage.height-1;i++){
for (int k=1;k<DrawImage.width-1;k++){
DrawImage.pixels[i*DrawImage.width+k]=result[i][k]
- min;
}
}
}else {//ca max va min khong chap nhan duoc
short tg=(short) (max - min);
for (int i=1;i<DrawImage.height-1;i++){
for (int k=1;k<DrawImage.width-1;k++){

11
DrawImage.pixels[i*DrawImage.width+k]=
(result[i][k] - min) * 255 / tg;
// if (
DrawImage.pixels[i*DrawImage.width+k]>=255) va++;
}
}

ProcessImageView.drawImage.paintImage();
Phát hiện và tách biên
Sobel Method

Laplacian Method

Giải thuật viết bằng Java:

*********************************************************

Ảnh gốc : 12 Ảnh tách biên theo phương pháp Sobel:
Ảnh tách biên theo phương pháp Laplacian:
Đặc tính biên ảnh là một vấn đề cơ bản và rất quan trọng trong vấn đề xử lý ảnh. Cạnh
của ảnh là những vùng ảnh với độ tương phản rất rõ - một đột biến về cường độ sáng từ
điểm ảnh này đến điểm ảnh khác. Dò biên ảnh có một ý nghĩa quan trọng trong việc làm
giảm số lượng dữ liệu và lọc đi những thông tin dư thừa, trong khi đó giữ lại những đặc
tính cấu trúc quan trọng của bức ảnh. Có nhiều cách để thực hiện vấn đề này. Tuy nhiên
các phương pháp khác nhau có thể nhóm vào 2 mục chính, gradient và Laplacian.

cũng như việc tính xấp xỉ nó áp dụng cho một bức ảnh 2 chiều. Toán tử Sobel thực hiện
một gradient không gian 2 chiều để tính toán một bức ảnh. Điển hình là nó sử dụng một

14
giá trị tuyệt đối xấp xỉ cho mỗi điểm ảnh từ một bức ảnh đa mức xám đầu vào. Phương
pháp dò sử dụng một mặt nạ tích chập kích thước 3x3, một cái là tính theo hướng x và
một cái tính theo hướng y. Mặt nạ trượt trên ma trận ảnh và tính ra giá trị tương ứng mỗi
điểm trung tâm. Mặt nạ Sobel cho dưới đây:
Công thức tính gradient là :

Và độ lớn của gradient có thể được tính xấp xỉ :

|G| = |Gx| + |Gy|

Sau đây là toàn bộ chương trình giải thuật được viết bằng C hoặc có thể dùng C++ cũng
ổn.

#include (stdio.h)
#include (stdlib.h)
#include (math.h)
#include (alloc.h)

/* STRUCTURES */
typedef struct {int rows; int cols; unsigned char* data;} sImage;


/* 3x3 GY Sobel mask. Ref: www.cee.hw.ac.uk/hipr/html/Sobel.html */
GY[0][0] = 1; GY[0][1] = 2; GY[0][2] = 1;
GY[1][0] = 0; GY[1][1] = 0; GY[1][2] = 0;
GY[2][0] = -1; GY[2][1] = -2; GY[2][2] = -1;

if(argc < 2) {
printf("Usage: %s bmpInput.bmp\n", argv[0]);
exit(0);
};
printf("Reading filename %s\n", argv[1]);

/* DECLARE INPUT & OUTPUT FILES */
bmpInput = fopen(argv[1], "rb");
bmpOutput = fopen("edgeSob.bmp", "wb");

/* SET POINTER TO BEGINNING OF FILE */
fseek(bmpInput, 0L, SEEK_END);

/* GET INPUT BMP DATA */
fileSize = getImageInfo(bmpInput, 2, 4);
originalImage.cols = (int)getImageInfo(bmpInput, 18, 4);
originalImage.rows = (int)getImageInfo(bmpInput, 22, 4);
edgeImage.rows = originalImage.rows;
edgeImage.cols = originalImage.cols;

/* PRINT DATA TO SCREEN */
printf("Width: %d\n", originalImage.cols);
printf("Height: %d\n", originalImage.rows);
printf("File size: %lu\n", fileSize);

*/
for(row=0; row<=originalImage.rows-1; row++) {
for(col=0; col<=originalImage.cols-1; col++) {
fread(pChar, sizeof(char), 1, bmpInput);
*(originalImage.data + row*originalImage.cols + col) =
*pChar;
}
}

/*
Sobel ALGORITHM STARTS HERE
*/
for(Y=0; Y<=(originalImage.rows-1); Y++) {
for(X=0; X<=(originalImage.cols-1); X++) {
sumX = 0;
sumY = 0;

/* image boundaries */
if(Y==0 || Y==originalImage.rows-1)
SUM = 0;
else if(X==0 || X==originalImage.cols-1)
SUM = 0;

/* Convolution starts here */
else {

/* X GRADIENT APPROXIMATION */
for(I=-1; I<=1; I++) {
for(J=-1; J<=1; J++) {
sumX = sumX + (int)( (*(originalImage.data + X + I

}

printf("See edgeSob.bmp for results\n");
fclose(bmpInput);
fclose(bmpOutput);
farfree(edgeImage.data); /* Finished with edgeImage.data */
farfree(originalImage.data); /* Finished with originalImage.data */
return 0;
}

/* GET IMAGE INFO SUBPROGRAM */
long getImageInfo(FILE* inputFile, long offset, int numberOfChars)
{
unsigned char *ptrC;
long value = 0L;
unsigned char dummy;
int i;

dummy = '0';
ptrC = &dummy;

fseek(inputFile, offset, SEEK_SET);

for(i=1; i<=numberOfChars; i++)
{
fread(ptrC, sizeof(char), 1, inputFile);
/* calculate value based on adding bytes */
value = (long)(value + (*ptrC)*(pow(256, (i-1))));
}
return(value);

unsigned char dummy;
int i;

dummy = '0';
ptrC = &dummy;

fseek(inputFile, 54L, SEEK_SET);
fseek(outputFile, 54L, SEEK_SET);

for(i=0; i<=(4*nColors); i++) /* there are (4*nColors) bytesin color
table */
{
fread(ptrC, sizeof(char), 1, inputFile);
fwrite(ptrC, sizeof(char), 1, outputFile);
}

}

Mặt nạ được trượt trên mỗi vùng của bức ảnh, thay đổi giá trị của điểm ảnh rồi trượt sang
phải cho đến khi hết hàng. Rồi nó lại thực hiện với hàng tiếp theo. Chẳng hạn: 19 Laplacian: Phương pháp này sử dụng một mặt nạ kích thước 5x5 để tính xấp xỉ ra bức ảnh dẫn xuất,
khác với Sobel nó tính trực tiếp luôn với hướng x và y. Tuy nhiên nó rất nhậy cảm với

unsigned long vectorSize;
unsigned long fileSize;
int MASK[5][5];
unsigned char *pChar, someChar;
unsigned int row, col;

someChar = '0'; pChar = &someChar;

/* 5x5 Laplace mask. Ref: Myler Handbook p. 135 */
MASK[0][0] = -1; MASK[0][1] = -1; MASK[0][2] = -1; MASK[0][3] = -1;
MASK[0][4] = -1;
MASK[1][0] = -1; MASK[1][1] = -1; MASK[1][2] = -1; MASK[1][3] = -1;
MASK[1][4] = -1;
MASK[2][0] = -1; MASK[2][1] = -1; MASK[2][2] = 24; MASK[2][3] = -1;
MASK[2][4] = -1;
MASK[3][0] = -1; MASK[3][1] = -1; MASK[3][2] = -1; MASK[3][3] = -1;
MASK[3][4] = -1;
MASK[4][0] = -1; MASK[4][1] = -1; MASK[4][2] = -1; MASK[4][3] = -1;
MASK[4][4] = -1;

if(argc < 2) {
printf("Usage: %s bmpInput.bmp\n", argv[0]);
exit(0);
};
printf("Reading filename %s\n", argv[1]);

/* open files for reading and writing to */
bmpInput = fopen(argv[1], "rb");
bmpOutput = fopen("edgeLap.bmp", "wb");


if(originalImage.data == NULL) {
printf("Failed to malloc originalImage.data\n");
exit(0);
}
printf("%lu bytes malloc'ed for originalImage.datt\n", vectorSize);

copyImageInfo(bmpInput, bmpOutput);
copyColorTable(bmpInput, bmpOutput, nColors);
fseek(bmpInput, (14+40+4*nColors), SEEK_SET);
fseek(bmpOutput, (14+40+4*nColors), SEEK_SET);

/* Read input.bmp and store it's raster data into originalImage.data
*/
for(row=0; row<=originalImage.rows-1; row++) {
for(col=0; col<=originalImage.cols-1; col++) {
fread(pChar, sizeof(char), 1, bmpInput);
*(originalImage.data + row*originalImage.cols + col) =
*pChar;
}
}

for(Y=0; Y<=(originalImage.rows-1); Y++) {
for(X=0; X<=(originalImage.cols-1); X++) {
SUM = 0;

/* image boundaries */
if(Y==0 || Y==1 || Y==originalImage.rows-2 ||
Y==originalImage.rows-1)
SUM = 0;
else if(X==0 || X==1 || X==originalImage.cols-2 ||

farfree(originalImage.data); /* Finished with originalImage.data */
return 0;
}

/* GET IMAGE INFO SUBPROGRAM */
long getImageInfo(FILE* inputFile, long offset, int numberOfChars)
{
unsigned char *ptrC;
long value = 0L;
unsigned char dummy;
int i;

dummy = '0';
ptrC = &dummy;

fseek(inputFile, offset, SEEK_SET);

for(i=1; i<=numberOfChars; i++)
{
fread(ptrC, sizeof(char), 1, inputFile);
/* calculate value based on adding bytes */
value = (long)(value + (*ptrC)*(pow(256, (i-1))));
}
return(value);

} /* end of getImageInfo */

/* COPIES HEADER AND INFO HEADER */
void copyImageInfo(FILE* inputFile, FILE* outputFile)
{

fseek(inputFile, 54L, SEEK_SET);
fseek(outputFile, 54L, SEEK_SET);

for(i=0; i<=(4*nColors); i++) /* there are (4*nColors) bytesin color
table */
{
fread(ptrC, sizeof(char), 1, inputFile);
fwrite(ptrC, sizeof(char), 1, outputFile);
}

}

Giải thích rõ hơn và cài đặt lại thuật toán bằng Java:
Phương pháp Sobel
Phương pháp Laplacian
Phương pháp dò biên Canny Ảnh được làm nổi biên : 24 Việc phát hiện biên thực chất là lấy những điểm ảnh có sự biến thiên về cường độ sáng
hay mức xám. Ta dùng ma trận lọc, thường dùng ma trận Sobel theo hướng x và y hoặc
dùng laplace, dùng laplace thì bị ảnh hưởng bởi nhiễu hơn, sau khi làm nổi biên, ta có thể
tính hướng của gradien theo công thức tan(phi) = Gy/Gx, dựa vào góc này để biết hướng
của gradien, từ đó với mỗi điểm trên biên sẽ được hiện khi 2 điểm lân cận theo hướng
đạo hàm của nó đều nhỏ hơn nó. Phương pháp dò biên canny sử dụng một ma trận nhân

int SUM = 0;

/* biên ảnh */
if(i==0 || i==1 || i==DrawImage.height-2 ||
i==DrawImage.height-1)
SUM = 0;
else if(j==0 || j==1 || j==DrawImage.height-2 ||
j==DrawImage.height-1)
SUM = 0;

else {

for(int I=-1; I<=1; I++)
for(int J=-1; J<=1; J++) {

sumX+=(int)(F[i+I][j+J]*GX[I+1][J+1]);
sumY+=(int)(F[i+I][j+J]*GY[I+1][J+1]);
} SUM = (int)(Math.sqrt(sumX*sumX + sumY*sumY));

}

if(SUM>255) SUM=255;
if(SUM<0) SUM=0;


Nhờ tải bản gốc

Tài liệu, ebook tham khảo khác

Music ♫

Copyright: Tài liệu đại học © DMCA.com Protection Status