C#呼叫NI的庫函式實現顏色識別檢測(在halcon環境下)
一直使用C#+halcon進行視覺演算法的開發,但是遇到了一個非常普遍的需求,對物體進行顏色識別。在halcon中顏色識別主要分兩種方式,一種為進行色域轉化,由RGB轉換為HSV後根據顏色表在H或者其他通道中對不同的顏色值進行區分,此種方式缺點是在進行建模時必須知道目標ROI的H通道值,且與其他ROI的值差別較大,不然非常容易誤報。另一種方法即建立分類器,使用mlp或者gmm進行訓練,然後將要識別的區域給分類器讓其判斷,這其中有一個缺點為,在建立分類器時必須知道當前有幾種顏色,然後建立起對應輸出的分類器,並且再有樣本新增進入時也必須按同時將這幾種顏色都加入進去(即使當前狀態只有一種顏色出現差異需要再訓練),同時,也不能再追加一種新的顏色。
在LabView的Vision模組中,有直接的顏色匹配模式,即將選定的ROI區域劃分為16個向量再與檢測的ROI作比較,識別較為準確。故本文介紹在C#環境下呼叫LV中的顏色識別函式,顯示視窗依然使用halcon的HWindowControl(畢竟主要的開發演算法還是在halcon下寫的,並且個人感覺LV的影象顯示視窗做的並不好,雜亂!)。
首先,呼叫LV需要先安裝labview並且安裝vision assistan模組,安裝好後在其安裝路徑下有兩個dll,分別為NationlInstryments.Vision.dll 和 NationlInstryments.Vision.Common.dll,同時引用halcondonet.dll(halcon的dll),找不到在哪的可以使用軟體everything進行搜尋。在自己的工程中引用這兩個dll,同時引用namespace,新增halcon影象顯示視窗,使用該文章中https://blog.csdn.net/qizijuesha/article/details/77400312的封裝後的顯示視窗 :
using NationalInstrumens.Vision
using NationInstruments.Vision.Analysis;
using HalconDotNet;
下面上程式碼:
private VisionImage myVisionImage = new VisionImage(); // VisionImage作為LV庫函式中的影象輸入
// 從本地讀取影象
private void buttonReadImage_Click(object sender, EventArgs e)
{
ImagePreviewFileDialog imageDialog = new ImagePreviewFileDialog();
imageDialog.InitialDirectory = "D:\\";
imageDialog.Filter = "All Files(*.*)";
if (imageDialog.ShowDialog() == DialogResult.OK)
string imagePath = imageDialog.FileName;
LoadSelectedImage(imagePath); // 使用LV讀取影象
}
private void LoadSelectedImage(string imagePath)
myVisionImage.ReadFile(imagePath);
myVisionImage.Type = ImageType.Rgb32; // 次句一定要加上,不然在進行識別時報錯,預設讀取進入後是U8單通道格式
在halcon視窗上進行roi的劃定
private HObject GetModelDrawRegion(HObject drawImage, ref HTuple hv_Row1, ref HTuple hv_Column1, ref HTuple hv_Row2, ref HTuple hv_Column2)
HObject ho_ModelRegion, ho_TemplateImage, ho_RegionSelect, ho_RegionUnion, ho_RegionModel;
HObject ho_ModelContours, ho_TransContours = null;
HTuple hv_TempHomMat2D = new HTuple();
HTuple hv_HomMat = new HTuple();
// 初始化本地變數值
HOperatorSet.GenEmptyObj(out ho_ModelRegion);
HOperatorSet.GenEmptyObj(out ho_TemplateImage);
HOperatorSet.GenEmptyObj(out ho_ModelContours);
HOperatorSet.GenEmptyObj(out ho_TransContours);
HOperatorSet.GenEmptyObj(out ho_RegionSelect);
HOperatorSet.GenEmptyObj(out ho_RegionUnion);
HOperatorSet.GenEmptyObj(out ho_RegionModel);
try
HObject ho_temp_brush = new HObject();
hWindow_Final1.DrawModel = true; // 縮放功能禁用
HOperatorSet.SetSystem("border_shape_models", "false");
ho_ModelRegion.Dispose();
HalconToolClass.set_display_font(hWindow_Final1.hWindowControl.HalconWindow, 10, "mono", new HTuple("true"), new HTuple("false"));
HalconToolClass.disp_message(hWindow_Final1.hWindowControl.HalconWindow, "在視窗中將MARK1點位置框出,點選右鍵完成", "window", 20, 20, "red", "false");
hWindow_Final1.Focus();
HOperatorSet.SetColor(hWindow_Final1.hWindowControl.HalconWindow, "red");
HOperatorSet.DrawRectangle1(hWindow_Final1.hWindowControl.HalconWindow, out hv_Row1, out hv_Column1, out hv_Row2, out hv_Column2);
HOperatorSet.GenRectangle1(out ho_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", new HTuple("true"), new HTuple("false"));
HalconToolClass.disp_message(hWindow_Final1.hWindowControl.HalconWindow, "未畫出有效區域", "window", 20, 20, "red", "false");
hWindow_Final1.DispObj(ho_ModelRegion, "yellow");
ho_TemplateImage.Dispose();
HOperatorSet.ReduceDomain(drawImage, ho_ModelRegion, out ho_TemplateImage);
catch
MessageBox.Show("劃定模板框出錯!");
finally
return ho_TemplateImage;
劃定好ROI後進行顏色的學習,並將學習完畢的顏色向量存入資料庫
private void buttonRecColor_Click(object sender, EventArgs e)
HTuple hv_Row1 = null, hv_Column1 = null, hv_Row2 = null, hv_Column2 = null;
HObject ho_ModelRegion;
ho_ModelRegion = GetModelDrawRegion(halconImage, ref hv_Row1, ref hv_Column1, ref hv_Row2, ref hv_Column2);
double []lvRoi = ConvertHalconToLV(hv_Row1, hv_Column1, hv_Row2, hv_Column2); // 在halcon中矩形的儲存為左上行列座標,右下行列座標;
// 而在LV中,矩形儲存方式為中心行列座標,weight和height長
// 查詢插入語言
sqlCommand = "INSERT INTO roi_rec_inf(id, left_top_row, left_top_column, right_bottom_row, right_bottom_column) SELECT (SELECT MAX(id) FROM roi_rec_inf)+1, "" + hv_Row1 + "", "" + hv_Column1 + "", "" + hv_Row2 + "", "" + hv_Column2 + "";";
mySqlClass.UsualSqlCommand(sqlCommand);
RectangleContour rectangle = new RectangleContour(lvRoi[0], lvRoi[1], lvRoi[2], lvRoi[3]); // 矩形
Roi rectangleRoi = rectangle.ConvertToRoi();
// 該函式為呼叫的LV中學習顏色的函式,ROI使用halcon視窗中畫出的ROI,若此時不存入資料庫,也可直接使用colorInformation進行顏色識別
ColorInformation colorInformation = Algorithms.LearnColor(myVisionImage, rectangleRoi, ColorSensitivity.Low, (int)80);
sqlCommand = @"INSERT INTO color_match(
rec_id, color1, color2, color3, color4, color5, color6, color7, color8, color9, color10, color11, color12, color13, color14, color15, color16)
SELECT (SELECT MAX(id) from roi_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); // 插入顏色資料
private double[] ConvertHalconToLV(HTuple hv_Row1, HTuple hv_Column1, HTuple hv_Row2, HTuple hv_Column2)
double width = 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 };// 需要傳出的左上橫縱座標及寬,長資訊
return lvRoi;
現在進行影象顏色識別,給定要識別的ROI區域及對應的影象和之前儲存的顏色向量,函式返回匹配分值
private void MatchColor(HObject imageMatch)
VisionImage myImage = new VisionImage();
myImage.Type = ImageType.Rgb32;
LoadSelectedImage("F:\\tempImage.jpeg", ref myImage);
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()));
Roi rectangleRoi = new Roi(new RectangleContour(lvROI[0], lvROI[1], lvROI[2], lvROI[3])); // 矩形
qlCommand = "SELECT color1, color2, color3, color4, color5, color6, color7, color8, color9, color10, color11, color12, color13, color14, color15, color16 FROM color_match WHERE rec_id = "" + Convert.ToInt32(dtSelect.Rows[0]["id"].ToString()) + "";";
DataTable dtColor = mySqlClass.SelectDataUsual(sqlCommand);
double []colorValue = DTConvertToDouble(dtColor);
ColorInformation myColorInformation = new ColorInformation(new Collection<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";
DoOKSomething(Convert.ToInt32(dtSelect.Rows[0]["id"].ToString()));
richTextBox1.Text = "OK";
總結:
先在halcon視窗上劃定ROI區域,將此ROI轉換為LV中Roi型別,然後呼叫ColorInformation = Algorithms.LearnColor(image,roi,low,threshold)方法,該函式返回16行向量值 ColorInformation即為該區域的顏色分佈
給定ROI區域(同樣在halcon中劃定並進行轉換),呼叫Algorithms.MatchColor(image, ColorInformation, roi)進行指定區域的顏色識別,該方法返回一個匹配分值
在給定image值時,一定要將其typeImage型別設定為RGB32
C#呼叫NI的庫函式實現顏色識別檢測(在halcon環境下)
一直使用C#+halcon進行視覺演算法的開發,但是遇到了一個非常普遍的需求,對物體進行顏色識別。在halcon中顏色識別主要分兩種方式,一種為進行色域轉化,由RGB轉換為HSV後根據顏色表在H或者其他通道中對不同的顏色值進行區分,此種方式缺點是在進行建模時必須知道目標ROI的H通道值,且與其他ROI的值差別較大,不然非常容易誤報。另一種方法即建立分類器,使用mlp或者gmm進行訓練,然後將要識別的區域給分類器讓其判斷,這其中有一個缺點為,在建立分類器時必須知道當前有幾種顏色,然後建立起對應輸出的分類器,並且再有樣本新增進入時也必須按同時將這幾種顏色都加入進去(即使當前狀態只有一種顏色出現差異需要再訓練),同時,也不能再追加一種新的顏色。
在LabView的Vision模組中,有直接的顏色匹配模式,即將選定的ROI區域劃分為16個向量再與檢測的ROI作比較,識別較為準確。故本文介紹在C#環境下呼叫LV中的顏色識別函式,顯示視窗依然使用halcon的HWindowControl(畢竟主要的開發演算法還是在halcon下寫的,並且個人感覺LV的影象顯示視窗做的並不好,雜亂!)。
首先,呼叫LV需要先安裝labview並且安裝vision assistan模組,安裝好後在其安裝路徑下有兩個dll,分別為NationlInstryments.Vision.dll 和 NationlInstryments.Vision.Common.dll,同時引用halcondonet.dll(halcon的dll),找不到在哪的可以使用軟體everything進行搜尋。在自己的工程中引用這兩個dll,同時引用namespace,新增halcon影象顯示視窗,使用該文章中https://blog.csdn.net/qizijuesha/article/details/77400312的封裝後的顯示視窗 :
using NationalInstrumens.Vision
using NationInstruments.Vision.Analysis;
using HalconDotNet;
下面上程式碼:
private VisionImage myVisionImage = new VisionImage(); // VisionImage作為LV庫函式中的影象輸入
// 從本地讀取影象
private void buttonReadImage_Click(object sender, EventArgs e)
{
ImagePreviewFileDialog imageDialog = new ImagePreviewFileDialog();
imageDialog.InitialDirectory = "D:\\";
imageDialog.Filter = "All Files(*.*)";
if (imageDialog.ShowDialog() == DialogResult.OK)
{
string imagePath = imageDialog.FileName;
LoadSelectedImage(imagePath); // 使用LV讀取影象
}
}
private void LoadSelectedImage(string imagePath)
{
myVisionImage.ReadFile(imagePath);
myVisionImage.Type = ImageType.Rgb32; // 次句一定要加上,不然在進行識別時報錯,預設讀取進入後是U8單通道格式
}
在halcon視窗上進行roi的劃定
private HObject GetModelDrawRegion(HObject drawImage, ref HTuple hv_Row1, ref HTuple hv_Column1, ref HTuple hv_Row2, ref HTuple hv_Column2)
{
HObject ho_ModelRegion, ho_TemplateImage, ho_RegionSelect, ho_RegionUnion, ho_RegionModel;
HObject ho_ModelContours, ho_TransContours = null;
HTuple hv_TempHomMat2D = new HTuple();
HTuple hv_HomMat = new HTuple();
// 初始化本地變數值
HOperatorSet.GenEmptyObj(out ho_ModelRegion);
HOperatorSet.GenEmptyObj(out ho_TemplateImage);
HOperatorSet.GenEmptyObj(out ho_ModelContours);
HOperatorSet.GenEmptyObj(out ho_TransContours);
HOperatorSet.GenEmptyObj(out ho_RegionSelect);
HOperatorSet.GenEmptyObj(out ho_RegionUnion);
HOperatorSet.GenEmptyObj(out ho_RegionModel);
try
{
HObject ho_temp_brush = new HObject();
hWindow_Final1.DrawModel = true; // 縮放功能禁用
HOperatorSet.SetSystem("border_shape_models", "false");
ho_ModelRegion.Dispose();
HalconToolClass.set_display_font(hWindow_Final1.hWindowControl.HalconWindow, 10, "mono", new HTuple("true"), new HTuple("false"));
HalconToolClass.disp_message(hWindow_Final1.hWindowControl.HalconWindow, "在視窗中將MARK1點位置框出,點選右鍵完成", "window", 20, 20, "red", "false");
hWindow_Final1.Focus();
HOperatorSet.SetColor(hWindow_Final1.hWindowControl.HalconWindow, "red");
HOperatorSet.DrawRectangle1(hWindow_Final1.hWindowControl.HalconWindow, out hv_Row1, out hv_Column1, out hv_Row2, out hv_Column2);
HOperatorSet.GenRectangle1(out ho_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", new HTuple("true"), new HTuple("false"));
HalconToolClass.disp_message(hWindow_Final1.hWindowControl.HalconWindow, "未畫出有效區域", "window", 20, 20, "red", "false");
}
HalconToolClass.set_display_font(hWindow_Final1.hWindowControl.HalconWindow, 20, "mono", new HTuple("true"), new HTuple("false"));
hWindow_Final1.DispObj(ho_ModelRegion, "yellow");
ho_TemplateImage.Dispose();
HOperatorSet.ReduceDomain(drawImage, ho_ModelRegion, out ho_TemplateImage);
}
catch
{
MessageBox.Show("劃定模板框出錯!");
}
finally
{
ho_ModelRegion.Dispose();
}
return ho_TemplateImage;
}
劃定好ROI後進行顏色的學習,並將學習完畢的顏色向量存入資料庫
private void buttonRecColor_Click(object sender, EventArgs e)
{
HTuple hv_Row1 = null, hv_Column1 = null, hv_Row2 = null, hv_Column2 = null;
HObject ho_ModelRegion;
ho_ModelRegion = GetModelDrawRegion(halconImage, ref hv_Row1, ref hv_Column1, ref hv_Row2, ref hv_Column2);
double []lvRoi = ConvertHalconToLV(hv_Row1, hv_Column1, hv_Row2, hv_Column2); // 在halcon中矩形的儲存為左上行列座標,右下行列座標;
// 而在LV中,矩形儲存方式為中心行列座標,weight和height長
// 查詢插入語言
sqlCommand = "INSERT INTO roi_rec_inf(id, left_top_row, left_top_column, right_bottom_row, right_bottom_column) SELECT (SELECT MAX(id) FROM roi_rec_inf)+1, "" + hv_Row1 + "", "" + hv_Column1 + "", "" + hv_Row2 + "", "" + hv_Column2 + "";";
mySqlClass.UsualSqlCommand(sqlCommand);
RectangleContour rectangle = new RectangleContour(lvRoi[0], lvRoi[1], lvRoi[2], lvRoi[3]); // 矩形
Roi rectangleRoi = rectangle.ConvertToRoi();
// 該函式為呼叫的LV中學習顏色的函式,ROI使用halcon視窗中畫出的ROI,若此時不存入資料庫,也可直接使用colorInformation進行顏色識別
ColorInformation colorInformation = Algorithms.LearnColor(myVisionImage, rectangleRoi, ColorSensitivity.Low, (int)80);
sqlCommand = @"INSERT INTO color_match(
rec_id, color1, color2, color3, color4, color5, color6, color7, color8, color9, color10, color11, color12, color13, color14, color15, color16)
SELECT (SELECT MAX(id) from roi_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); // 插入顏色資料
}
private double[] ConvertHalconToLV(HTuple hv_Row1, HTuple hv_Column1, HTuple hv_Row2, HTuple hv_Column2)
{
double width = 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 };// 需要傳出的左上橫縱座標及寬,長資訊
return lvRoi;
}
現在進行影象顏色識別,給定要識別的ROI區域及對應的影象和之前儲存的顏色向量,函式返回匹配分值
private void MatchColor(HObject imageMatch)
{
VisionImage myImage = new VisionImage();
myImage.Type = ImageType.Rgb32;
LoadSelectedImage("F:\\tempImage.jpeg", ref myImage);
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()));
Roi rectangleRoi = new Roi(new RectangleContour(lvROI[0], lvROI[1], lvROI[2], lvROI[3])); // 矩形
qlCommand = "SELECT color1, color2, color3, color4, color5, color6, color7, color8, color9, color10, color11, color12, color13, color14, color15, color16 FROM color_match WHERE rec_id = "" + Convert.ToInt32(dtSelect.Rows[0]["id"].ToString()) + "";";
DataTable dtColor = mySqlClass.SelectDataUsual(sqlCommand);
double []colorValue = DTConvertToDouble(dtColor);
ColorInformation myColorInformation = new ColorInformation(new Collection<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";
}
}
總結:
先在halcon視窗上劃定ROI區域,將此ROI轉換為LV中Roi型別,然後呼叫ColorInformation = Algorithms.LearnColor(image,roi,low,threshold)方法,該函式返回16行向量值 ColorInformation即為該區域的顏色分佈
給定ROI區域(同樣在halcon中劃定並進行轉換),呼叫Algorithms.MatchColor(image, ColorInformation, roi)進行指定區域的顏色識別,該方法返回一個匹配分值
在給定image值時,一定要將其typeImage型別設定為RGB32