Hướng dẫn lập trình nhận dạng hình ảnh với Opencv

A.1. Giới thiệu
OpenCV (Open Computer Vision http://opencv.org ) là một thư viện mã nguồn mở chuyên dùng để xử lý các vấn đề liên quan đến thị giác máy tính hay còn gọi theo tên thông dụng khác là xử lý hình ảnh hoặc nhận dạng hình ảnh. 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:

 opencv

- 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.

Các cấu trúc quan trọng


CvPoint: Chứa cấu trúc tọa độ của một điểm ảnh:
Code:  
typedef struct CvPoint
    {
        int x; /* x-coordinate, usually zero-based */
        int y; /* y-coordinate, usually zero-based */
    }
    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
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ật

Code:
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 */
    }
    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:
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;
        };

        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:
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 */
        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:
#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 */ \
    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 Array
Song 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:
   double a[] = { 1, 2, 3, 4
                  5, 6, 7, 8,
                  9, 10, 11, 12 };

   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 động
OpenCV 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: MemStorage
Code:  
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.

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. CV
Nhó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ý ảnh
Bao gồm:
Code:
     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úc
Bao gồm
Cá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. HighGUI
HighGUI 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ện
Bao 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:
    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 ảnh
Bao 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.

Cài đặt thư viện OpenCv 2.x
Bài viết này là để cập nhật cho bài hướng dẫn cài đặt OpenCV 1.1. Khi viết bài này tôi sử dụng với Visual studio .Net 2008 và 2010 cho các dự án của mình. Phiên bản 2.x là sự cải tiến về cấu trúc, tăng cường thuật tóan cấp cao, giải quyết vấn đề bộ nhớ cho v1.1.

Giữa hai phiên bản này có sự hác biệt về cài đặt khá lớn đó là trong khi v1.1 tích hợp mã nguồn, tập tin thực thi và cấu hình dự án cho VS2005 thì v2.x chỉ cung cấp nội dung, cấu trúc mã nguồn còn bạn phải tự tạo cấu hình dự án (project) tùy theo từng môi trường bạn muốn phát triển. Trong trường hợp của tôi đó là VS2008. Điều này có một điểm hay đó là tách bạch giữa nội dung mã nguồn và môi trường phát triển, tuy nhiên lại gây một chút khó khăn cho người dùng "newbie". Công cụ dùng để tạo, cấu hình dự án là CMake có thể download: https://cmake.org  Bộ cài đặt cho OpenCV 2.x có thể được tải https://sourceforge.net/projects/opencvlibrary/files/

Vui lòng thực hiện các bước sau đây để cài đặt Open CV:

1. Download, cài đặt Open CV 2.x và CMake. Trong quá trình cài đặt OpenCV chú ý chọn để tạo liên kết trong system PATH. Dưới đây là OpenCV của tôi sau khi cài đặt.

opencv1
 
2. Chạy CMake để tạo và cấu hình dự án cho OpenCV.

opencv2

3. Click nút Configure để chọn lọai môi trường và dự án bạn muốn (chú ý là trên máy của bạn phải có cài đặt sẵn môi trường phát triển IDE, trong trường hợp của tui là VS2008):

opencv3

4. Sau khi đã chọn xong nhấn finish:

opencv

5. Nhấn chọn tiếp nút Configure lần nữa để tiếp tục cấu hình sau đó nhấn Generate và bạn đã hòan tất việc tạo, cấu hình dự án để biên dịch OpenCV

opencv5
 
6. Mở dự án vừa tạo và biên dịch để tạo ra file dll, lib cho opencv.

opencv6
 
7. Sau khi biên dịch bạn sẽ có các tập tin DLL, Lib cùng với các tập tin .h sẵn có trong thư mục install bạn đã sằn sàng để cấu hình cho việc sự dụng OpenCV trong dự án của mình.

opencv7

 

8. Cấu hình để sử dụng OpenCV trong dự án của bạn, cái này tương tự như trong phần hướng dẫn cho V1.1 trước đây. Chỉ chú ý một vài điểm:
- header file trong OpenCV 2.0 tập trung tại một vị trí duy nhất như hình trên chứ không phân tán nhiều nơi như 1.1.
- tên tập tin library của OpenCV 2.0 khác với 1.1. Ví dụ v1.1: abc.lib thì trong 2.0 sẽ là abc200.lib

opencv8

9. Chi tiết cấu hình cho OpenCV 2.2 và VS2010: Các bước trên từ 1-7 đã hướng dẫn các bạn cách để build lại mã nguồn OpenCV theo môi trường phát triển mong muốn, nếu bạn muốn dùng VS2010 thì đơn giản là bạn chỉ cần cài đặt VS2010 rồi tuần tự làm theo 1-7 nhưng thay vì chọn VS2008 bạn chọn VS2010 trong cấu hình CMake. Lưu ý là DLL mặc định đi kèm với OpenCV 2.2 là DLL được biên dịch bằng VS2010 với Win32 bit, nếu môi trường phát triển của bạn tương thích với DLL, Lib mặc định và bạn không có nhu cầu phát triển mã của OpenCV thì bạn không cần thực hiện bước 1-7. Trong trường hợp của tôi thì tôi đã thực hiện 1-7 sau đó biên dịch lại OpenCV ở chế độ 64 bit rồi dùng DLL và Lib mới biên dịch được. Sau đây là chi tiết cấu hình để sử dụng thư viện cho dự án với VS2010.

opencv9
 Chọn Properties của dự án để bắt đầu cấu hình

opencv10

Thiết lập đường dẫn tới header


 opencv11
Thiết lập đường dẫn tới Lib trong thư mục mới build lại của OpenCV dùng bước 1-7

 opencv12Thêm thự viện muốn sử dụng vào Linker


Chú ý DLL của OpenCV sẽ được dự án Load dựa vào cấu hình biến môi trường PATH.

 

CHÚC THÀNH CÔNG!

Download tài liệu tại đây >>

(st)

Hồ sơ năng lực xem tại: Scribd | Slideshare

CTY DVMS

150/30 Đường Trục, Phường 13, Q. Bình Thạnh, TP.HCM, Việt Nam.

02836028937 | 02835531145

02835531145

This email address is being protected from spambots. You need JavaScript enabled to view it.

Văn Phòng Hà Nội

Tầng 9 số 169 Nguyễn Ngọc Vũ, P. Trung Hòa, Q. Cầu Giấy, Hà Nội, Việt Nam

02836028937 | 02835531145

02835531145

This email address is being protected from spambots. You need JavaScript enabled to view it.

Đại diện tại Hải Phòng

Hải Phòng, Việt Nam

02836028937 | 02835531145

02835531145

This email address is being protected from spambots. You need JavaScript enabled to view it.