1. 程式人生 > >OpenCV與MFC通用型影象處理開發實踐

OpenCV與MFC通用型影象處理開發實踐

imagehandler

該程式的起源說來話長,它起源自上課的一次作業,後來又由於接觸了OpenCV這個開源庫,我就試圖將OpenCV和MFC搓到一塊,畢竟微軟近來在介面上也下了狠功夫,尤其是Windows 7大獲成功,而WP7.5和Windows 8躍躍欲試。結合Windows桌面也不失為一個有益的嘗試。

關於imagehandler

本程式是在 MFC 中使用 OpenCV 處理影象的演示程式,由2部分組成。

背景知識:

OpenCV是Intel®開源計算機視覺庫。它由一系列 C 函式和少量 C++ 類構成,實現了影象處理和計算機視覺方面的很多通用演算法。現在OpenCV已經發布了2.3.1版本,也就是本程式使用的版本。

本程式使用Visual Studio 2010開發環境在Windows 7 SP1 上開發完成,並採用了Microsoft 最新的Ribbon UI,介面友好,使用簡便。

一、Windows 下用 MFC(Ribbon 介面) 編制的程式框架

採用裝置無關點陣圖DIB實現Windows多文件模式下影象的顯示,實現顯示的關鍵函式StretchDIBits的原型如下:

int StretchDIBits(

    HDC hdc,                       //  顯示裝置控制代碼

    int XDest,                       //  目標矩形區域左上角X座標

    int YDest,                       //  目標矩形區域左上角Y座標

    int nDestWidth,                   //  目標矩形區域寬度

    int nDestHeight,                   //  目標矩形區域高度

    int XSrc,                         //  源矩形區域左上角X座標

    int YSrc,                         //  源矩形區域左上角Y座標

    int nSrcWidth,                    //  源矩形區域寬度

    int nSrcHeight,                    //  源矩形區域高度

    CONST VOID *lpBits,             //  點陣圖的畫素存放首地址

    CONST BITMAPINFO *lpBitsInfo,  //  點陣圖資訊存放地址

    UINT iUsage,                     //  點陣圖中的顏色型別,RGB模式用DIB_RGB_COLORS

    DWORD dwRop                  //  畫素操作碼,簡單複製用SRCCOPY

);

由於OpenCV中的點陣圖結構中的畫素資料與DIB中的畫素具有相同的儲存結構,見表1中的畫素部分。所以,只要為它構造一個DIB的點陣圖資訊就可以呼叫API函式StretchDIBits實現它的顯示了。

表1  DIB點陣圖引數與IplImage結構引數

參  數

DIB (MFC)

Mat (OpenCV)

寬  度

biWidth

Mat::cols

高  度

biHeight

Mat::rows

畫素位數

biBitCount (1,4,8,16,24,32) = elemSize1*nChannels*8

Mat::elemSize1()

通道數

---

Mat::channels ()

(單通道點陣圖) 調色盤單元數

2biBitCount

(2, 16, 256)

二值影象顯示為灰階影象

256色彩色影象顯示為真彩色影象

點陣圖座標原點

底-左

origin (0 頂-左,1 底-左)

畫素分量存放方式

交叉存取 (按畫素為單位存放)

0 交叉存取,1 位平面方式

對齊方式 (行畫素資料湊整)

4位元組對齊

8位元組對齊

每行位元組數

(biWidth*biBitCount+31)/32*4

Mat::step

畫素位元組數

((biWidth*biBitCount+31)/32*4)* biHeight

----

畫素存放地址

BYTE*  pBits

uchar*Mat::data

感興趣區域

---

roi

表中正體字母部分表示相同的引數,粗體字母表示引數部分相同時的交集,斜體加下劃線表示結構特有的引數。

點陣圖的寬度、高度、畫素存放首地址、每行位元組數、畫素總位元組數等5個引數在兩種結構中相同。

畫素位數、通道數、座標原點位置、畫素分量存放方式、對齊方式等5個引數在兩種結構中部分相同,使用時可以取其交集,表中用粗體字表示。

有2個引數是兩種點陣圖各自獨有的,感興趣區域為Mat類所獨有,調色盤單元為DIB所獨有。

從表1中可以看出,除了高精度影象(位深度16,32,64)外,這兩種點陣圖結構在影象處理的絕大部分應用中可以通用。

從以上比較中也可看出,Mat類適用於高精度處理,並且可以限制處理的區域;而DIB適用於Windows圖形操作,並且可以儲存低位數影象檔案,如每畫素一位的二值影象與畫素8位的索引影象等。

二、呼叫 OpenCV 函式實現處理

使用 OpenCV 函式處理影象在 MFC 環境下顯示,實現功能為影象平移、影象翻轉與映象。

主要內容

下面列出stdafx.h尾部集中的幾個標頭檔案,程式結構由此可見一斑。

#include "imagehandler.h"                       //  視窗管理

#include "opencv2/core/core.h"                            //  OpenCV 標頭檔案

#include " opencv2/highgui/highgui.h"                      //OpenCV自帶介面

#include "opencv2/imgproc/imgproc.h"                     //影象處理函式庫,本來可以用上的但是

                                                    //功能沒有寫完

imagehandler的選單結構

程式分為主功能和幾何變換2部分,程式的選單結構見表2,其中列出了演示程式的大多數功能。

表2  imagehandler選單結構

main

幾何變換

開啟

翻轉

儲存

映象

平移

程式結構

程式採用VC++多文件結構,影象的存放與處理則採用OpenCV的結構與函式,影象的顯示採用點陣圖資訊m_lpBmi實現,為了便於管理對m_lpBmi的操作集中在OnDraw程式中。待顯示點陣圖結構發生改變時用m_dibFlag標誌激發m_lpBmi的重新整理。除了檔案結構與影象顯示外,其餘部分基本上是OpenCV程式。

主要功能區為mfcvProcess

CimagehandlerView

CimagehandlerDoc

mfcvProcess的基本功能

1實現讀入影象寫入到Mat中,

2 使用DIB在文件檢視中顯示,

3 進行幾何變換,

4 進行裁剪,影象拼接操作,

5 將修改的資料儲存到Mat 格式中,

6 將Mat寫入到影象資料中並儲存。

演算法實現:

話說影象

BMP取自點陣圖BitMap的縮寫,也稱為DIB(與裝置無關的點陣圖)是微軟視窗圖形子系統(GDI)內部使用的一種點陣圖圖形格式,它是微軟視窗平臺上的一個簡單的圖形檔案格式。的圖形檔案格式。

點陣圖畫素寬度必須是4的倍數……

影象可以分解成多個通道存放在一個二維矩陣中,

   Mat即矩陣的簡稱,它是OpenCV中一個基礎的矩陣結構。在CV(computer vision)中,影象就是一個二維的矩陣,Mat的責任就是將影象資料讀入到記憶體塊中,並將影象每一個通道的資料通過特殊的資料結構進行表達。通常這些結構的原子就是簡單的數字(usigned、double、int、float等)或是無符號的字元(usigned char)。一些常用的函式:

at模板函式,ptr模板函式,create函式,channels函式(獲取影象通道數)。。。

影象顯示

由於bmp要求影象單行所佔位元組數必須是4的倍數我於是在顯示時都通過OpenCV處理成4的倍數在顯示,但實際處理的影象始終按原來大小進行操作。

 影象幾何變換

概念建立一種元影象畫素與變換後的的影象畫素之間的對映關係。

公式如下:(x、y表示輸出影象畫素座標,x0,y0表示輸入影象畫素的座標

    ;

採用統一的矩陣表示法:

向前對映  入射→輸出

浮點數座標(放大縮小),對映不完全和對映重疊(向後對映:輸出影象的畫素座標來確定輸入影象畫素座標)

影象放大縮小問題

第一位,確定所處理的物件是一個什麼結構,在這裡我使用了OpenCV中的C++介面,使用了微軟的MFC程式框架,只有這兩個東西可以提供資料結構容器,否則就只有用C++的標準函式(fopen)和陣列(向量(vector.h))了。為了簡化後續應用演算法,這裡採用OpenCV的矩陣結構Mat。這是一個以矩陣形式儲存影象資料或矩陣的C++類。

其次要決定的是採用什麼樣的演算法對影象進行處理。通常影象放大有:最近鄰法、雙線性插值法、二次卷積插值法、三次卷積插值法等。

影象的旋轉

仍然採用向後對映,旋轉的同時注意改變影象的大小和影象對齊的問題

影象平移

應用向後對映原理,通過目標影象象素點座標計算出該點在原圖中的座標,如果座標值存在,複製資料,否則什麼也不幹。因為在此之前,我已經快取影象的所有畫素都賦值了。

設 (x0,y0)為原影象上一點,影象水平平移量為tx,垂直平移量為ty,平移後的點為(x1,y1) x1=x0+tx;y1=y0+ty,轉換後x0=x1-tx;y0=y1-ty這樣平移後的影象上的每一點都可以在原影象中找到對應的點,可以根據x0和y0的值,判斷原來的點是否在影象中,如果超出了原來影象的範圍,就把點(x1,y1)的值設定成0(黑色)或255(白色)如果希望保留原圖所有畫素,則根據平移量增加相應的象素點即可。

參考文獻

演算法學習:

[1]  左飛.萬晉森.劉航 Visual C++數字影象處理開發入門與程式設計實踐[M]. 北京:電子工業出版社, 2008

[2] [Laganière 2011] Robert Laganière Overview of OpenCV 2 Computer VisionApplication Programming Cookbook,Birmingham(UK):Packt Publishing Ltd;2011

OpenCV學習

[3]  (美)布拉德斯基(Bradski G)(美)克勒(keahler,A).學習OpenCV[M] 於士祺 劉瑞禎譯. 北京:清華大學出版社2009

[4] OpenCV Reference ,US,2011

其他:

百度空間,新浪部落格,網易部落格,CSDN以及Stackoverflow,Guru,CodeProject等社群。


目前的工作結果:

計劃中的工作:(有興趣的筒子可以一起學習QQ:547792075

新增遙感影像處理

附件:

imagehandler.rar,以上只是一個簡單的作業,為了方便大家學習,附上原始碼,有疑問的可以和我交流。