C#調(diào)用NI的庫函數(shù)實(shí)現(xiàn)顏色識(shí)別檢測(cè)(在halcon環(huán)境下)
一直使用C#+halcon進(jìn)行視覺算法的開發(fā),但是遇到了一個(gè)非常普遍的需求,對(duì)物體進(jìn)行顏色識(shí)別。在halcon中顏色識(shí)別主要分兩種方式,一種為進(jìn)行色域轉(zhuǎn)化,由RGB轉(zhuǎn)換為HSV后根據(jù)顏色表在H或者其他通道中對(duì)不同的顏色值進(jìn)行區(qū)分,此種方式缺點(diǎn)是在進(jìn)行建模時(shí)必須知道目標(biāo)ROI的H通道值,且與其他ROI的值差別較大,不然非常容易誤報(bào)。另一種方法即建立分類器,使用mlp或者gmm進(jìn)行訓(xùn)練,然后將要識(shí)別的區(qū)域給分類器讓其判斷,這其中有一個(gè)缺點(diǎn)為,在建立分類器時(shí)必須知道當(dāng)前有幾種顏色,然后建立起對(duì)應(yīng)輸出的分類器,并且再有樣本添加進(jìn)入時(shí)也必須按同時(shí)將這幾種顏色都加入進(jìn)去(即使當(dāng)前狀態(tài)只有一種顏色出現(xiàn)差異需要再訓(xùn)練),同時(shí),也不能再追加一種新的顏色。
在LabView的Vision模塊中,有直接的顏色匹配模式,即將選定的ROI區(qū)域劃分為16個(gè)向量再與檢測(cè)的ROI作比較,識(shí)別較為準(zhǔn)確。故本文介紹在C#環(huán)境下調(diào)用LV中的顏色識(shí)別函數(shù),顯示窗口依然使用halcon的HWindowControl(畢竟主要的開發(fā)算法還是在halcon下寫的,并且個(gè)人感覺LV的圖像顯示窗口做的并不好,雜亂?。?。
首先,調(diào)用LV需要先安裝labview并且安裝visionassistan模塊,安裝好后在其安裝路徑下有兩個(gè)dll,分別為NationlInstryments.Vision.dll和NationlInstryments.Vision.Common.dll,同時(shí)引用halcondonet.dll(halcon的dll),找不到在哪的可以使用軟件everything進(jìn)行搜索。在自己的工程中引用這兩個(gè)dll,同時(shí)引用namespace,添加halcon圖像顯示窗口,使用該文章中https://blog.csdn.net/qizijuesha/article/details/77400312的封裝后的顯示窗口:
usingNationalInstrumens.Vision
usingNationInstruments.Vision.Analysis;
usingHalconDotNet;
下面上代碼:
privateVisionImagemyVisionImage=newVisionImage();//VisionImage作為LV庫函數(shù)中的圖像輸入
//從本地讀取圖像
privatevoidbuttonReadImage_Click(objectsender,EventArgse)
{
ImagePreviewFileDialogimageDialog=newImagePreviewFileDialog();
imageDialog.InitialDirectory="D:\\";
imageDialog.Filter="AllFiles(*.*)";
if(imageDialog.ShowDialog()==DialogResult.OK)
{
stringimagePath=imageDialog.FileName;
LoadSelectedImage(imagePath);//使用LV讀取圖像
}
}
privatevoidLoadSelectedImage(stringimagePath)
{
myVisionImage.ReadFile(imagePath);
myVisionImage.Type=ImageType.Rgb32;//次句一定要加上,不然在進(jìn)行識(shí)別時(shí)報(bào)錯(cuò),默認(rèn)讀取進(jìn)入后是U8單通道格式
}
在halcon窗口上進(jìn)行roi的劃定
privateHObjectGetModelDrawRegion(HObjectdrawImage,refHTuplehv_Row1,refHTuplehv_Column1,refHTuplehv_Row2,refHTuplehv_Column2)
{
HObjectho_ModelRegion,ho_TemplateImage,ho_RegionSelect,ho_RegionUnion,ho_RegionModel;
HObjectho_ModelContours,ho_TransContours=null;
HTuplehv_TempHomMat2D=newHTuple();
HTuplehv_HomMat=newHTuple();
//初始化本地變量值
HOperatorSet.GenEmptyObj(outho_ModelRegion);
HOperatorSet.GenEmptyObj(outho_TemplateImage);
HOperatorSet.GenEmptyObj(outho_ModelContours);
HOperatorSet.GenEmptyObj(outho_TransContours);
HOperatorSet.GenEmptyObj(outho_RegionSelect);
HOperatorSet.GenEmptyObj(outho_RegionUnion);
HOperatorSet.GenEmptyObj(outho_RegionModel);
try
{
HObjectho_temp_brush=newHObject();
hWindow_Final1.DrawModel=true;//縮放功能禁用
HOperatorSet.SetSystem("border_shape_models","false");
ho_ModelRegion.Dispose();
HalconToolClass.set_display_font(hWindow_Final1.hWindowControl.HalconWindow,10,"mono",newHTuple("true"),newHTuple("false"));
HalconToolClass.disp_message(hWindow_Final1.hWindowControl.HalconWindow,"在窗口中將MARK1點(diǎn)位置框出,點(diǎn)擊右鍵完成","window",20,20,"red","false");
hWindow_Final1.Focus();
HOperatorSet.SetColor(hWindow_Final1.hWindowControl.HalconWindow,"red");
HOperatorSet.DrawRectangle1(hWindow_Final1.hWindowControl.HalconWindow,outhv_Row1,outhv_Column1,outhv_Row2,outhv_Column2);
HOperatorSet.GenRectangle1(outho_ModelRegion,hv_Row1,hv_Column1,hv_Row2,hv_Column2);
hWindow_Final1.DrawModel=false;
if(hv_Row1.D!=0)
{
brush_region.Dispose();
brush_region=ho_ModelRegion;
}
else
{
hWindow_Final1.HobjectToHimage(drawImage);
HalconToolClass.set_display_font(hWindow_Final1.hWindowControl.HalconWindow,20,"mono",newHTuple("true"),newHTuple("false"));
HalconToolClass.disp_message(hWindow_Final1.hWindowControl.HalconWindow,"未畫出有效區(qū)域","window",20,20,"red","false");
}
HalconToolClass.set_display_font(hWindow_Final1.hWindowControl.HalconWindow,20,"mono",newHTuple("true"),newHTuple("false"));
hWindow_Final1.DispObj(ho_ModelRegion,"yellow");
ho_TemplateImage.Dispose();
HOperatorSet.ReduceDomain(drawImage,ho_ModelRegion,outho_TemplateImage);
}
catch
{
MessageBox.Show("劃定模板框出錯(cuò)!");
}
finally
{
ho_ModelRegion.Dispose();
}
returnho_TemplateImage;
}
劃定好ROI后進(jìn)行顏色的學(xué)習(xí),并將學(xué)習(xí)完畢的顏色向量存入數(shù)據(jù)庫
privatevoidbuttonRecColor_Click(objectsender,EventArgse)
{
HTuplehv_Row1=null,hv_Column1=null,hv_Row2=null,hv_Column2=null;
HObjectho_ModelRegion;
ho_ModelRegion=GetModelDrawRegion(halconImage,refhv_Row1,refhv_Column1,refhv_Row2,refhv_Column2);
double[]lvRoi=ConvertHalconToLV(hv_Row1,hv_Column1,hv_Row2,hv_Column2);//在halcon中矩形的存儲(chǔ)為左上行列坐標(biāo),右下行列坐標(biāo);
//而在LV中,矩形存儲(chǔ)方式為中心行列坐標(biāo),weight和height長
//查詢插入語言
sqlCommand="INSERTINTOroi_rec_inf(id,left_top_row,left_top_column,right_bottom_row,right_bottom_column)SELECT(SELECTMAX(id)FROMroi_rec_inf)+1,'"+hv_Row1+"','"+hv_Column1+"','"+hv_Row2+"','"+hv_Column2+"';";
mySqlClass.UsualSqlCommand(sqlCommand);
RectangleContourrectangle=newRectangleContour(lvRoi[0],lvRoi[1],lvRoi[2],lvRoi[3]);//矩形
RoirectangleRoi=rectangle.ConvertToRoi();
//該函數(shù)為調(diào)用的LV中學(xué)習(xí)顏色的函數(shù),ROI使用halcon窗口中畫出的ROI,若此時(shí)不存入數(shù)據(jù)庫,也可直接使用colorInformation進(jìn)行顏色識(shí)別
ColorInformationcolorInformation=Algorithms.LearnColor(myVisionImage,rectangleRoi,ColorSensitivity.Low,(int)80);
sqlCommand=@"INSERTINTOcolor_match(
rec_id,color1,color2,color3,color4,color5,color6,color7,color8,color9,color10,color11,color12,color13,color14,color15,color16)
SELECT(SELECTMAX(id)fromroi_rec_inf),
'"+colorInformation.Information[0]+"','"+colorInformation.Information[1]+"','"+colorInformation.Information[2]+"','"+colorInformation.Information[3]+"','"+colorInformation.Information[4]+"','"+colorInformation.Information[5]+"','"+colorInformation.Information[6]+"','"+colorInformation.Information[7]+"','"+colorInformation.Information[8]+"','"+colorInformation.Information[9]+"','"+colorInformation.Information[10]+"','"+colorInformation.Information[11]+"','"+colorInformation.Information[12]+"','"+colorInformation.Information[13]+"','"+colorInformation.Information[14]+"','"+colorInformation.Information[15]+"'";
mySqlClass.UsualSqlCommand(sqlCommand);//插入顏色數(shù)據(jù)
}
privatedouble[]ConvertHalconToLV(HTuplehv_Row1,HTuplehv_Column1,HTuplehv_Row2,HTuplehv_Column2)
{
doublewidth=0,height=0;
if(hv_Row2>hv_Row1)
{
width=hv_Row2-hv_Row1;
}
if(hv_Column2>hv_Column1)
{
height=hv_Column2-hv_Column1;
}
double[]lvRoi={hv_Column1,hv_Row1,width,height};//需要傳出的左上橫縱坐標(biāo)及寬,長信息
returnlvRoi;
}
現(xiàn)在進(jìn)行圖像顏色識(shí)別,給定要識(shí)別的ROI區(qū)域及對(duì)應(yīng)的圖像和之前保存的顏色向量,函數(shù)返回匹配分值
privatevoidMatchColor(HObjectimageMatch)
{
VisionImagemyImage=newVisionImage();
myImage.Type=ImageType.Rgb32;
LoadSelectedImage("F:\\tempImage.jpeg",refmyImage);
double[]lvROI=ConvertHalconToLV(Convert.ToDouble(dtSelect.Rows[0]["left_top_row"].ToString()),Convert.ToDouble(dtSelect.Rows[0]["left_top_column"].ToString()),Convert.ToDouble(dtSelect.Rows[0]["right_bottom_row"].ToString()),Convert.ToDouble(dtSelect.Rows[0]["right_bottom_column"].ToString()));
RoirectangleRoi=newRoi(newRectangleContour(lvROI[0],lvROI[1],lvROI[2],lvROI[3]));//矩形
qlCommand="SELECTcolor1,color2,color3,color4,color5,color6,color7,color8,color9,color10,color11,color12,color13,color14,color15,color16FROMcolor_matchWHERErec_id='"+Convert.ToInt32(dtSelect.Rows[0]["id"].ToString())+"';";
DataTabledtColor=mySqlClass.SelectDataUsual(sqlCommand);
double[]colorValue=DTConvertToDouble(dtColor);
ColorInformationmyColorInformation=newColorInformation(newCollection<double>(colorValue));
Collection<int>scores=Algorithms.MatchColor(myImage,myColorInformation,rectangleRoi);
if(scores[0]<700)
{
DoNGSomething(Convert.ToInt32(dtSelect.Rows[0]["id"].ToString()));
richTextBox1.Text="NG";
}
else
{
DoOKSomething(Convert.ToInt32(dtSelect.Rows[0]["id"].ToString()));
richTextBox1.Text="OK";
}
}
總結(jié):
先在halcon窗口上劃定ROI區(qū)域,將此ROI轉(zhuǎn)換為LV中Roi類型,然后調(diào)用ColorInformation=Algorithms.LearnColor(image,roi,low,threshold)方法,該函數(shù)返回16行向量值ColorInformation即為該區(qū)域的顏色分布
給定ROI區(qū)域(同樣在halcon中劃定并進(jìn)行轉(zhuǎn)換),調(diào)用Algorithms.MatchColor(image,ColorInformation,roi)進(jìn)行指定區(qū)域的顏色識(shí)別,該方法返回一個(gè)匹配分值
在給定image值時(shí),一定要將其typeImage類型設(shè)定為RGB32