Halcon 機器視覺程式設計初探
在機器視覺領域,德國MVTec公司出品的視覺開發軟體Halcon可謂無人不知,無人不曉,相比與其他輕量級的視覺開發包,Halcon提供了很多具有工業強度的影象識別演算法,效能優越,是機器視覺開發首先。最新版為Halcon 12,提供C/C++,.Net等介面,可以非常方便使用者將Halcon中的影象演算法植入到自己的應用程式中來。
很早以前就打算深入研究一下Halcon機器視覺開發了,利用工作之餘,搗鼓了一下,稍微試用了一下,立刻體會到,果真這個軟體不是一般的牛逼,對於很多不是計算機影象專業出生的工程師來說,終於可以從晦澀難懂的高等代數與微積分,以及各種矩陣方程中解脫出來,讓你不必瞭解影象處理理論,直接處理業務核心邏輯,極大的縮短了機器視覺的開發週期。本文以微軟VS2010中使用MFC開發基於Halcon11的機器視覺應用為例,為很多像我一樣的初學者做登堂入室的墊腳石。閒話少說,詳見下文所述。
首先,在VS2010中使用MFC配置Halcon11,這一步雖然簡單,但有很多初學者在邁出這第一步的時候就碰了一鼻子灰,無論怎麼配置,程式就是編譯通不過。不要著急,請仔細看好了。以基於對話方塊的MFC應用程式為例。
第一步,建立MFC應用程式,給工程取個名字叫HalconFirstStep,如下圖所示:
第二步,選擇基於對話方塊的應用程式,如下圖所示:
第三步:在本例中,我們在對話方塊中,新增兩個按鈕,一個按鈕用來載入圖片,一個用來處理圖片,如下所示:
第四步:我們在選單欄找到”Project“ -> "HalconFirstStep Properties...",在彈出的對話中中,選擇左邊視窗選擇VC++ Directories, 在右邊視窗中選擇Include Directories,新增Halcon的標頭檔案路徑,這個視Halcon的安裝路徑不同而不同,也許你電腦上的安裝路徑和下圖中顯示的有所出入。標頭檔案路徑包含兩個路徑,一個指定Halcon的Include資料夾位置,一個指定Include資料夾下CPP的位置。如下圖所示:
第五步:還是在左邊視窗選擇VC++ Directories, 在右邊視窗中選擇Library Directories,新增Halcon的lib檔案路徑,如下圖所示:
第六步:在左邊視窗中選擇C/C++, 在下拉樹形列表中選擇General,在視窗右邊選擇Additional Include Directories,配置Halcon標頭檔案所在路徑。如下圖所示:
第七步:在視窗左邊Linker下選擇General,在視窗右邊選擇Addtional Library Directories,配置Halcon庫檔案所在路徑,如下圖所示:
第八步: 在左邊視窗的Linker下選擇Input,在右邊視窗中選擇Additional Dependencies 輸入Halconcpp.lib。如下圖所示:
在這一步需要注意的是,如果你安裝的是Halcon的版本號是11.0.0.1的話,這裡Additional Dependencies 輸入的應該是halconcpp10.lib。這是因為11.0.0.1實際上仍然使用的是Halcon10所用的靜態連結庫。Halcon 11.0.0.1其實並不是真正意義的11.0版本。很多初學者,在安裝了Halcon11.0.0.1版本後,參考網上的配置方法,程式編譯時死活說找不到符號。多半都是卡在這裡。筆者就被這個問題折磨了兩天。
經過以上八步,恭喜你,VS 2010配置Halcon 11算是大功告成。接下來就是好戲上演的時刻了,我們要開始編程式碼來演示我們的例子了。
第九步:在HalconFirstStepDlg.h 檔案開始處,新增程式碼:
[cpp] view plain copy print?- #include "halconcpp.h"
- usingnamespace Halcon;
#include "halconcpp.h"
using namespace Halcon;
注意,如果你安裝的Halcon版本是11.0.0.1的話,實際上這個版本仍然和Halcon10一樣,使用的是Halcon名稱空間,而不是HalconCpp。
第十步:我們在HalconFirstStepDlg.cpp檔案中,新增一個全域性變數來儲存開啟的圖片。
[cpp] view plain copy print?- Hobject img;
Hobject img;
第十一步:新增讀取圖片按鈕的響應程式碼,我們雙擊對話方塊中的”載入圖片“按鈕,新增下面的程式碼: [cpp] view plain copy print?
- void CHalconFisrtStepDlg::OnBnClickedButton1()
- {
- //獲取影象視窗父視窗控制代碼
- CRect rect;
- HWND hwnd = GetDlgItem(IDC_STATIC1)->m_hWnd;
- GetDlgItem(IDC_STATIC1)->GetWindowRect(&rect);
- //開啟影象視窗
- Hlong windowId;
- open_window(0,0,rect.Width(),rect.Height(),(Hlong)hwnd,"visible","",&windowId);
- //將影象讀入記憶體
- read_image(&img,"mreut");
- //獲取影象大小
- HTuple width,height;
- get_image_size(img,&width,&height);
- //按照比例縮放到影象視窗
- set_part(windowId,0,0,width,height);
- //顯示影象
- disp_obj(img,windowId);
- }
void CHalconFisrtStepDlg::OnBnClickedButton1()
{
//獲取影象視窗父視窗控制代碼
CRect rect;
HWND hwnd = GetDlgItem(IDC_STATIC1)->m_hWnd;
GetDlgItem(IDC_STATIC1)->GetWindowRect(&rect);
//開啟影象視窗
Hlong windowId;
open_window(0,0,rect.Width(),rect.Height(),(Hlong)hwnd,"visible","",&windowId);
//將影象讀入記憶體
read_image(&img,"mreut");
//獲取影象大小
HTuple width,height;
get_image_size(img,&width,&height);
//按照比例縮放到影象視窗
set_part(windowId,0,0,width,height);
//顯示影象
disp_obj(img,windowId);
}
上面的程式碼中讀取的圖片,是怎樣一副圖片呢,如下圖所示:
在這幅衛星圖片中,我們的目的是,找出公路所在區域,並把它用紅色標記出來。從這幅圖片的特徵我們不難看出,公路與周圍草坪的顏色反差很大,草坪和公路顏色涇渭分明,所以,我們對影象進行二值化處理,區域灰度在閾值以下的全部變黑,區域灰度在閾值以上的全部變白,只留下閾值範圍內的區域。然後聯通所有存在的區域,並選擇其中最大的區域。有了這樣的思路,我們就可以給按鈕“影象處理”單擊事件新增下面的程式碼:
[cpp] view plain copy print?- void CHalconFisrtStepDlg::OnBnClickedButton2()
- {
- //獲取影象視窗父視窗控制代碼
- CRect rect;
- HWND hwnd = GetDlgItem(IDC_STATIC2)->m_hWnd;
- GetDlgItem(IDC_STATIC2)->GetWindowRect(&rect);
- //開啟影象視窗
- Hlong windowId;
- open_window(0,0,rect.Width(),rect.Height(),(Hlong)hwnd,"visible","",&windowId);
- //獲取影象大小
- HTuple width,height;
- get_image_size(img,&width,&height);
- //按照比例縮放到影象視窗
- set_part(windowId,0,0,width,height);
- //顯示影象
- disp_obj(img,windowId);
- Hobject BrightRegion,ConnectedRegion,SelectedRegion;
- //將影象二值化,設定閾值下限為180,上限為255
- threshold(img,&BrightRegion,188,255);
- //連通閾值範圍內明亮區域
- connection(BrightRegion,&ConnectedRegion);
- //選擇連通區域內面積最大的區域
- select_shape_std(ConnectedRegion,&SelectedRegion,"max_area",0);
- //設定選擇區域的顏色為紅色
- set_color(windowId,"red");
- //顯示選擇區域
- disp_obj(SelectedRegion,windowId);
- }
void CHalconFisrtStepDlg::OnBnClickedButton2()
{
//獲取影象視窗父視窗控制代碼
CRect rect;
HWND hwnd = GetDlgItem(IDC_STATIC2)->m_hWnd;
GetDlgItem(IDC_STATIC2)->GetWindowRect(&rect);
//開啟影象視窗
Hlong windowId;
open_window(0,0,rect.Width(),rect.Height(),(Hlong)hwnd,"visible","",&windowId);
//獲取影象大小
HTuple width,height;
get_image_size(img,&width,&height);
//按照比例縮放到影象視窗
set_part(windowId,0,0,width,height);
//顯示影象
disp_obj(img,windowId);
Hobject BrightRegion,ConnectedRegion,SelectedRegion;
//將影象二值化,設定閾值下限為180,上限為255
threshold(img,&BrightRegion,188,255);
//連通閾值範圍內明亮區域
connection(BrightRegion,&ConnectedRegion);
//選擇連通區域內面積最大的區域
select_shape_std(ConnectedRegion,&SelectedRegion,"max_area",0);
//設定選擇區域的顏色為紅色
set_color(windowId,"red");
//顯示選擇區域
disp_obj(SelectedRegion,windowId);
}
好了,完整的程式程式碼到這裡就全部結束了,我們來檢驗一下程式的執行效果,我們除錯執行一下,先點選“載入圖片”,然後點選“處理圖片”按鈕。果然程式按照我們預想的那樣工作了。怎麼樣,是不是很驚喜呀。我們驚喜的同時,要感謝那些為Halcon編寫演算法的那些演算法工程師和數學家,感謝他們為我們提供了一個這麼智慧的視覺開發包。下圖是程式執行效果。
要轉載本文,請註明出處,尊重智慧財產權。