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;
}