Top Banner
A.1. Giới thiệu OpenCV, như đã nói là một thư viện rất đồ sộ và được tập thể các tác giả chia làm 4 phần chính: Mã HTML: (Click Here to Select All) CxCore: Chứa các cấu trúc cơ bản như điểm, đường, dãy, mặt, ma trận… và các thao tác cấp thấp liên quan. CV: Chứa hầu hết các thao tác liên quan đến việc xử lý ảnh ở cấp thấp như lọc ảnh, trích biên, phân vùng, tìm contour, biến đổi Fourier… HighGUI: Các thao tác lên những file ảnh và file Video như đọc ảnh, hiển thị ảnh, chuyển đổi định dạng… CvCam: Làm việc với Camera. Vì lý do phạm vi của luận văn này chỉ làm việc với ảnh nên chúng tôi không trình bày CvCam ở đây. A.2. Sử dụng OpenCV Tất cả các cấu trúc và các hàm của OpenCV đều được đặt tên theo cách quy định sau: Tất các các từ khóa, các hằng đều được viết hoa toàn bộ, bắt đầu bởi tiếp đầu ngữ “CV”, các từ cách nhau bởi dấu gạch dưới (_). Ví dụ: CV_SEQ_KIND_GRAPH. Tên của hàm và cấu trúc được viết hoa chữ cái đầu mỗi chữ có nghĩa và sử dụng tiếp đầu ngữ “cv” cho hàm và “Cv” cho cấu trúc. Ví dụ: hàm cvFindContours và cấu trúc CvPoint. Tên của một hàm có cấu trúc như sau: cv <hành động> <đối tượng> <kiểu> o <hành động>: Thao tác nào được sử dụng. Ví dụ như –Set–, –Convert–, –Create–. o <đối tượng>: Chỉ định đối tượng mà hành động hướng tới. Ví dụ như – FindContours, -ApproxPoly • Nếu đối tượng có tên dài hơn 1 chữ thì các chữ được viết hoa ký tự đầu. Ví dụ: -MatchContourTree. • Một số hàm chỉ có <hành động>, hoặc chỉ có <đối tượng>. Ví dụ: cvUnDistort, cvAcc. o <kiểu>: là một tham số không bắt buộc, xác định kiểu tác động của hàm. Ví dụ: cvFindExtrinsicCameraParams_64d. Ở các hàm thuộc HighGUI, tiếp đầu ngữ sẽ là “cvv” thay cho “cv”. Tiếp theo, chúng tôi sẽ giới thiệu vắn tắt một số tính năng của 3 phần cơ bản cấu thành nên OpenCV là CxCore, CV và HighGUI. Trong mỗi phần này có vô số các hàm bên trong mà chúng tôi ở đây không thể nào liệt kê ra hết (có thể xem trong tài liệu hướng dẫn của Intel ). A.2.1. CxCore CxCore chứa đựng rất nhiều các thành phần cơ bản cấu thành nên toàn bộ OpenCV. CxCore bao gồm các cấu trúc dữ liệu cơ bản, các thao tác lên array, các cấu trúc động, các hàm vẽ, các hàm tác động lên dữ liệu, các hàm quản lý lỗi và sự kiện và một số hàm cần thiết khác. Số lượng chứa đựng trong CxCore là rất lớn và chúng tôi chỉ trích ra đây một số ít những cấu trúc và hàm cơ bản nhất của OpenCV. 1
25
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Xu ly anh

A.1. Giới thiệuOpenCV, như đã nói là một thư viện rất đồ sộ và được tập thể các tác giả chia làm 4 phần chính: Mã HTML: (Click Here to Select All)

CxCore: Chứa các cấu trúc cơ bản như điểm, đường, dãy, mặt, ma trận… và các thao tác cấp thấp liên quan.

CV: Chứa hầu hết các thao tác liên quan đến việc xử lý ảnh ở cấp thấp như lọc ảnh, trích biên, phân vùng, tìm contour, biến đổi Fourier…

HighGUI: Các thao tác lên những file ảnh và file Video như đọc ảnh, hiển thị ảnh, chuyển đổi định dạng…

CvCam: Làm việc với Camera. Vì lý do phạm vi của luận văn này chỉ làm việc với ảnh nên chúng tôi không trình bày CvCam ở đây.

A.2. Sử dụng OpenCVTất cả các cấu trúc và các hàm của OpenCV đều được đặt tên theo cách quy định sau:

Tất các các từ khóa, các hằng đều được viết hoa toàn bộ, bắt đầu bởi tiếp đầu ngữ “CV”, các từ cách nhau bởi dấu gạch dưới (_). Ví dụ: CV_SEQ_KIND_GRAPH.Tên của hàm và cấu trúc được viết hoa chữ cái đầu mỗi chữ có nghĩa và sử dụng tiếp đầu ngữ “cv” cho hàm và “Cv” cho cấu trúc. Ví dụ: hàm cvFindContours và cấu trúc CvPoint.Tên của một hàm có cấu trúc như sau:cv <hành động> <đối tượng> <kiểu>o <hành động>: Thao tác nào được sử dụng. Ví dụ như –Set–, –Convert–, –Create–.o <đối tượng>: Chỉ định đối tượng mà hành động hướng tới. Ví dụ như –FindContours, -ApproxPoly• Nếu đối tượng có tên dài hơn 1 chữ thì các chữ được viết hoa ký tự đầu. Ví dụ: -MatchContourTree. • Một số hàm chỉ có <hành động>, hoặc chỉ có <đối tượng>. Ví dụ: cvUnDistort, cvAcc.o <kiểu>: là một tham số không bắt buộc, xác định kiểu tác động của hàm. Ví dụ: cvFindExtrinsicCameraParams_64d.Ở các hàm thuộc HighGUI, tiếp đầu ngữ sẽ là “cvv” thay cho “cv”.Tiếp theo, chúng tôi sẽ giới thiệu vắn tắt một số tính năng của 3 phần cơ bản cấu thành nên OpenCV là CxCore, CV và HighGUI. Trong mỗi phần này có vô số các hàm bên trong mà chúng tôi ở đây không thể nào liệt kê ra hết (có thể xem trong tài liệu hướng dẫn của Intel ).

A.2.1. CxCoreCxCore chứa đựng rất nhiều các thành phần cơ bản cấu thành nên toàn bộ OpenCV. CxCore bao gồm các cấu trúc dữ liệu cơ bản, các thao tác lên array, các cấu trúc động, các hàm vẽ, các hàm tác động lên dữ liệu, các hàm quản lý lỗi và sự kiện và một số hàm cần thiết khác.Số lượng chứa đựng trong CxCore là rất lớn và chúng tôi chỉ trích ra đây một số ít những cấu trúc và hàm cơ bản nhất của OpenCV.

Các cấu trúc quan trọngCvPoint: Chứa cấu trúc tọa độ của một điểm ảnh:Code: (Click Here to Select All)

typedef struct CvPoint

{

int x; /* x-coordinate, usually zero-based */

int y; /* y-coordinate, usually zero-based */

}

1

Page 2: Xu ly anh

CvPoint;

/* the constructor function */

inline CvPoint cvPoint( int x, int y );

/* conversion from CvPoint2D32f */

inline CvPoint cvPointFrom32f( CvPoint2D32f point );

Cùng họ với CvPoint còn có: CvPoint2D32f chứa tọa độ thực, CvPoint3D32f, chứa tọa độ thực của điểm trong không gian. Ta để ý các cấu trúc này theo đúng cách đặt tên đã mô tả. Ngoài ra còn có CvPoint2D64f, CvPoint3D64f.

CvSize: Chứa thông tin để lưu lại kích thước.Code: (Click Here to Select All)

typedef struct CvSize

{

int width; /* width of the rectangle */

int height; /* height of the rectangle */

}

CvSize;

/* the constructor function */

inline CvSize cvSize( int width, int height );

Tương tự như CvPoint, cùng họ với CvSize cũng có các cấu trúc CvSize khác.

CvRect: Hình chữ nhậtCode: (Click Here to Select All)

typedef struct CvRect

{

int x; /* x-coordinate of the left-most rectangle corner[s] */

int y; /* y-coordinate of the top-most or bottom-most

rectangle corner[s] */

int width; /* width of the rectangle */

int height; /* height of the rectangle */

2

Page 3: Xu ly anh

}

CvRect;

/* the constructor function */

inline CvRect cvRect( int x, int y, int width, int height );

CvMat: ma trận. Một cấu trúc được sử dụng khá nhiều.Code: (Click Here to Select All)

typedef struct CvMat

{

int type; /* CvMat signature (CV_MAT_MAGIC_VAL), element type and flags */

int step; /* full row length in bytes */

int* refcount; /* underlying data reference counter */

union

{

uchar* ptr;

short* s;

int* i;

float* fl;

double* db;

} data; /* data pointers */

#ifdef __cplusplus

union

{

int rows;

int height;

};

3

Page 4: Xu ly anh

union

{

int cols;

int width;

};

#else

int rows; /* number of rows */

int cols; /* number of columns */

#endif

} CvMat;

IplImage: Cấu trúc quan trọng nhất. Chứa đựng toàn bộ ảnh. Code: (Click Here to Select All)

typedef struct _IplImage

{

int nSize; /* sizeof(IplImage) */

int ID; /* version (=0)*/

int nChannels; /* Most of OpenCV functions support 1,2,3 or 4 channels */

int alphaChannel; /* ignored by OpenCV */

int depth; /* pixel depth in bits: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U,

IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F are supported */

char colorModel[4]; /* ignored by OpenCV */

char channelSeq[4]; /* ditto */

int dataOrder; /* 0 - interleaved color channels, 1 - separate color channels.

cvCreateImage can only create interleaved images */

int origin; /* 0 - top-left origin,

4

Page 5: Xu ly anh

1 - bottom-left origin (Windows bitmaps style) */

int align; /* Alignment of image rows (4 or 8).

OpenCV ignores it and uses widthStep instead */

int width; /* image width in pixels */

int height; /* image height in pixels */

struct _IplROI *roi;/* image ROI. when it is not NULL, this specifies image region to process */

struct _IplImage *maskROI; /* must be NULL in OpenCV */

void *imageId; /* ditto */

struct _IplTileInfo *tileInfo; /* ditto */

int imageSize; /* image data size in bytes

(=image->height*image->widthStep

in case of interleaved data)*/

char *imageData; /* pointer to aligned image data */

int widthStep; /* size of aligned image row in bytes */

int BorderMode[4]; /* border completion mode, ignored by OpenCV */

int BorderConst[4]; /* ditto */

char *imageDataOrigin; /* pointer to a very origin of image data

(not necessarily aligned) -

it is needed for correct image deallocation */

}

IplImage;

CvSeq: Cấu trúc quan trọng cuối cùng mà chúng tôi nêu ra ở đây. Cấu trúc này chứa một danh sách các dữ liệu. Đây có thể xem là một ArrayList trong OpenCV.Code: (Click Here to Select All)

#define CV_SEQUENCE_FIELDS() \

int flags; /* micsellaneous flags */ \

int header_size; /* size of sequence header */ \

struct CvSeq* h_prev; /* previous sequence */ \

struct CvSeq* h_next; /* next sequence */ \

5

Page 6: Xu ly anh

struct CvSeq* v_prev; /* 2nd previous sequence */ \

struct CvSeq* v_next; /* 2nd next sequence */ \

int total; /* total number of elements */ \

int elem_size;/* size of sequence element in bytes */ \

char* block_max;/* maximal bound of the last block */ \

char* ptr; /* current write pointer */ \

int delta_elems; /* how many elements allocated when the sequence grows (sequence granularity) */ \

CvMemStorage* storage; /* where the seq is stored */ \

CvSeqBlock* free_blocks; /* free blocks list */ \

CvSeqBlock* first; /* pointer to the first sequence block */

typedef struct CvSeq

{

CV_SEQUENCE_FIELDS()

} CvSeq;

Các thao tác trên ArraySong song với các cấu trúc trên là một loạt các hàm cơ bản trên các Array (bao gồm ma trận, ảnh, và cả dãy), dưới đây chúng tôi sẽ trình bày các nhóm hàm cơ bản.Nhóm Create: Là những hàm khởi tạo các cấu trúc kể trên. Ví dụ như cvCreateImage, cvCreateMat. Mỗi hàm có các khai báo riêng, nhưng đều có cùng một dạng chức năng là khởi tạo ra một đối tượng mới. Nhóm tác động vào những phần tử của Array. Tiêu biểu là các hàm lấy dòng, lấy cột như cvGetRow, cvGetCol, cvGetDiag…Nhóm các hàm Copy và Fill. Ví dụ như cvCloneImage, cvCopy,…Các hàm thay đổi hình dạng. Ví dụ như cvRepeat, cvFlip,…Các thao tác số học. Ví dụ cvLUT, cvConvertScale…Các hàm thống kê. cvSum, cvAvg,…Các hàm đại số tuyến tính. Tiêu biểu là nhân ma trận, tích hữu hướng, tích vô hướng… Như cvDotProduct, cvMatMul…Các biến đổi rời rạc. Tiêu biểu là biến đổi Fourier rời rạc, Cosine rời rạc,… như cvDFT, cvDCT,…Các hàm tạo số ngẫu nhiên. cvRNG, cvRandArr…Ví dụ về tính tích 2 ma trận:Code: (Click Here to Select All)

double a[] = { 1, 2, 3, 4

5, 6, 7, 8,

9, 10, 11, 12 };

6

Page 7: Xu ly anh

double b[] = { 1, 5, 9,

2, 6, 10,

3, 7, 11,

4, 8, 12 };

double c[9];

CvMat Ma, Mb, Mc ;

cvInitMatHeader( &Ma, 3, 4, CV_64FC1, a );

cvInitMatHeader( &Mb, 4, 3, CV_64FC1, b );

cvInitMatHeader( &Mc, 3, 3, CV_64FC1, c );

cvMatMulAdd( &Ma, &Mb, 0, &Mc );

// c array now contains product of a(3x4) and b(4x3) matrices

Các thao tác trên dữ liệu độngOpenCV có một cách làm việc khá hay trên dữ liệu động là tạo ra một không gian làm việc riêng, gọi là storage và sau đó các thao tác khác sẽ tiến hành trên đó, như các thao tác trên CvSeg, trên CvArr,… Ở đây khá đơn giản, chúng tôi chỉ trình bày cấu trúc quan trọng nhất của nhóm này: MemStorageCode: (Click Here to Select All)

typedef struct CvMemStorage

{

struct CvMemBlock* bottom;/* first allocated block */

struct CvMemBlock* top; /* the current memory block - top of the stack */

struct CvMemStorage* parent; /* borrows new blocks from */

int block_size; /* block size */

int free_space; /* free space in the top block (in bytes) */

} CvMemStorage;

Hầu như MemStorage có mặt trong mọi hàm của OpenCV, từ các hàm tìm cạnh như Canny đến những hàm khác như cvFindContours… đều phải cần đến MemStorage. Nắm được MemStorage có thể gọi là nắm được linh hồn của OpenCV.

7

Page 8: Xu ly anh

Các hàm vẽTương tự như các thư viện khác, các hàm vẽ là những thành phần không thể thiếu, OpenCV cũng cung cấp khá nhiều hàm vẽ như cvLine, cvRectangle, cvCircle…

Ngoài ra, còn có các hàm, cấu trúc thao tác trên đồ thị như Tree, Graph… Tất cả những gì trong CxCore đều góp phần tạo nên bộ khung cho OpenCV.

A.2.2. CVNhóm CV cung cấp các hàm liên quan trực tiếp đến Computer Vision, trong đó tập trung ở các thao tác cấp thấp trên ảnh và camera. Phần này chia thành các nhóm lớn như sau:Nhóm xử lý ảnhBao gồm:Code: (Click Here to Select All)

Gradient, cạnh (edge) và góc: gồm các hàm như Canny, Sobel, Laplace, các hàm tìm góc…

Các hàm lấy mẫu, nội suy và biến đổi hình học: Các biến đổi Affine, biến đổi kích thước, …

Các bộ lọc: Các hàm chuyển đổi hệ màu, bộ lọc Median, bộ lọc Gaussian, Threshold…

Pyramid và ứng dụng: các hàm trên Pyramid như Pyramid Segmentation, Downsample hoặc Upsample trên ảnh…

Các hàm làm việc trên các thành phần liên thông: như tìm các component, tìm các đường viền (FindContour)…

Khảo sát moment: làm việc trên mọi thứ liên quan đến Moment.

Những biến đổi đặc biệt: Các biến đổi khác với Affine hay Canny, ví dụ như biến đổi Hough tìm đường thẳng, tìm đường tròn…

Làm việc với Histograms: cung cấp các hàm trên Histogram như lấy Histogram của một vùng, cân bằng Histogram…

Nhóm phân tích cấu trúcBao gồmCác xử lý trên Contour: bao gồm xấp xỉ Contour, tính diện tích Contour…Các tính toán hình học: tìm đường bao, hình bao, đa giác…Còn có nhiều nhóm khác nữa trong phần này như các hàm làm việc trên Camera, trên phân tích chuyển động của điểm ảnh, phân đoạn ảnh (segmentation)…, tuy nhiên chúng tôi không trình bày ra vì lý do không cần thiết. Phần tiếp theo chúng tôi sẽ trình bày thành phần quan trọng cuối cùng, HighGUI.

A.2.3. HighGUIHighGUI cung cấp các hàm để thao tác trực tiếp lên file ảnh và camera, trong đó phần làm việc với ảnh chia thành 2 nhóm chính là nhóm tác động lên giao diện và nhóm tác động lên ảnh.

Nhóm tác động lên giao diệnBao gồm:Các hàm làm việc với cửa sổ: gồm các hàm tạo cửa sổ, hủy cửa sổ, lấy Handle của một của sổ, thay đổi kích thước của một cửa sổ.Làm việc với mouse và bàn phím: Cung cấp một số hàm cơ bản xử lý những sự kiện tương ứng với mouse và bàn phím.Các hàm hiển thị ảnh lên cửa sổ: Ở đây chỉ có một hàm duy nhất: cvvShowImage.Ví dụ để hiển thị một ảnh lên một cửa sổ mới có title là “Source”, ta làm như sau:Code: (Click Here to Select All)

8

Page 9: Xu ly anh

IplImage *source;

source = cvvLoadImage(path); // load image

cvvNamedWindow(“Source”, 1 );

// hien thi anh len cua so vua tao

cvvShowImage(“Source”, img);

Nhóm tác động lên file ảnhBao gồm:cvLoadImage: đọc một ảnh vào cấu trúc IplImage. Các loại ảnh hỗ trợ hiện tại là:o Windows bitmaps - BMP, DIB; o JPEG files - JPEG, JPG, JPE; o Portable Network Graphics - PNG; o Portable image format - PBM, PGM, PPM; o Sun rasters - SR, RAS; o TIFF files - TIFF, TIF.cvSaveImage: Lưu một ảnh vào file, định dạng tùy thuộc vào phần mở rộng của tên file muốn lưu.

thưa các bác e là dân điện tử ,kì này làm đồ an tốt nghiệp nhưng do đăng kí giáo viên trễ nên bị sắp vào giáo viên hướng dẫn là thầy viễn thông,, thầy cho nhóm e 2 người làm dề tài nhận dạng biển số xe dùng công nghệ rfid + xử lý anh + quản lý dữ liệu trên pc, rfid thì bạn mình lo,mình lo xla,mình chưa học một môn nào về xử lý ảnh số có vài điều thắc mắc muốn tìm bác nào rành chỉ với .e đang làm đến phần tim biên của bàng số, ( em dung vc++ 2008 vầ thư viện openv , dến lúc tách biên thì thấy opencv có hỗ trợ 1 số tuật toán như Sobel,Laphace....)nhưng e ứng dụng không , Mong bác nào cho e 1 cái vd tach biên dùng cvSboel,cvSmooth,hoặc cvCanny,..... giúp với !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!include <stdlib.h> #include <stdio.h> #include <math.h> #include <string.h> #include <cv.h>#include <highgui.h>

int main() { IplImage* src = cvLoadImage("a12.jpg"); cvNamedWindow("sourceImage"); cvShowImage("sourceImage", src); IplImage*sobel=cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,1); IplImage*dst_x=cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_32F,1);cvCvtColor(src,sobel, CV_RGB2GRAY);cvSobel(sobel,dst_x,0,1,3);cvWaitKey(50000);}///////////////////////////// vi du

1. Adding Text to Image

Listing 1 below shows you how to add text to image. The result is shown in Fig.1

Listing 1: add_text.c1. #include <stdio.h>

9

Page 10: Xu ly anh

2. #include "cv.h"3. #include "highgui.h"4.  5. int main(int argc, char** argv)6. {7.     IplImage *img = cvLoadImage("2.jpg", CV_LOAD_IMAGE_COLOR);8.  9.     /* initialize font and add text */10.     CvFont font;11.     cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 1.0, 1.0, 0, 1, CV_AA);12.     cvPutText(img, "Hello

World!", cvPoint(10, 130), &font, cvScalar(255, 255, 255, 0));13.  14.     /* display the image */15.     cvNamedWindow("image", CV_WINDOW_AUTOSIZE);16.     cvShowImage("image", img);17.     cvWaitKey(0);18.     cvDestroyWindow("image");19.     cvReleaseImage( &img );20.  21.     return 0;22. }

The code above simply loads an image, setup font and add text, then displays the image. Consult OpenCV Reference for details of cvInitFont and cvPutText parameters. The result is shown in Fig.1 below.

Fig 1. The result image.

2. Drawing Shapes

Listing 2 below shows you how to draw some shapes. The result is shown in Figure 2.

Listing 2: shapes.c1. #include <stdio.h>2. #include "cv.h"3. #include "highgui.h"4.  5. int main(int argc, char** argv)6. {7.     /* create an image */8.     IplImage *img = cvCreateImage(cvSize(200, 100), IPL_DEPTH_8U, 3);9.    10.     /* draw a green line */11.     cvLine(img,                         /* the dest image */12.            cvPoint(10, 10),             /* start point */13.            cvPoint(150, 80),            /* end point */14.            cvScalar(0, 255, 0, 0),      /* the color; green */15.            1, 8, 0);                    /* thickness, line type, shift */

10

Page 11: Xu ly anh

16.    17.     /* draw a blue box */18.     cvRectangle(img,                    /* the dest image */19.                 cvPoint(20, 15),        /* top left point */20.                 cvPoint(100, 70),       /* bottom right point */21.                 cvScalar(255, 0, 0, 0), /* the color; blue */22.                 1, 8, 0);               /* thickness, line type, shift */23.    24.     /* draw a red circle */25.     cvCircle(img,                       /* the dest image */26.              cvPoint(110, 60), 35,      /* center point and radius */27.              cvScalar(0, 0, 255, 0),    /* the color; red */28.              1, 8, 0);                  /* thickness, line type, shift */29.    30.     /* display the image */31.     cvNamedWindow("img", CV_WINDOW_AUTOSIZE);32.     cvShowImage("img", img);33.     cvWaitKey(0);34.     cvDestroyWindow("img");35.     cvReleaseImage(&img);36.  37.     return 0;38. }

The code above draws a line, a rectangle and a circle. It is also possible to draw more complex shapes like ellipses and pollygons. Consult the OpenCV Reference for the functions. The result image is shown below

Fig 2. The result image.

3. Handling Keyboard Input

Listing 3 shows you a simple example of keyboard input handling. While there is no button or such in OpenCV GUI,you can employ input from keyboard to control your application.

Listing 3: keybd.c1. #include <stdio.h>2. #include "cv.h"3. #include "highgui.h"4.  5. int main(int argc, char** argv)6. {7.     IplImage *img0, *img1;8.     int       key;9.    10.     /* load an image */11.     img0 = cvLoadImage("2.jpg", CV_LOAD_IMAGE_COLOR);12.    13.     /* create a copy */14.     img1 = cvCloneImage(img0);15.    

11

Page 12: Xu ly anh

16.     /* display original image */17.     cvNamedWindow("image", CV_WINDOW_AUTOSIZE);18.     cvShowImage("image", img0);19.    20.     while(1) {21.         /* wait for keyboard input */22.         key = cvWaitKey(0);23.        24.         /* 'q' pressed, quit the program */25.         if (key == 'q') break;26.        27.         switch(key) {28.             /* '1' pressed, display the original image */29.             case '1':30.                 cvShowImage("image", img0);31.                 break;32.            33.             /* '2' pressed, flip the image horizontally */34.             case '2':35.                 cvFlip(img1, NULL, 1);36.                 cvShowImage("image", img1);37.                 break;38.            39.             /* '3' pressed, flip the image vertically */40.             case '3':41.                 cvFlip(img1, NULL, 0);42.                 cvShowImage("image", img1);43.                 break;44.         }45.     }46.    47.     /* free memory */48.     cvDestroyWindow("image");49.     cvReleaseImage(&img0);50.     cvReleaseImage(&img1);51.    52.     return 0;53. }

The code above loads an image and waits for user input. If the user press '1', it displays the original image. If the user press '2', it flips the image horizontally. If the user press '3', it flips the image vertically. And it quits when the user press 'q'.

4. Handling Mouse Events

Employing mouse for you OpenCV application is very useful, since you can select object, make selection, slicing image and such things.

To do this, you need to perform 2 things: Write a mouse handler function Register the function to a specified window

Listing 4 below shows you a simple example.

Listing 4: mouse.c1. #include <stdio.h>2. #include "cv.h"3. #include "highgui.h"4.  

12

Page 13: Xu ly anh

5. IplImage *img0, *img1;6.  7. void mouseHandler(int event, int x, int y, int flags, void *param)8. {9.     switch(event) {10.         /* left button down */11.         case CV_EVENT_LBUTTONDOWN:12.             fprintf(stdout, "Left button down (%d, %d).\n", x, y);13.             break;14.        15.         /* right button down */16.         case CV_EVENT_RBUTTONDOWN:17.             fprintf(stdout, "Right button down (%d, %d).\n", x, y);18.             break;19.        20.         /* mouse move */21.         case CV_EVENT_MOUSEMOVE:22.             /* draw a rectangle */23.             img1 = cvCloneImage(img0);24.             cvRectangle(img1,25.                         cvPoint(x - 15, y - 15),26.                         cvPoint(x + 15, y + 15),27.                         cvScalar(0, 0, 255, 0), 2, 8, 0);28.             cvShowImage("image", img1);29.             break;30.     }31. }32.  33. int main(int argc, char** argv)34. {35.     /* load an image */36.     img0 = cvLoadImage("2.jpg", CV_LOAD_IMAGE_COLOR);37.    38.     /* create new window and register mouse handler */39.     cvNamedWindow("image", CV_WINDOW_AUTOSIZE);40.     cvSetMouseCallback( "image", mouseHandler, NULL );41.    42.     /* display the image */43.     cvShowImage("image", img0);44.     cvWaitKey(0);45.    46.     cvDestroyWindow("image");47.     cvReleaseImage(&img0);48.     cvReleaseImage(&img1);49.    50.     return 0;51. }

//=====================================================================

Hi ể n th ị ả nh x ử lý b ằ ng OpenCV lên Picturebox c ủ a Visual Studio MFC

 02:11   Computer Vision and Application

Việc sử dụng OpenCV để lập trình cho xử lý ảnh và dùng chung cùng dao diện của MFC không phải là một chuyện đơn giản và thường có nhiều vướng mắc đối với những ai mới bước đầu làm quen. Trong bài viết này tôi sẽ hướng dẫn các newbi làm một bài thực hành đơn giản để gải tỏa các vướng mắc và làm quen dần với thư viện này. Bài thực hành đơn giản là load một ảnh rồi hiển thị ảnh đó lên picture box của MFC, sau đó dùng các hàm của OpenCV chuyển ảnh này thành ảnh xám và hiển thị lên một picture box khác. Giao diện chương trình như sau:

13

Page 14: Xu ly anh

OK, bắt đầu nhé!Đầu tiên ta khởi tạo một project sử dụng MFC, các bạn vào  File->New->Project. Chọn loại ứng dụng là MFC Application, đặt tên cho Project rồi click OK.Môt hộp thoại hiện ra, các bạn chọn Next, đến hộp thoại tiếp theo các bạn chọn vào Dialog based như hình sau:

Chọn Next một vài lần nữa cho tới khi cửa sổ cuối cùng như sau hiện ra:

14

Page 15: Xu ly anh

 Khi đó trong mục Generate Classes hãy chọn lớp thứ hai (có dạng ...Dlg) để chương trình khởi động tự động lớp Dialog. Nhấn Finish để kết thúc, như vậy ta đã có một project bằng MFC dựa trên giao diện Dialog. Để config cho Project có thể chạy được với OpenCV các bạn hãy vào Project Properties hoặc nhấn Alt + F7 để tuy chỉnh. Cách tùy chỉnh cũng giống như đối với Project dạng console mà tôi đã giới thiệu trước đó, các bạn có thểtham khảo thêm ở đây.

Ok, bây giờ ta hãy thiết kế một giao diện như hình đầu tiên. Giao diện gồm một button có nhãn Load Image, một button Convert to Scale Image. 2 Picture Control, và các Group box. Để lôi được các item này ra các bạn hãy vào ToolBox và kéo thả bình thường.

15

Page 16: Xu ly anh

Để thay đổi các thuộc tính của các Item này hãy click chuột phải vào Item cần tùy chỉnh, chọn Properties (ví dụ như thay đổi tên hiển thị thì tìm mục caption mà đổi ...). Riêng đối với 2 Picture Control để hiển thị ảnh được và giúp lập trình đơn giản thì ta cần làm theo các một số việc sau:- Thứ nhất, mặc định của Picture Control là dạng Frame. Để hiển thị ảnh Bitmap ta cần chỉnh thành Bitmap, để chỉnh sữa, click chuột phải chọn Properties, trong bảng Properties, chọn mục Type, sau đó đổi Frame thành Bitmap.- Thứ hai, tất cả các Item trong MFC đều được định sẵn một ID. Để tiện lợi cho việc thay lập trình ta sẽ truy xuất các ID này bằng các biến. Như vậy ta cần gắn cho các Picture Control một biến truy cập. Để gắn được biến cho Picture Control, trược hết phải đổi thuộc tính STATIC của chúng. Để đổi thuộc tính này, trong mục Properties của Picture Control, chon ID, chỉnh sữa IDC_STATIC thành bất kì cái gì bạn muốn, thông thường nên chỉnh thành IDC_STATIC1 chẳn hạn. Picture Control thứ hai là IDC_STATIC2. Sau khi đổi được thuộc tính STATIC, hãy click chuột phải vào biểu tượng Picture Control và chọn Add Variable... Một bảng hiện ra, hãy đặt tên lần lượt cho các Picture Control là pic1 và pic2 như sau:

16

Page 17: Xu ly anh

Và bây giờ ta có thể truy xuất tới các Picture Control bày bằng các biến pic1, pic2. Để đặt một ảnh bitmap lên control này ta có thể dùng lệnhpic1.SetBitmap(bitmap);  Vấn đề lớn nhất ở đây là hàm SetBitmap của MFC chỉ nhận duy nhất tham số đầu vào là một ảnh Bitmap (Trong khi có nhất nhiều định dạng ảnh khác nữa: Jpeg, png, ...) và với định dạng IplImage của OpenCV thì làm thế nào?Có hai giải pháp được đưa ra (có thể có nhiều nhưng tui mới biết có hai ... :D). Thứ nhất, chuyển đổi định dạng IplImage của OpenCV ra thành định dạng bitmap bằng cách dùng các hàm chuyển đồi. Thứ hai, lưu ảnh xử lý bằng OpenCV thành Bitmap sau đó load ảnh bằng hàm LoadImage của MFC rồi hiển thị ảnh. Tôi sẽ giới thiệu cả hai cách.

♥ Chuyển đổi IplImage của OpenCV sang định dạng Bitmap Các thông tin về định dạng của một bức ảnh được lưu ở header của ảnh. Do đó để chuyển đổi định dạng của ảnh ta chỉ cần can thiệp vào header của nó. Đoạn code sau sẽ làm việc đó.

inline HBITMAP IplImage2DIB(const IplImage *Image) // Convert IPl Image to Bitmap{ int bpp = Image->nChannels * 8; assert(Image->width >= 0 && Image->height >= 0 &&(bpp == 8 || bpp == 24 || bpp == 32)); CvMat dst; void* dst_ptr = 0; HBITMAP hbmp = NULL; unsigned char buffer[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)]; BITMAPINFO* bmi = (BITMAPINFO*)buffer; BITMAPINFOHEADER* bmih = &(bmi->bmiHeader); ZeroMemory(bmih, sizeof(BITMAPINFOHEADER)); bmih->biSize = sizeof(BITMAPINFOHEADER); bmih->biWidth = Image->width; bmih->biHeight = Image->origin ? abs(Image->height) : -abs(Image->height); bmih->biPlanes = 1; bmih->biBitCount = bpp; bmih->biCompression = BI_RGB;

17

Page 18: Xu ly anh

if (bpp == 8) { RGBQUAD* palette = bmi->bmiColors; int i; for (i = 0; i < 256; i++) { palette[i].rgbRed = palette[i].rgbGreen = palette[i].rgbBlue = (BYTE)i; palette[i].rgbReserved = 0; } } hbmp = CreateDIBSection(NULL, bmi, DIB_RGB_COLORS, &dst_ptr, 0, 0); cvInitMatHeader(&dst, Image->height, Image->width, CV_8UC3, dst_ptr, (Image->width * Image->nChannels + 3) & -4); cvConvertImage(Image, &dst, Image->origin ? CV_CVTIMG_FLIP : 0); return hbmp; }

♥ Bằng cách lưu ảnh lại dưới dạng bitmap, sau đó load và hiển thị ảnh:Sử dụng hàm của OpenCV để lưu ảnh: cvSaveImage(ten_anh.bmp, du_lieu_anh); sau đó dùng hàm LoadImage(); của MFC để load ảnh bitmap và hiển thị lên Picture box.

Quay lại Project, hãy copy đoạn code trên pass vào file ten_projectDlg.cpp ngay dưới phần include các header (Nhớ là include opencv.hpp vào đã nhé.). sau đó hãy ta xử lý sự kiện click chuột ở các button Load Image và Convert to Scale Image như sau:Double click vào button Load Image và thêm vào đoạn code như hình sau:

 Ở button Convert to Gray Image ta viết đoạn code sau:

Chú ý là các ảnh src, gray, resize và file_name có thể được khai báo trong header ten_projectDlg.hĐể kích thước của ảnh vừa khít với khung của dao diện thiết kế, ta có thể chỉnh tham số của ảnh resize

18

Page 19: Xu ly anh

trong hàm cvCreateImage(). (trong bài là 400x300 pixel). Một số trường hợp báo lỗi do khai báo file_name là kiểu CString còn tham sốcvLoadImage lại là const char*. Để khắc phục lỗi này hãy tắt chế độ unicode của chương trình đi bằng cách vào Project Properties (Alt + F7) -> General. Ở trang bên của General, mục Character Set chỉnh Use Unicode Character Set thành Use Multi-Byte Character Set.Sau đây là kết quả chạy chương trình:

PS: Một số khái niệm nhỏ hoặc các bước đơn giản trung gian khác nếu các bạn chưa rõ có thể tìm hiểu thêm, trong bài có đôi lúc gọi Picture Control là Picture Box ...MA#include "cv.h"#include "highgui.h"

char wndname[] = "Edge";char tbarname[] = "Threshold";int edge_thresh = 1;

IplImage *image = 0, *cedge = 0, *gray = 0, *edge = 0;

// define a trackbar callbackvoid on_trackbar(int h){    cvSmooth( gray, edge, CV_BLUR, 3, 3, 0, 0 );    cvNot( gray, edge );

    // Run the edge detector on grayscale    cvCanny(gray, edge, (float)edge_thresh, (float)edge_thresh*3, 3);      cvZero( cedge );    // copy edge points    cvCopy( image, cedge, edge );

    cvShowImage(wndname, cedge);}

int main( int argc, char** argv ){    char* filename = argc == 2 ? argv[1] : (char*)"fruits.jpg";        if( (image = cvLoadImage( filename, 1)) == 0 )        return -1;

19

Page 20: Xu ly anh

    // Create the output image    cedge = cvCreateImage(cvSize(image->width,image->height), IPL_DEPTH_8U, 3);

    // Convert to grayscale    gray = cvCreateImage(cvSize(image->width,image->height), IPL_DEPTH_8U, 1);    edge = cvCreateImage(cvSize(image->width,image->height), IPL_DEPTH_8U, 1);    cvCvtColor(image, gray, CV_BGR2GRAY);

    // Create a window    cvNamedWindow(wndname, 1);

    // create a toolbar     cvCreateTrackbar(tbarname, wndname, &edge_thresh, 100, on_trackbar);

    // Show the image    on_trackbar(0);

    // Wait for a key stroke; the same function arranges events processing    cvWaitKey(0);    cvReleaseImage(&image);    cvReleaseImage(&gray);    cvReleaseImage(&edge);    cvDestroyWindow(wndname);

    return 0;}  Rùi, bây giờ phân tích 1 chút về các hàm của openCV dùng trong bài toán này nhe.

Mã:#include "cv.h"#include "highgui.h"

Khai báo các thư viện của openCV được sử dụng trong chương trình. Nếu dùng Visual C 6 thì phải set up các thư viện trước cho project của bạn nhé.

Mã:IplImage *image = 0, *cedge = 0, *gray = 0, *edge = 0;

Khai báo header cho các file ảnh, các header này sẽ quy định những thông số của ảnh như kích cỡ, định dạng ảnh, độ phân giải, v.v... Đây là một biến con trỏ kiểu struct được định nghĩa trong thư viện OpenCV. Code của struct này như sau:

Mã:typedef struct _IplImage{    int  nSize;         /* sizeof(IplImage) */    int  ID;            /* version (=0)*/    int  nChannels;     /* Most of OpenCV functions support 1,2,3 or 4 channels */    int  alphaChannel;  /* ignored by OpenCV */    int  depth;         /* pixel depth in bits: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U,                            IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F are supported */    char colorModel[4]; /* ignored by OpenCV */    char channelSeq[4]; /* ditto */    int  dataOrder;     /* 0 - interleaved color channels, 1 - separate color channels.                            cvCreateImage can only create interleaved images */    int  origin;        /* 0 - top-left origin,                            1 - bottom-left origin (Windows bitmaps style) */    int  align;         /* Alignment of image rows (4 or 8).                            OpenCV ignores it and uses widthStep instead */

20

Page 21: Xu ly anh

    int  width;         /* image width in pixels */    int  height;        /* image height in pixels */    struct _IplROI *roi;/* image ROI. when it is not NULL, this specifies image region to process */    struct _IplImage *maskROI; /* must be NULL in OpenCV */    void  *imageId;     /* ditto */    struct _IplTileInfo *tileInfo; /* ditto */    int  imageSize;     /* image data size in bytes                            (=image->height*image->widthStep                            in case of interleaved data)*/    char *imageData;  /* pointer to aligned image data */    int  widthStep;   /* size of aligned image row in bytes */    int  BorderMode[4]; /* border completion mode, ignored by OpenCV */    int  BorderConst[4]; /* ditto */    char *imageDataOrigin; /* pointer to a very origin of image data                              (not necessarily aligned) -                              it is needed for correct image deallocation */}IplImage;

Đầu tiên chúng ta sẽ mở một file ảnh chứa sẵn trong máy lên để xử lý bằng hàm cvLoadImage()

Mã:if( (image = cvLoadImage( filename, 1)) == 0 )        return -1; // Mo mot file anh, neu thanh cong tra ve 1, khong tra ve -1

Hàm này có hai đối số, cái thứ nhất là 1 string chỉ đường dẫn và tên file ta cần load, các định dạng ảnh được hỗ trợ gồm có :

Windows bitmaps - BMP, DIBJPEG files - JPEG, JPG, JPEPortable Network Graphics - PNGPortable image format - PBM, PGM, PPMSun rasters - SR, RASTIFF files - TIFF, TIF

Đối số thứ hai là định dạng ảnh được đưa vào biến image. nếu đối số này là 1, ảnh là dạng RGB,2 là Grayscale còn -1 là không thay đổi so với nguyên mẫu. Sau khi thực hiện hàm,con trỏ header *image đã trỏ tới vùng nhớ chứa ảnh cần xử lý.

Bây giờ chúng ta sẽ tạo các file image rỗng để chứa các kết quả xử lý, để ý rằng các khai báo IplImage ban đầu chỉ là các header, ko phải file ảnh. Sau khi tạo file ảnh bằng hàm cvCreateImage(), chúng mới trỏ tới vùng nhớ chứa ảnh.

Mã:// Create the output image    cedge = cvCreateImage(cvSize(image->width,image->height), IPL_DEPTH_8U, 3);    gray = cvCreateImage(cvSize(image->width,image->height), IPL_DEPTH_8U, 1);    edge = cvCreateImage(cvSize(image->width,image->height), IPL_DEPTH_8U, 1);

Khai báo như trên nghĩa là ảnh cedge là ảnh màu 8 bit, 3 kênh (RGB), gray và edge là ảnh grayscale, chỉ có 1 kênh.

Để có thể thực hiện các thuật toán dò cạnh như dò cạnh sobel hay dò cạnh cranny ảnh cần phải được chuyển thành grayscale. Lý thuyết về convert grayscale có thể theo dõi ở đây. Trong OpenCV, hàm cvCvtColor() sẽ giúp ta thực hiện việc này.

Mã:cvCvtColor(image, gray, CV_BGR2GRAY);

Hàm này sẽ chuyển ảnh image màu thành ảnh gray là dạng grayscale. 

21

Page 22: Xu ly anh

Sau đó ảnh sẽ được lọc nhiễu, phân ngưỡng và xuất ra màn hình. Ở đây các thuật toán đó được viết trong hàm con on_trackbar.

Mã:void on_trackbar(int h){    cvSmooth( gray, edge, CV_BLUR, 3, 3, 0, 0 );    cvNot( gray, edge );

    // Run the edge detector on grayscale    cvCanny(gray, edge, (float)edge_thresh, (float)edge_thresh*3, 3);

    cvZero( cedge );    // copy edge points    cvCopy( image, cedge, edge );

    cvShowImage(wndname, cedge);}

Dưới đây là hai file chạy chương trình và file ảnh mẫu, các bạn có thể thấy hiệu quả của openCV À wên, phải cài openCV vào nó mới chạy được. File cài nè

22