Giới thiệu
Bạn là một người sử dụng thư viện OpenCV cho công việc nghiên cứu Thị giác máy tính (Computer Vison) và thuật toán xử lý ảnh. Bạn muốn viết một chương trình demo kết quả nghiên cứu một cách trực quan và tương tác hơn. Windows Form là một giải pháp mà tôi cảm thấy thú ví nhất.
Trong bài viết này tôi sẽ giới thiệu đến các bạn cách hiển thị ảnh IplImage (thư viện OpenCV) lên MFC dialog.
Bài viết này tôi dành cho các bạn mới bắt đầu nghiên cứu OpenCV, và các bạn cần một ứng dụng Windows Form để demo thuật toán xử lý. Do đó tôi cố gắng trình bày ở mức dễ hiểu nhất có thể, hy vọng các bạn nắm bắt được phương pháp và mở rộng tính năng của ứng dụng để phục vụ tốt hơn cho công việc nghiên cứu.
Kiến thức nền
Ngôn ngữ lập trình: C/C++
Biết lập trình Windows Form MFC căn bản (trong bài viết này tôi sử dụng Visual Studio 10)
Biết sử dụng thư viện OpenCV (trong bài viết này tôi sử dụng phiên bản 3.0.0-alpha, các phiên bản khác cũng tương tự) trong Visual Studio.
- Đã biết cách cấu hình thư viện OpenCV trong Visual Studio (có trình bày sơ lược trong bài viết này)
- Đã biết cách tạo ứng dụng Win32 Console để sử dụng OpenCV
Chi tiết
Chúng ta sẽ tạo một ứng dụng dạng Dialog có thiết kế như hình bên dưới. Click vào nút Browse để chọn ảnh cần hiển thị. Sau khi chọn xong thì ảnh sẽ được hiển thị lên control của Dialog.
Nếu muốn thay đổi ảnh thì chỉ việc click và Browse phát nữa. Nếu muốn hiển thỉ cả ảnh gốc và kết quả của thuật toán thì chỉ việc thêm một control để hiển thị ảnh nữa là xong.
Về tổng quát thì giải pháp sẽ như sau:
- Tạo một MFC dialog,và thêm Picture Control (hoặc Static Text) vào dialog. Tạo buffer ảnh cho control này
- Load ảnh bằng hàm
cvLoadImage()
của thư viện OpenCV - Copy ảnh đã load vào buffer ảnh của control (có thể cần phải rescale lại ảnh để hiển thị lên control)
- Convert dữ liệu từ buffer ảnh sang đối tượng ảnh của MFC và vẽ lên control
Bước 1: Tạo MFC project trong Visual Studio.
Chọn File>New>Project
Chọn Visual C++>MFC>MFC Application. Đặt tên cho project là
mfcopencv
và click OK.Thiết lập cho Application Type như sau:
Click Finish.
Bước 2: Chuẩn bị thư viện OpenCV
Trong thư mục chứa Project, tạo 2 thư mục
inc
và lib
Các bạn download và giải nén thư viện OpenCV.
Sau đó copy 2 thư mục
opencv
và opencv2
vào thư mục inc
đã tạo. Copy file
opencv_world300.lib
vào thư mục lib
đã tạoSau đó copy file
opencv_world300.dll
vào thư mục Debug
của project.Các bạn cấu hình thư viện OpenCV cho project như sau:
Bước 3: CvMFCImage class
Class
CvMFCImage
gồm có 2 file: CvMFCImage.h
, CvMFCImage.cpp
Tiền thân của 2 anh em thằng này à lớp
CvvImage
của OpenCV 2.1.0. Từ phiên bản 2.2.0 trở về sau thì class này đã bị lưu đày biệt xứ :(.Các bạn download 2 file này vào thư mực source code của project (link download ở cuối bài viết)
Sau đó các bạn Build project. Nếu build bị lỗi thì các bạn có thể tắt máy đi ngủ.
Bước 4: Thêm control vào Dialog để hiển thị ảnh
Trên thanh Menu, chọn View>Resource View. Click chọn IDD_MFCOPENCV_DIALOG
Các bạn chọn View>Toolbox, chọn Picture Control (hoặc Static Text cũng được).
Sau khi chọn thì click vào Dialog box để vẽ control đấy. Tiện tay thì sửa luôn cái Caption cho nút OK thành Browse.
Kết quả vẽ vời của tôi như hình bên dưới.
Tiếp theo, chúng ta sẽ viết code để hiển thị ảnh vào cái vùng hình nhật mà chúng ta vừa tạo xong.
Bước 5: Xử lý khi Click vào nút Browse.
Để tạo sự kiện click cho nút Browse, các bạn double click vào nút này. Visual Studio sẽ tự động tạo code như bên dưới:
void CMfcOpencvDlg::OnBnClickedOk() { // TODO: Add your control notification handler code here CDialogEx::OnOK(); }Các bạn sửa lại code như sau:
void CMfcOpencvDlg::OnBnClickedOk() { CFileDialog fileDlg(TRUE, NULL, NULL, OFN_FILEMUSTEXIST, "(*.bmp;*.jpg;*.png)|*.png;*.jpg;*.png|", this); if(fileDlg.DoModal()==IDOK) { CString strPathname = fileDlg.GetPathName(); IplImage *pImage = cvLoadImage(strPathname.GetBuffer(0),1); if(pImage) { ShowIplImage(pImage); cvReleaseImage(&pImage); } else { MessageBox(strPathname, "Open file error"); } } }Tất nhiên để đoạn code này chạy được thì chúng ta cần phải implement hàm
ShowIplImage()
cho class CMfcOpencvDlg
★ Chúng ta sửa lại code cho class
CMfcOpencvDlg
như sau:- Khai báo buffer ảnh cho control (IplImage* m_pImgDisp)
- Khai báo kích thước của buffer ảnh (IMG_WIDTH, IMG_HEIGHT)
- Định nghĩa và implement cho hàm
CopyImage()
- Định nghĩa và implement cho hàm
ShowIplImage()
// ... #include "CvMFCImage.h" // ... class CMfcOpencvDlg : public CDialogEx { // Construction public: CMfcOpencvDlg(CWnd* pParent = NULL); // standard constructor ~CMfcOpencvDlg(); // ... -> Một số dòng code đã được ẩn đi :D static const unsigned int IMG_WIDTH = 320; /* Chiều rộng của buffer ảnh */ static const unsigned int IMG_HEIGHT = 240; /* Chiều cao của buffer ảnh */ // ... protected: IplImage* m_pImgDisp; /* Buffer ảnh của control IDC_IMG_DSP */ void CopyImage(const IplImage* imgI); void ShowIplImage(IplImage* pImgSrc); // ... public: afx_msg void OnBnClickedOk(); };★ Buffer ảnh sẽ được cấp phát trong Constructor và thu hồi trong Destructor:
CMfcOpencvDlg::CMfcOpencvDlg(CWnd* pParent /*=NULL*/) : CDialogEx(CMfcOpencvDlg::IDD, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); m_pImgDisp = cvCreateImage(cvSize(IMG_WIDTH, IMG_HEIGHT),IPL_DEPTH_8U,3); cvSet((IplImage*)m_pImgDisp, CV_RGB(128,128,128)); } CMfcOpencvDlg::~CMfcOpencvDlg() { cvReleaseImage(&m_pImgDisp); }★ Hàm
CopyImage()
được implement như bên dưới:
/** * @brief Copy ảnh cần hiển thị vào buffer ảnh của control * @param pImg Ảnh cần hiển thị * @param imgContainer Ảnh */ void CMfcOpencvDlg::CopyImage(const IplImage* img) { float fXScale = 1.0; float fYScale = 1.0; float fScale = 1.0; int iDispWidth; int iDispHeight; int iDispWPad; int iDispHPad; /* Nếu ảnh cần hiển thị lớn hơn buffer ảnh thì cần phải thực hiện Rescale*/ if(img->width > m_pImgDisp->width || img->height > m_pImgDisp->height) { fXScale = (float) ( (float)img->width / (float)m_pImgDisp->width ); fYScale = (float) ( (float)img->height / (float)m_pImgDisp->height ); /* Rescale theo chiều lớn hơn */ if(fXScale > fYScale) { fScale = fXScale; } else { fScale = fYScale; } } /* Điều chỉnh để cho ảnh gốc được vẽ vào giữa buffer ảnh của control */ iDispWidth = (int)(img->width / fScale); iDispHeight = (int)(img->height / fScale); iDispWPad = (m_pImgDisp->width - iDispWidth) / 2; iDispHPad = (m_pImgDisp->height - iDispHeight) / 2; cvSet( m_pImgDisp, cvScalar(128,128,128) ); cvSetImageROI( m_pImgDisp, cvRect(iDispWPad, iDispHPad, iDispWidth, iDispHeight) ); cvResize( img, m_pImgDisp ); cvResetImageROI( m_pImgDisp ); }★ Hàm
ShowIplImage()
:
/** * @brief Hiển thị ảnh lên Dialog control * * @param pImg Ảnh gốc cần hiển thị */ void CMfcOpencvDlg::ShowIplImage( IplImage* pImg ) { CDC* pDC = NULL; HDC hDC; CRect rect; /* Copy ảnh cần hiển thị vào buffer ảnh của control */ CopyImage(pImg); pDC = GetDlgItem(IDC_IMG_DSP)->GetDC(); hDC = pDC->GetSafeHdc(); GetDlgItem(IDC_IMG_DSP)->GetClientRect(&rect); /* Điều chỉnh để cho ảnh hiển thị giữa control */ int rw = rect.right - rect.left; int rh = rect.bottom - rect.top; int iw = m_pImgDisp->width; int ih = m_pImgDisp->height; int tx = (int)(rw - iw) / 2; int ty = (int)(rh - ih) / 2; SetRect( rect, tx, ty, tx + iw, ty + ih ); /* Hiển thị ảnh lên control */ CvMFCImage cimg; cimg.CopyOf( m_pImgDisp ); cimg.DrawToHDC( hDC, &rect ); ReleaseDC( pDC ); }
Kết luận
Như vậy là bằng việc sử dụng MFC Windows Form và class CvMFCImage chúng ta đã có được một ứng dụng trực quan cho việc demo kết quả nghiên cứu rồi. Đơn giản như đang giỡn :DSource code
mfcopencv.zipTham khảo
http://opencv.org/http://docs.opencv.org/trunk/doc/tutorials/introduction/windows_visual_studio_Opencv/windows_visual_studio_Opencv.html#windows-visual-studio-how-to
Bai viết hay
Trả lờiXóaCòn video thì như nào bạn
Trả lờiXóa