阅读量:0
2.5 C#视觉程序开发实例2----图片内存管理 Csharp实现
1 目标效果视频
mat-buffer
2 VisionManager类,专门用来管理Opencv相关的内存和 工具参数
2.1 定义一个mat_buffers数组
// Mat buffer 用于保存Mat 图片内存 //Mat[0]:register //Mat[1]:cur img //Mat[2-6]:colorfilter //Mat[7-16]:grayfilter public static int n_max_buffers = 17; public Mat[,] mat_buffers;//Mat[camCount,17]
2.2 初始化Mat_buffer数组
VisionManager初始化时自动初始化内存数组
public VisionManager() { try { // 初始化 mat_buffers mat_buffers = new Mat[n_max_CamCount, n_max_buffers]; for (int i = 0; i < n_max_CamCount; i++) { for (int j = 0; j < n_max_buffers; j++) { mat_buffers[i, j] = new Mat(); } } } catch(Exception ex) { ExceptionManager.Add_Exception(TraceHelper.GetFuncName(), ex); } }
2.3 创建LoadProgram()函数
用于应用程序切换程序时导入视觉工具参数,这里只是举例说明读取注册图片
/// <summary> /// LoadProgram /// </summary> /// <param name="ProNO"></param> /// <returns></returns> public int LoadProgram(int ProNO) { int nRet = 0; try { //stp0 读取注册图片 nRet = Read_Register_Img(); } catch(Exception ex) { nRet = -2; } return nRet; } /***************************************************************/ /// <summary> /// get_Path /// 获取当前程序号的全路径 /// </summary> /// <param name="proNO"></param> /// <returns></returns> private string get_Path(int proNO) { return @appPath + "Program" + proNO.ToString("000") + "/"; } /// <summary> /// Read_CamParams /// </summary> /// <param name="CamNO"></param> /// <returns></returns> private int Read_Register_Img(int CamNO) { int nRet = 0; string CameraName, FilePath, FileName; CameraName = CamNO.ToString(); FilePath = get_Path(Program_NO)+"Cam" + CameraName+@"/"; FileName = "camParams.xml"; try { // 判断是否文件夹存在 // 先清空内存 BD_OperateSet.Assign_Temp(ref mat_buffers[CamNO,0],new Mat()); // 读取保存的注册画面 FileName = "Img.png"; if (ContextManager.get_fileopCtx().FileExist(FilePath, FileName)) { Mat tmp= Cv2.ImRead(FilePath + FileName, ImreadModes.Unchanged); BD_OperateSet.Assign_Mat(ref mat_buffers[CamNO, 0], ref tmp); BD_OperateSet.Assign_Temp(ref tmp);// 清空临时变量 } } catch(Exception ex) { ExceptionManager.Add_Exception(TraceHelper.GetFuncName(), ex); nRet = (int)STATUS_ENUM.STATUS_EXCEPTION; } return nRet; } /// <summary> /// 读取全部相机注册图片 /// </summary> /// <returns></returns> private int Read_Register_Img() { int nRet = 0; for(int i=0;i<n_max_CamCount;i++) { nRet = Read_Register_Img(i); if (nRet != 0) break; } return nRet; }
3 ContextManager中添加对VisionManager的实现
//visionManager private static VisionManager vision_Ctx; public static VisionManager get_visionCtx() { if (vision_Ctx == null) vision_Ctx = new VisionManager(); return vision_Ctx; }
4 FormVision.exe 中实现
4.1 程序初始化时,导入程序参数
/// <summary> /// Load_Program /// 导入当前程序参数 /// </summary> /// <param name="ProNO"></param> /// <returns></returns> private int Load_Program( ) { int nRet = 0; ContextManager.get_visionCtx().LoadProgram(VisionManager.Program_NO); return nRet; }
Form_vision_Load时 ,按照以下流程进行处理
- 当前程序号赋值=0
- 导入程序参数
- 初始化显示控件
- 创建线程
private void Form_vision_Load(object sender, EventArgs e) { //打开资源 Open_Resources(); // load 程序参数 VisionManager.Program_NO = 0; // 导入程序参数 Load_Program(); // 初始化显示控件 Init_Display(); // 创建线程 CreateThread(); timer1.Interval = 100; timer1.Start(); }
Init_Display()实现
/// <summary> /// Init_Display /// 显示控件第一次显示, 目的进行画布的初始化布局 /// </summary> private void Init_Display() { //显示控件第一次显示, 目的进行画布的初始化布局 for(int i=0;i<VisionManager.n_max_CamCount;i++) { // 初始化显示注册图片, if(BD_OperateSet.MatisNotNull(ContextManager.get_visionCtx().mat_buffers[i,0])) bdDisplay_Runsets1.picture_cam.InitDisplay_Mat(ref ContextManager.get_visionCtx().mat_buffers[i, 0]); } }
4.2 图片处理线程完善代码
- 取出最新图片 ,赋值给mat_buffer[1]
//C# Class是地址传递,这里直接用= tmp = imgs_buffer.Pop_Front(); // bdDisplay_Runsets1.flush_Display = false; int CamNO = 0; // stp0 matbuffer[CamNO,1],代表当前最新抓取图片 BD_OperateSet.Assign_Mat(ref ContextManager.get_visionCtx().mat_buffers[CamNO, 1], ref tmp); ok_message.Add("采集图片成功");
- 彩色过滤处理,获取R通道图片
输入源mat_buffer[1],输出源mat_buffer[2]
// stp1 cfilter 处理 if (tmp.Type() == MatType.CV_8UC3)//判断是否彩色图片,一般采集图片都是8位的 { Mat[] bgr = new Mat[3]; // 分解成三通道, 默认是通道0:B ,通道1:G ,通道2: R Cv2.Split(tmp, out bgr); // 获取其中 R 通道,赋值给 mat_buffers[CamNO, 2] BD_OperateSet.Assign_Mat(ref ContextManager.get_visionCtx().mat_buffers[CamNO, 2], ref bgr[2]); // 销毁临时变量 BD_OperateSet.Mats_Clear(bgr); bgr = null; ok_message.Add("彩色过滤器,获取R通道成功"); }
- 灰度过滤处理,dst=src*scale+add; 输出到mat_buffer[7]
输入源mat_buffer[2],输出源mat_buffer[7]
// stp2 filter 处理 // 联系 scale img if (BD_OperateSet.MatisNotNull(ContextManager.get_visionCtx().mat_buffers[CamNO, 2])) { Mat scale_img = new Mat(); // dst=src*1.2+add; double scale = 1.2; double add = 0; ContextManager.get_visionCtx().mat_buffers[CamNO, 2].ConvertTo(scale_img, -1, scale, add); //输出结果到 mat_buffers[CamNO, 6] BD_OperateSet.Assign_Mat(ref ContextManager.get_visionCtx().mat_buffers[CamNO, 7], ref scale_img); // 销毁临时变量 BD_OperateSet.Assign_Temp(ref scale_img); ok_message.Add("灰度过滤器,图片增强成功"); }
处理效果
- 视觉工具:Intensity,获取平均亮度
输入源mat_buffer[7]
// stp3 intensity处理 if (BD_OperateSet.MatisNotNull(ContextManager.get_visionCtx().mat_buffers[CamNO, 7])) { //获取平均亮度 Scalar intensity = Cv2.Mean(ContextManager.get_visionCtx().mat_buffers[CamNO, 7]); ok_message.Add("获取图片平均亮度,亮度=" + intensity.Val0.ToString("0")); }
结果显示效果
- ImgProcessCCD 完整代码
/// <summary> /// ImgProcessCCD0 /// remark: thread 图像process0 /// </summary> private void ImgProcessCCD(int n_thread_index = 0) { ListViewItem DATA = new ListViewItem(); DateTime ts3 = DateTime.Now; DateTime current = DateTime.Now; bool status = true; // OK结果信息记录 List<string> ok_message = new List<string>(); // NG结果信息记录 List<string> ng_message = new List<string>(); while ( newImgEvent_thread.WaitOne()) //相机1&2都已经已拍照 { Mat tmp = null; ok_message.Clear(); ng_message.Clear(); try { // 添加线程统计信息 //C# Class是地址传递,这里直接用= tmp = imgs_buffer.Pop_Front(); // bdDisplay_Runsets1.flush_Display = false; int CamNO = 0; // stp0 matbuffer[CamNO,1],代表当前最新抓取图片 BD_OperateSet.Assign_Mat(ref ContextManager.get_visionCtx().mat_buffers[CamNO, 1], ref tmp); ok_message.Add("采集图片成功"); // stp1 cfilter 处理 if (tmp.Type() == MatType.CV_8UC3)//判断是否彩色图片,一般采集图片都是8位的 { Mat[] bgr = new Mat[3]; // 分解成三通道, 默认是通道0:B ,通道1:G ,通道2: R Cv2.Split(tmp, out bgr); // 获取其中 R 通道,赋值给 mat_buffers[CamNO, 2] BD_OperateSet.Assign_Mat(ref ContextManager.get_visionCtx().mat_buffers[CamNO, 2], ref bgr[2]); // 销毁临时变量 BD_OperateSet.Mats_Clear(bgr); bgr = null; ok_message.Add("彩色过滤器,获取R通道成功"); } // stp2 filter 处理 // 联系 scale img if (BD_OperateSet.MatisNotNull(ContextManager.get_visionCtx().mat_buffers[CamNO, 2])) { Mat scale_img = new Mat(); // dst=src*1.2+add; double scale = 1.2; double add = 0; ContextManager.get_visionCtx().mat_buffers[CamNO, 2].ConvertTo(scale_img, -1, scale, add); //输出结果到 mat_buffers[CamNO, 6] BD_OperateSet.Assign_Mat(ref ContextManager.get_visionCtx().mat_buffers[CamNO, 7], ref scale_img); // 销毁临时变量 BD_OperateSet.Assign_Temp(ref scale_img); ok_message.Add("灰度过滤器,图片增强成功"); } // stp3 intensity处理 if (BD_OperateSet.MatisNotNull(ContextManager.get_visionCtx().mat_buffers[CamNO, 7])) { //获取平均亮度 Scalar intensity = Cv2.Mean(ContextManager.get_visionCtx().mat_buffers[CamNO, 7]); ok_message.Add("获取图片平均亮度,亮度=" + intensity.Val0.ToString("0")); } // 图片结果刷新 bdDisplay_Runsets1.flush_Display = true; if (BD_OperateSet.MatisNotNull(tmp)) { int index = index_mat_buffer; if (index == -1) index = 1; switch (index_mat_buffer) { case 0: bdDisplay_Runsets1.Display(tmp); break; default: bdDisplay_Runsets1.Display(ContextManager.get_visionCtx().mat_buffers[CamNO, index]); break; } } else { status = false; } // 结果信息刷新 bdDisplay_Runsets1.Display_Result(ok_message,ng_message,Color.DarkGreen,Color.Red); //统计结果显示 thead0_summary.Update_Statistics(status); // 相机状态栏更新 bdDisplay_Runsets1.Update_Cam_Text(status, thead0_summary.toString()); } catch(Exception ex) { ExceptionManager.Add_Exception(TraceHelper.GetFuncName(), ex); } // 输出脉冲 ContextManager.get_IOCtx().task_out_server_thread0.Add_One_Task(status); // 临时变量赋值null tmp = null; if (StopProgramEvent.WaitOne(0, true)) break; } //end while return; }