1. 程式人生 > >Halcon 機器視覺程式設計初探

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?
  1. #include "halconcpp.h"
  2. usingnamespace Halcon;  
#include "halconcpp.h"
using namespace Halcon;

注意,如果你安裝的Halcon版本是11.0.0.1的話,實際上這個版本仍然和Halcon10一樣,使用的是Halcon名稱空間,而不是HalconCpp。

第十步:我們在HalconFirstStepDlg.cpp檔案中,新增一個全域性變數來儲存開啟的圖片。

[cpp] view plain copy print?
  1. Hobject img;  
Hobject img;

第十一步:新增讀取圖片按鈕的響應程式碼,我們雙擊對話方塊中的”載入圖片“按鈕,新增下面的程式碼: [cpp] view plain copy print?
  1. void CHalconFisrtStepDlg::OnBnClickedButton1()  
  2. {  
  3.     //獲取影象視窗父視窗控制代碼
  4.     CRect rect;  
  5.     HWND hwnd = GetDlgItem(IDC_STATIC1)->m_hWnd;  
  6.     GetDlgItem(IDC_STATIC1)->GetWindowRect(&rect);  
  7.     //開啟影象視窗
  8.     Hlong windowId;  
  9.     open_window(0,0,rect.Width(),rect.Height(),(Hlong)hwnd,"visible","",&windowId);  
  10.     //將影象讀入記憶體
  11.     read_image(&img,"mreut");  
  12.     //獲取影象大小
  13.     HTuple width,height;  
  14.     get_image_size(img,&width,&height);  
  15.     //按照比例縮放到影象視窗
  16.     set_part(windowId,0,0,width,height);  
  17.     //顯示影象
  18.     disp_obj(img,windowId);  
  19. }  
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?
  1. void CHalconFisrtStepDlg::OnBnClickedButton2()  
  2. {  
  3.     //獲取影象視窗父視窗控制代碼
  4.     CRect rect;  
  5.     HWND hwnd = GetDlgItem(IDC_STATIC2)->m_hWnd;  
  6.     GetDlgItem(IDC_STATIC2)->GetWindowRect(&rect);  
  7.     //開啟影象視窗
  8.     Hlong windowId;  
  9.     open_window(0,0,rect.Width(),rect.Height(),(Hlong)hwnd,"visible","",&windowId);  
  10.     //獲取影象大小
  11.     HTuple width,height;  
  12.     get_image_size(img,&width,&height);  
  13.     //按照比例縮放到影象視窗
  14.     set_part(windowId,0,0,width,height);  
  15.     //顯示影象
  16.     disp_obj(img,windowId);  
  17.     Hobject BrightRegion,ConnectedRegion,SelectedRegion;  
  18.     //將影象二值化,設定閾值下限為180,上限為255
  19.     threshold(img,&BrightRegion,188,255);  
  20.     //連通閾值範圍內明亮區域
  21.     connection(BrightRegion,&ConnectedRegion);  
  22.     //選擇連通區域內面積最大的區域
  23.     select_shape_std(ConnectedRegion,&SelectedRegion,"max_area",0);  
  24.     //設定選擇區域的顏色為紅色
  25.     set_color(windowId,"red");  
  26.     //顯示選擇區域
  27.     disp_obj(SelectedRegion,windowId);    
  28. }  
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編寫演算法的那些演算法工程師和數學家,感謝他們為我們提供了一個這麼智慧的視覺開發包。下圖是程式執行效果。

要轉載本文,請註明出處,尊重智慧財產權。