基于Halcon深度学习之分类
*****
***环境准备***
***系统:win7以上系统
***显卡:算力3.0以上
***显卡驱动:10.1以上版本(nvidia-smi查看指令)***读取深度学习模型***
read_dl_model ('pretrained_dl_classifier_compact.hdl', DLModelHandle)
***获取模型中的图象张量及对应的灰度值范围
get_dl_model_param (DLModelHandle, 'image_width', ImgWidth)
get_dl_model_param (DLModelHandle, 'image_height', ImgHeight)
get_dl_model_param (DLModelHandle, 'image_num_channels', ImgChannel)
get_dl_model_param (DLModelHandle, 'image_range_min', ImgRangMin)
get_dl_model_param (DLModelHandle, 'image_range_max', ImgRangMax)************预处理数据准备及拆分**********
classNames := ['1-2','1-3','1-4','2-4','3-5','4-7','5-6']
rawImageFolders := '../images/' + classNames
***把原图像数据转换为对应的Dataset格式***
read_dl_dataset_classification (rawImageFolders, 'last_folder', DLDataset)
***对数据集进行拆分***
trainPrecent := 60 // 用于训练的比例
validdatatPrecent := 20 // 用于测试的比例
GenSplitParam := dict{overwrite_split:'true'}
split_dl_dataset (DLDataset, trainPrecent, validdatatPrecent, GenSplitParam)
***预处理数据***
*1、创建预处理参数
** 预处理数据存储路径
processFolder := 'ProcessData'
** 定义预处理参数文件路径
dlProcessFileName := processFolder + '/dl_preprocess_param.hdict'
** 检查文件是否存在
file_exists (processFolder, FileExists)
if(not FileExists)make_dir (processFolder)
endif
** 创建预处理参数
create_dl_preprocess_param ('classification', ImgWidth, ImgHeight, ImgChannel, \ImgRangMin, ImgRangMax, 'none', 'full_domain',\[], [], [], [], DLPreprocessParam)
** 对数据进行预处理
GenParam := dict{overwrite_files:'true'}
preprocess_dl_dataset (DLDataset, processFolder, DLPreprocessParam, \GenParam, DLDatasetFileName)
** 保存预处理参数文件
write_dict (DLPreprocessParam, dlProcessFileName, [], [])************使用预处理数据对模型进行训练************
** 总周期(所有图片训练一次为一个周期)
numEpochs := 100
** 批次数(一个周期本分割的份数)
batchSize := 5
** 评估周期(每训练几个周期进行一次评估)
evluationIntervalEphochs := 2
** 学习率
learningRate := 0.001
**** 设置模型参数
set_dl_model_param(DLModelHandle, 'class_names', classNames)
set_dl_model_param(DLModelHandle, 'image_dimensions', [ImgWidth,ImgHeight,ImgChannel])
set_dl_model_param(DLModelHandle, 'learning_rate', learningRate)
set_dl_model_param (DLModelHandle, 'batch_size', batchSize)
** 设置增强参数
GenParamName := []
GenParamValue := []
** 定义参数字典,增强参数
augmentParam := dict{}
augmentParam.augmentation_percentage := 100
augmentParam.mirror := 'rc'
GenParamName := [GenParamName,'augment']
GenParamValue := [GenParamValue,augmentParam]** 定义存储最佳模型路径和最终模型路径
augmentBest := dict{}
augmentBest.type := 'best'
augmentBest.basename := processFolder + '/model_best'
GenParamName := [GenParamName,'serialize']
GenParamValue := [GenParamValue,augmentBest]augmentFinal := dict{}
augmentFinal.type := 'final'
augmentFinal.basename := processFolder + '/model_final'
GenParamName := [GenParamName,'serialize']
GenParamValue := [GenParamValue,augmentFinal]
** 创建训练参数及执行训练
create_dl_train_param (DLModelHandle, numEpochs, evluationIntervalEphochs, \'true', 32, GenParamName, GenParamValue, TrainParam)
** 执行模型训练
train_dl_model (DLDataset, DLModelHandle, TrainParam, 0,\TrainResults, TrainInfos, EvaluationInfos)
** 释放资源
clear_dl_model (DLModelHandle)
** 关闭训练窗口
stop()
dev_close_window()
dev_close_window()***********模型评估***********
** 定义评估模型文件路径
retainModelFile := processFolder + '/model_best.hdl'
** 读取训练后的模型
read_dl_model (retainModelFile, RetainDLModelHandle)
** 定义评估的指标
evaluateGenParam := ['f_score','recall','precision','absolute_confusion_matrix',\'relative_confusion_matrix']
evaluateDict := dict{measures:evaluateGenParam}
** 执行模型评估
evaluate_dl_model(DLDataset, RetainDLModelHandle, 'split', 'test', \evaluateDict, EvaluationResult, EvalParams)
** 显示评估结果
GenDispParam := dict{}
GenDispParam.display_mode := ['measures','pie_charts_recall','pie_charts_precision',\'absolute_confusion_matrix','relative_confusion_matrix']
WindowHandleDict := dict{}
dev_display_classification_evaluation(EvaluationResult, EvalParams,\GenDispParam, WindowHandleDict)
stop()
dev_close_window_dict(WindowHandleDict)***********模型推断***********
** 读取推断数据
list_image_files('../test_image','bmp',[],ImageFiles)
** 读取预处理参数
read_dict(dlProcessFileName,[],[],DLPreprocessParam)
** 设置显示字体大小
dev_get_window(WindowHandle)
set_display_font(WindowHandle, 26, 'mono', 'true', 'false')
** 循环检测每一张图像
for Index :=0 to |ImageFiles| -1 by 1** 获取当前图像read_image(Image,ImageFiles[Index])** 生产样本图像gen_dl_samples_from_images(Image, DLSampleBatch)** 把推断图像处理成预处理图像数据preprocess_dl_samples(DLSampleBatch, DLPreprocessParam)** 使用模型进行推断类别apply_dl_model(RetainDLModelHandle, DLSampleBatch, [], DLResultBatch)** 评估结果显示className := DLResultBatch.classification_class_names[0]score := DLResultBatch.classification_confidences[0]** 显示图像上面dev_disp_text('类别:'+className+',分数:'+score, 'window',\'top', 'left', 'white', 'box_color', 'forest green')stop()
endforclear_dl_model(RetainDLModelHandle)
以上为halcon源码,联合C#编程操作界面
C#源码
/// <summary>/// 分类类别名称/// </summary>private HTuple classNames;/// <summary>/// 模型文件/// </summary>public string[] ModelFiles { get; private set; }#region 主界面相关事件public HomePage(){InitializeComponent();}private void HomePage_FormClosing(object sender, FormClosingEventArgs e){}private void HomePage_Load(object sender, System.EventArgs e){ // UI 显示日志ViewAppender viewAppender = new ViewAppender(dgvLog){Location = "",};LogCombiner.Ins.Append(viewAppender);// 初始化网络模型InitializeModels();// 模型评估默认参数// recallcbMetric.SelectedIndex = 0;// testcbSampleSelectValues.SelectedIndex = 0;}#endregion#region 设置HWindowControl控件的显示方式private void DispImage(HImage image, HWindow window){int imageWidth, imageHeight, winRow, winCol, winWidth, winHeight, partWidth, partHeight;try{image.GetImageSize(out imageWidth, out imageHeight);window.GetWindowExtents(out winRow, out winCol, out winWidth, out winHeight);if (winWidth > winHeight){partWidth = imageWidth;partHeight = imageWidth * winHeight / winWidth;}else{partWidth = imageHeight * winWidth / winHeight;partHeight = imageHeight;}// 设置显示图像在窗口中间var offsetX = (imageWidth - partWidth) / 2;var offsetY = (imageHeight - partHeight) / 2;// 设置窗口显示区域HOperatorSet.SetPart(window, offsetY, offsetX, partHeight + offsetY - 1, partWidth + offsetX - 1);// 显示图形HOperatorSet.DispObj(image, window);}catch (HalconException hEx){MessageBox.Show(hEx.Message);}}/// <summary>/// 把HObject转化为对应的HImage方法/// </summary>/// <param name="hObject"></param>/// <param name="image"></param>private HImage HObject2HImage(HObject hObject){HImage image = new HImage();// 获取当前传人对象的通道数【灰度/彩色】HOperatorSet.CountChannels(hObject, out var channels);if (channels.I == 0){return image;}// 判断通道数if (channels.I == 1){// 获取传人图形的数据HOperatorSet.GetImagePointer1(hObject,out var pointer, out var type, out var width, out var height);// 生成当通道图形image.GenImage1(type, width, height, pointer);}else{// 彩色图HOperatorSet.GetImagePointer3(hObject, out var pointerRed, out var pointerGreen,out var pointerBlue, out var type, out var width, out var height);image.GenImage3(type, width, height, pointerRed, pointerGreen, pointerBlue);}return image;}#endregion#region 加载模型文件选择下拉框private void InitializeModels(){// 获取项目编译路径ModelFiles = Directory.GetFiles(Path.Combine(Directory.GetCurrentDirectory(), "hdl"),"*.hdl");// 把模型文件添加至下拉框中foreach(string modelFile in ModelFiles){// 获取模型文件名string modelName = Path.GetFileNameWithoutExtension(modelFile);// 添加到下拉列表cbBackBone.Items.Add(modelName);}// 判断是否有模型文件if(ModelFiles.Length > 0){// 默认选择第一个文件cbBackBone.SelectedIndex = 0;Logger.Notify("model load finished .", "Preprocess");}else{// 如果没有模型文件,下拉框禁用cbBackBone.Enabled = false;Logger.Warn("model files not found .", "Preprocess");}}#endregion#region 读取模型参数private void cbBackBone_SelectedIndexChanged(object sender, EventArgs e){try{// 读取选择的网络模型文件string modelFile = ModelFiles[cbBackBone.SelectedIndex];// 加载模型 read_dl_modelHOperatorSet.ReadDlModel(modelFile, out var dLModelHandle);// 判断模型不为空if(dLModelHandle == null){Logger.Warn("read_dl_model failure .", "Preprocess");return;}// 读取模型张量数HOperatorSet.GetDlModelParam(dLModelHandle, "image_width", out HTuple imageWidth);HOperatorSet.GetDlModelParam(dLModelHandle, "image_height", out HTuple imageHeight);HOperatorSet.GetDlModelParam(dLModelHandle, "image_num_channels", out HTuple imageChannels);HOperatorSet.GetDlModelParam(dLModelHandle, "image_range_min", out HTuple imageRangMin);HOperatorSet.GetDlModelParam(dLModelHandle, "image_range_max", out HTuple imageRangMax);// 数据填充至对应文本框tbImgWidth.Text = imageWidth.ToString();tbImgHeight.Text = imageHeight.ToString();tbChannel.Text = imageChannels.ToString();tbGrayMin.Text = imageRangMin.ToString();tbGrayMax.Text = imageRangMax.ToString();// 释放加载的模型HOperatorSet.ClearDlModel(dLModelHandle);dLModelHandle.Dispose();dLModelHandle = null;}catch (Exception ex){Logger.Error(ex.Message, "Preprocess");}}#endregion#region 选择样本路径和存储路径private void btnSelectRawPath_Click(object sender, EventArgs e){using (FolderBrowserDialog dlg = new FolderBrowserDialog()){if (dlg.ShowDialog() == DialogResult.OK){// 重新创建,防止重复添加classNames = new HTuple();tbRawPath.Text = dlg.SelectedPath;// 获取选择文件夹下面的所有文件夹名称string[] folder = Directory.GetDirectories(tbRawPath.Text);// 把文件夹名添加到元组中foreach (var item in folder){classNames.Append(new DirectoryInfo(item).Name);}}}}private void btnSelectPrePath_Click(object sender, EventArgs e){using (FolderBrowserDialog dlg = new FolderBrowserDialog()){if (dlg.ShowDialog() == DialogResult.OK){tbPreStorPath.Text = dlg.SelectedPath;}}}#endregion#region 执行数据预处理操作private async void btnExecPreprocess_Click(object sender, EventArgs e){// 获取预处理对象var preprocess = Classification.ProcessAction;// 绑定更新方法preprocess.UpdateImageAction += Preprocess_UpdateImageAction; // 获取界面的参数var imageWith = Convert.ToInt32(tbImgWidth.Text);var imageHeight = Convert.ToInt32(tbImgHeight.Text);var imageNumChannels = Convert.ToInt32(tbChannel.Text);var imageRangeMin = Convert.ToInt32(tbGrayMin.Text);var imageRangeMax = Convert.ToInt32(tbGrayMax.Text);var backBoneFileName = ModelFiles[cbBackBone.SelectedIndex];var rawImagePath = tbRawPath.Text;var preprocessPath = tbPreStorPath.Text;// 设置到预处理对象属性中preprocess.ImageHeight = imageHeight;preprocess.ImageWidth = imageWith;preprocess.ImageNumChannels = imageNumChannels;preprocess.ImageRangeMin = imageRangeMin;preprocess.ImageRangeMax = imageRangeMax;preprocess.BackBonePath = backBoneFileName;preprocess.PreProcessPath = preprocessPath;preprocess.SamplesPath = rawImagePath;// 设置分类名称preprocess.ClassNames = classNames;// 界面显示信息HalconDLTool.set_display_font(hWinPre.HalconWindow, 20, "mono", "true", "false");// 调用预处理对象的预处理方法var res = await preprocess.ExecutePreProcess();// 判断执行结果if (res > 0){HOperatorSet.DispText(hWinPre.HalconWindow, "Preprocess finished .", "window", 12, 12, "white", "box_color", "forest green");Logger.Notify("Preprocess finished .", "Preprocess");}else{HOperatorSet.DispText(hWinPre.HalconWindow, "Preprocess failure .", "window", 12, 12, "white", "box_color", "red");Logger.Error("Preprocess failure .", "Preprocess");}}/// <summary>/// /// </summary>/// <param name="obj"></param>/// <exception cref="NotImplementedException"></exception>private void Preprocess_UpdateImageAction(HObject obj){try{if (obj != null){var hw = hWinPre.HalconWindow;hw.ClearWindow();hw.SetWindowParam("flush", "false");DispImage(HObject2HImage(obj), hw);hw.FlushBuffer();}}catch (Exception){throw;}}#endregion#region 选择训练的数据集文件private string SelectFile(string filter){using(OpenFileDialog dlg = new OpenFileDialog()){dlg.Filter = filter;if(dlg.ShowDialog() == DialogResult.OK){return dlg.FileName;}return null;}}private void btnSelectData_Click(object sender, EventArgs e){// 获取选择的数据集文件路径string datasetFile = SelectFile("Dataset(*.hdict)|*.hdict");// 把数据集路径存放至控件的Tag属性,并显示文件名称tbDataPath.Tag = datasetFile;if(datasetFile != null){// 将数据集名称显示至文本框tbDataPath.Text = Path.GetFileNameWithoutExtension(datasetFile);}// 获取当前文件所在的路径,模型文件也在当前目录下Classification.TrainingAction.ModelFilePath = Path.GetDirectoryName(datasetFile);}#endregion#region 执行模型训练private async void btnTrain_Click(object sender, EventArgs e){// 获取训练对象var training = Classification.TrainingAction;// 获取界面的数据var batchSize = Convert.ToInt32(tbBatchSize.Text);var learningRate = Convert.ToDouble(tbLearningRate.Text);var numEpochs = Convert.ToInt32(tbNumEpochs.Text);var evaluateNumEpochs = Convert.ToInt32(tbEvluationIntervalEphochs.Text);var trainingPrecent = Convert.ToInt32(tbTrainPrecent.Text);var validationPercent = Convert.ToInt32(tbValiddatatPrecent.Text);// 设置训练对象的属性training.TraingPercent = trainingPrecent;training.ValidationPercent = validationPercent;training.BatchSize = batchSize;training.LearningRate = learningRate;training.NumEpochs = numEpochs;training.EvaluateNumEpoch = evaluateNumEpochs;// 设置显示窗口的的背景var hw = hWinTrain.HalconWindow;hw.SetWindowParam("background_color", "light gray");training.TrainWindow = hw;// 调用模型训练的方法int res = await training.ExecuteTraining();if (res > 0){Logger.Notify("training finished .", "Training");}else{Logger.Error("training exception .", "Training");}}#endregion#region 执行评估private void btnEvaluate_Click(object sender, EventArgs e){// 获取评估对象并给属性赋值var evaluate = Classification.EvaluateAction;evaluate.EvaluateMetric = cbMetric.Text;evaluate.EvaluateDataName = cbSampleSelectValues.Text;evaluate.EvaluateWindow = hWinEvaluate.HalconWindow;// 执行模型评估int res = evaluate.ExecuteEvaluate();if (res > 0){Logger.Notify("evaluate finished .", "Evaluate");}else{Logger.Error("evaluate error .", "Evaluate");}}private void btnSelectEvaluateModel_Click(object sender, EventArgs e){// 获取选择的数据集文件路径string datasetFile = SelectFile("Model(*.hdl)|*.hdl");if (datasetFile != null){// 将数据集名称显示至文本框tbEvaluateModelFile.Text = Path.GetFileNameWithoutExtension(datasetFile);}// 设置完成的模型路径Classification.EvaluateAction.EvaluateModelFileName = datasetFile;}#endregion#region 执行推断private void btnSelectInferModel_Click(object sender, EventArgs e){// 获取选择的数据集文件路径string datasetFile = SelectFile("Model(*.hdl)|*.hdl");// 把数据集路径存放至控件的Tag属性,并显示文件名称tbInferModel.Tag = datasetFile;if (datasetFile != null){// 将数据集名称显示至文本框tbInferModel.Text = Path.GetFileNameWithoutExtension(datasetFile);}// 设置推断使用的模型文件Classification.InferenceAction.ModelTypeName = datasetFile;}private void btnSelectInferImg_Click(object sender, EventArgs e){var dialog = new FolderBrowserDialog();if (dialog.ShowDialog() == DialogResult.OK){// 获取用户选择的目录var inferDataPath = dialog.SelectedPath;// 给文本框赋值tbInferPath.Text = inferDataPath;// 设置推断文件,这里可以进行优化文件后缀,避免放置非图像文件Classification.InferenceAction.InferImages = Directory.GetFiles(inferDataPath).ToList();}}private async void btnSigInfer_Click(object sender, EventArgs e){// 获取推断对象var infer = Classification.InferenceAction;infer.UpdateInvoker += InferOnece_UpdateInvoker;// 调用推断方法int res = await infer.ExecuteInfer(InferType.ONECE);if (res > 0){// 赋值推断结果tbClass.Text = infer.Class;tbScore.Text = (infer.Score*100).ToString("F2");tbTicks.Text = (infer.Ticks * 1000).ToString("F4");Logger.Log($"{infer.Index}.Type:{infer.Class},Score:{(infer.Score * 100).ToString("F2")}", "Inference");}else{Logger.Log("infer method error.", "Inference");}}private void InferOnece_UpdateInvoker(HObject obj){if (obj != null){var hw = hWinInfer.HalconWindow;// 关闭窗口缓存更新hw.SetWindowParam("flush", "false");// 把上一次窗口显示数据清空hw.ClearWindow();// 显示采集图像DispImage(HObject2HImage(obj), hw);// 更新创建数据hw.FlushBuffer();}}private async void btnContinueInfer_Click(object sender, EventArgs e){// 获取推断对象var infer = Classification.InferenceAction;infer.ContinueUpdateInvoker += InferContinue_UpdateInvoker;// 调用推断方法int res = await infer.ExecuteInfer(InferType.CONTINUE);if (res > 0){// 赋值推断结果Logger.Notify("continue inference finished.", "Inference");}else{Logger.Log("continue infer method error.", "Inference");}}private void InferContinue_UpdateInvoker(HObject obj, Inference inference){if (obj != null){var hw = hWinInfer.HalconWindow;// 关闭窗口缓存更新hw.SetWindowParam("flush", "false");// 把上一次窗口显示数据清空hw.ClearWindow();// 显示采集图像DispImage(HObject2HImage(obj), hw);// 更新创建数据hw.FlushBuffer();// 多线程中调用必须使用异步调用方式BeginInvoke(new Action(() =>{// 赋值推断结果tbClass.Text = inference.Class;tbScore.Text = (inference.Score*100).ToString("F2");tbTicks.Text = (inference.Ticks * 1000).ToString("F4");}));Logger.Log($"{inference.Index}.Type:{inference.Class},Score:{(inference.Score * 100).ToString("F2")}", "Inference");}}#endregion
完整打包资料资料包