C#,人工智能,深度学习,目标检测,OpenCV级联分类器数据集的制作与《层级分类器一键生成器》源代码

一、目标识别技术概述
1、摘要
目标检测是计算机视觉中最基本和最具挑战性的问题之一,它试图从自然图像中的大量预定义类别中定位目标实例。深度学习技术已成为直接从数据中学习特征表示的强大策略,并在通用目标检测领域取得了显著突破。鉴于这一快速发展时期,本文的目标是全面综述深度学习技术在这一领域的最新成就。这项调查包括300多项研究贡献,涵盖了通用对象检测的许多方面:检测框架、对象特征表示、对象提议生成、上下文建模、训练策略和评估指标。我们通过确定未来研究的前景来完成调查。
2、介绍
作为计算机视觉中的一个长期、基本和具有挑战性的问题,目标检测(如图1所示)几十年来一直是一个活跃的研究领域(Fischler和Elschlager 1973)。目标检测的目标是确定图像中是否存在来自给定类别(如人类、汽车、自行车、狗或猫)的任何对象实例,如果存在,则返回每个对象实例的空间位置和范围(例如,通过边界框Everingham等人2010;Russakovsky等人2015)。作为图像理解和计算机视觉的基石,目标检测是解决复杂或高级视觉任务的基础,例如分割、场景理解、目标跟踪、图像字幕、事件检测和活动识别。目标检测支持广泛的应用,包括机器人视觉、消费电子、安全、自动驾驶、人机交互、基于内容的图像检索、智能视频监控和增强现实。
最近,深度学习技术(Hinton和Salakhutdinov 2006;LeCun等人,2015)已成为从数据中自动学习特征表示的强大方法。特别是,如图3所示,这些技术在对象检测方面提供了重大改进。
如图2所示,物体检测可以分为两种类型之一(Grauman和Leibe 2011;Zhang等人,2013):特定实例的检测与广泛类别的检测。第一种类型旨在检测特定对象的实例(例如唐纳德·特朗普的脸、埃菲尔铁塔或邻居的狗),本质上是一个匹配问题。第二种类型的目标是检测某些预定义对象类别(例如人、汽车、自行车和狗)的实例(通常以前未看到)。历史上,目标检测领域的大部分工作都集中在单个类别(通常是人脸和行人)或几个特定类别的检测上。相比之下,在过去几年中,研究界已开始朝着更具挑战性的目标迈进,即建立通用目标检测系统,在该系统中,目标检测能力的广度与人类相当。
Krizhevsky等人(2012a)提出了一种称为AlexNet的深度卷积神经网络(DCNN),该网络在大规模视觉识别挑战(ILSVRC)中实现了破纪录的图像分类精度(Russakovsky等人,2015)。自那时以来,计算机视觉的大多数方面的研究重点都是深度学习方法,实际上包括通用对象检测领域(Girshick等人2014;He等人2014;Girshick 2015;Sermanet al.2014;Ren等人2017)。虽然已经取得了巨大的进步,如图3所示,但我们不知道在过去5年中对这一主题进行了全面的调查。鉴于进展速度异常迅速,本文试图跟踪最新进展并总结其成果,以便更清楚地了解通用目标检测中的当前全景。
3、与之前算法的比较
如表1所示,已经发布了许多著名的物体检测调查。其中包括许多关于特定物体检测问题的优秀调查,例如行人检测(Enzweiler和Gavrila 2009;Geronimo等人2010;Dollar等人2012)、人脸检测(Yang等人2002;Zafeiriou等人2015)、车辆检测(Sun等人2006)和文本检测(Ye和Doermann 2015)。除了张等人(2013)就对象类检测主题进行的调查外,最近直接关注一般对象检测问题的调查相对较少。然而,在Grauman和Leibe(2011)、Andreopoulos和Tsotsos(2013)以及Zhang等人(2013)中回顾的研究大多是在2012年之前,因此在深度学习和相关方法最近取得显著成功并占据主导地位之前。
深度学习允许计算模型学习极其复杂、微妙和抽象的表示,推动了广泛问题的重大进展,如视觉识别、物体检测、语音识别、自然语言处理、医学图像分析、药物发现和基因组学。在不同类型的深度神经网络中,DCNN(LeCun等人,1998、2015;Krizhevsky等人,2012a)在处理图像、视频、语音和音频方面取得了突破。可以肯定的是,已经发表了许多关于深度学习的调查,包括Bengio等人(2013)、LeCun等人(2015)、Litjens等人(2017)、Gu等人(2018),以及最近在ICCV和CVPR的教程中发表的调查。
相比之下,虽然已经提出了许多基于深度学习的目标检测方法,但我们不知道最近有任何全面的调查。全面回顾和总结现有工作对于目标检测的进一步进展至关重要,特别是对于希望进入该领域的研究人员而言。由于我们的重点是一般物体检测,因此将不考虑针对特定物体检测的DCNN的广泛工作,例如人脸检测(李等人2015a;张等人2016a;胡等人2017)、行人检测(张等人2016b;何桑等人2015)、车辆检测(周等人2016b)和交通标志检测(朱等人2016b)。
4、范围
基于深度学习的通用目标检测的论文数量惊人。事实上,有如此之多的内容,以至于对最新技术的任何全面综述都超出了任何合理篇幅的论文的范围。因此,有必要制定选择标准,将我们的重点限制在顶级期刊和会议论文上。由于这些局限性,我们真诚地向那些作品未包含在本文中的作者道歉。有关相关主题工作的调查,读者请参阅表1中的文章。本综述主要关注过去5年的主要进展,我们将注意力限制在静态图片上,将视频对象检测这一重要课题作为未来单独考虑的主题。

二、OpenCV级联分类器(CascadeClassifier)生成方法
OpenCV级联分类器数据(比如:cascade.xml)用于实现目标识别的核心数据。
CascadeClassifier则是opencv下objdetect模块中用来做目标检测的级联分类器的一个类;简而言之是滑动窗口机制+级联分类器的方式;早期opencv版本仅支持haar特征的目标检测,分别在opencv2.2和2.4之后开始支持LBP和HOG特征的目标检测。
使用现成的级联分类器数据局限性太多了,工业软件都是自己制作。
1、级联分类器数据的制作流程
2、图片准备与预处理
(1)图片最好用现场拍摄的照片,尽量不要过多的处理,原本最好!
(2)文件夹、文件名等,最好不要有汉字等,数字与字母最好;文件夹最好不要有空格!
(3)本文的《层级分类器集成生成环境》可以帮助你一键生成同样大小、黑白以及按数字命名的正样本图片及负样本图片。
3、正样本 Positive Images(Samples)
正样本图片,是告诉程序,这些 或 接近的就是目标!一般来说,数量至少在 1000 以上。本文只是示意性的,仅仅给出几十个图片,这是不够的哈。
(1)正样本 一般要求 20x20,24x24,64x64;
(2)现在有了本文的《层级分类器集成生成环境》,你随便,正样本只要截取的是正方形(其实也不一定)的即可。
(3)彩色?黑白?无所谓。
(4)正样本文件 pos.txt 是为了生成 正样本矢量化数据 pos.vec 准备的;
posdata/001.jpg 1 0 0 20 20
posdata/002.jpg 1 0 0 20 20
posdata/003.jpg 1 0 0 20 20
posdata/004.jpg 1 0 0 20 20
posdata/005.jpg 1 0 0 20 20
posdata/006.jpg 1 0 0 20 20
posdata/007.jpg 1 0 0 20 20
posdata/008.jpg 1 0 0 20 20
posdata/009.jpg 1 0 0 20 20
posdata/010.jpg 1 0 0 20 20
posdata/011.jpg 1 0 0 20 20
posdata/012.jpg 1 0 0 20 20
正样本文件 pos.txt 每行的格式是:
文件名 样本目标数 起点x 起点 y 宽度 高度
文件名可以用相对路径。样本数建议为1。起点建议为(0,0)。
本文的《层级分类器集成生成环境》可以帮助你一键生成 pos.txt 文件。图片尺寸自动提取。
4、正样本 矢量化
正样本矢量化数据 pos.vec 是训练必须的基础数据,是归一化、标准化、矢量化的 正样本数据,可以不再使用正样本图片及其数据,因而大大提高训练效率。
正样本矢量化数据 pos.vec 用 opencv_createsamples.exe 生成。
Windows cmd:
opencv_createsamples.exe -vec pos.vec -info pos.txt -num 12 -w 20 -h 20
Windows PowerShell:
.\opencv_createsamples.exe -vec pos.vec -info pos.txt -num 12 -w 20 -h 20
参数简要说明:
-vec pos.vec 生成的矢量文件
-info pos.txt 正样本文件
-num 12 正样本数量
-w 20 正样本尺寸(宽)
-h 20 正样本尺寸(高)
本文的《层级分类器集成生成环境》可以帮助你一键生成 pos.vec 文件。不需要进入 cmd 或 PowerShell 去敲键盘!
5、负样本 Negative Images(Samples)
(1)负样本 是告诉识别程序,哪些元素是目标中没有的!数量至少是正样本的 3 倍。不好凑!可以多复制几份哈。可以凑合的。
(2)负样本,大小无所谓;唯一的要求是不能含有正样本的物体;建议尺寸为 320x240 -- 640x480 ;
(3)负样本文件 neg.txt
C:/Downloads/Baidu/opencv_bin/negdata/001.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/002.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/003.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/004.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/005.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/006.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/007.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/008.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/009.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/010.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/011.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/012.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/013.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/014.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/015.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/016.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/017.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/018.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/019.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/020.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/021.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/022.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/023.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/024.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/025.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/026.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/027.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/028.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/029.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/030.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/031.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/032.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/033.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/034.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/035.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/036.jpeg
C:/Downloads/Baidu/opencv_bin/negdata/037.jpeg
负样本文件,只需要指定用于训练的 负样本图片即可。绝对地址!绝对地址!绝对地址!
本文的《层级分类器集成生成环境》可以帮助你一键生成 neg.txt 文件。
正样本数 :负样本数 至少是 1:3
6、训练 Cascade Trainning
有了 pos.vec 与 neg.txt 文件,就可以进行训练了。这个过程 坑 比较多。
Windows cmd:
opencv_traincascaded.exe -data xml -vec pos.vec -bg neg.txt -numPos 12 -numNeg 37 -numStages 20 -w 20 -h 20 -maxFalseAlarmRate 0.5 -mode ALL
Windows PowerShell:
.\opencv_traincascaded.exe -data xml -vec pos.vec -bg neg.txt -numPos 12 -numNeg 37 -numStages 20 -w 20 -h 20 -maxFalseAlarmRate 0.5 -mode ALL
注意几点:
(1)先检查 pos.vec ,neg.txt 文件是否存在?是否符合要求?
(2)建议创建子目录 posdata 放置 正样本 图片;子目录 negdata 放置 负样本图片;
(3)必须创建 xml 子目录;生成结果就在这个子目录下;
(4)无需生成 neg.vec
这个过程很吃资源,很慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢,要花很长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长的时间。
敲击这些参数,很麻烦的。经过漫长的等待,最终生成 xml/cascade.xml 文件,大功告成!
本文的《层级分类器集成生成环境》可以帮助你一键做好上述工作,自动完成训练,生成 cascade.xml 文件!!!!!
三、《层级分类器集成生成环境》源代码

1、老老程序员的唠叨
自己制作 级联分类器数据 不是一件轻松、简单的事情,但没有级联分类器数据几乎无法开展后续的工作。因而不得不硬着头皮做下去。
看到大多数朋友都喜欢进入 cmd 去 key key key,效率实在是太低了。
我们这些从 DOS 过来的骨灰级程序员,有了 Windows 或 iOS 的 GUI ,终于摆脱了 KEY KEY KEY ,看到没有 GUI 的程序简直是受罪。关键是效率太低了。3天的活,本来1小时可以搞掂。
为了提高效率,很多年前就写了 《层级分类器集成生成环境》,现在按 Visual Studio 2022 做些改动与改进,放出来分享。
代码并不完善,有很多不足,请自行修改完善之。
2、准备工作
首先需要有 openCV 训练器相关程序:
(1)使用 openCV 开源,自己或使用别人编译好的 build ;
(2)去 OpenCV 官网下载 release:
OpenCV 官网下载
https://opencv.org/releases/
(3)(多动症儿童〄的博客_CSDN博客-百度AI,笔记领域博主)提供的下载:
https://pan.baidu.com/s/1vCdmWnRRjRNmOCKm30602w?pwd=zur8
https://pan.baidu.com/s/1vCdmWnRRjRNmOCKm30602w?pwd=zur8
CVTrainer项目的目录结构是(供参考):

3、图片预处理源代码
功能包括:批量处理;统一尺寸;统一名称;统一后缀;
#region 图片批量转换/// <summary>
/// 原始文件夹
/// </summary>
private string FromFolder { get; set; } = "";
/// <summary>
/// 目标文件夹
/// </summary>
private string SaveFolder { get; set; } = "";
/// <summary>
/// 图片尺寸信息
/// </summary>
private int[] SaveSizes { get; set; }
/// <summary>
/// 数字型文件名的序列号
/// </summary>
private int SaveIndex { get; set; } = 1;private void tpNormalize_SizeChanged(object sender, EventArgs e)
{txtFrom.Width = tpNormalize.Width - txtFrom.Left - btnFrom.Width - 60;btnFrom.Left = txtFrom.Left + txtFrom.Width + 5;btnFrom.Top = txtFrom.Top;btnFrom.Height = txtFrom.Height;
}/// <summary>
/// 浏览原始文件夹
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnFrom_Click(object sender, EventArgs e)
{if (folderBrowserDialog1.ShowDialog() == DialogResult.OK){FromFolder = folderBrowserDialog1.SelectedPath;txtFrom.Text = FromFolder;SaveSizes = ImageSizes(FromFolder);if (SaveSizes[0] != SaveSizes[1]) txtFromWidth.Text = SaveSizes[0] + "..." + SaveSizes[1];else txtFromWidth.Text = SaveSizes[0] + "";if (SaveSizes[2] != SaveSizes[3]) txtFromHeight.Text = SaveSizes[2] + "..." + SaveSizes[3];else txtFromHeight.Text = SaveSizes[2] + "";txtSaveWidth.Text = SaveSizes[0] + "";txtSaveHeight.Text = SaveSizes[2] + "";}
}/// <summary>
/// 浏览并指定目标文件夹
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSave_Click(object sender, EventArgs e)
{if (folderBrowserDialog1.ShowDialog() == DialogResult.OK){SaveFolder = folderBrowserDialog1.SelectedPath;txtSave.Text = SaveFolder;}
}/// <summary>
/// 图片的批量处理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnNormalize_Click(object sender, EventArgs e)
{if (FromFolder.Length < 1){MessageBox.Show("browse the source folder.");return;}if (SaveFolder.Length < 1){MessageBox.Show("browse the destination folder.");return;}int w = int.Parse("0" + txtSaveWidth.Text);int h = int.Parse("0" + txtSaveHeight.Text);try{int idx = 0;SaveIndex = 1;DirectoryInfo fd = new DirectoryInfo(FromFolder);FileInfo[] xfiles = fd.GetFiles();progressBar1.Maximum = xfiles.Count();progressBar1.Visible = true;foreach (FileInfo fx in xfiles){progressBar1.Value = idx;progressBar1.Refresh();if (IsImageFile(fx.Extension)){string filename = Path.Combine(SaveFolder, fx.Name);if (cbNumericName.Checked){filename = Path.Combine(SaveFolder, GetNumericalName());}// 如果只是复制if (w == SaveSizes[0] && h == SaveSizes[2] && txtSaveExt.Text.Length == 0){File.Copy(fx.FullName, filename);continue;}else{Image img = Image.FromFile(fx.FullName);if (txtSaveExt.Text.Length > 0){filename = Path.Combine(SaveFolder, fx.Name.Replace(fx.Extension, "") + txtSaveExt.Text);}if (w > 0 && h > 0){Bitmap bmp = new Bitmap(w, h);Graphics g = Graphics.FromImage(bmp);g.DrawImage(img, 0, 0, w, h);if(cbGray.Checked){ToGrayImage(ref bmp);}bmp.Save(filename);}else if (w > 0 && h == 0){h = (int)(w * (double)img.Height / (double)img.Width);Bitmap bmp = new Bitmap(w, h);Graphics g = Graphics.FromImage(bmp);g.DrawImage(img, 0, 0, w, h);if (cbGray.Checked){ToGrayImage(ref bmp);}bmp.Save(filename);}else{w = (int)(h * (double)img.Width / (double)img.Height);Bitmap bmp = new Bitmap(w, h);Graphics g = Graphics.FromImage(bmp);g.DrawImage(img, 0, 0, w, h);if (cbGray.Checked){ToGrayImage(ref bmp);}bmp.Save(filename);}}}}progressBar1.Visible = false;MessageBox.Show("OK!");}catch (Exception ex){MessageBox.Show(ex.Message);}
}/// <summary>
/// 计算下一个可使用的数字型图片文件名
/// </summary>
/// <returns></returns>
private string GetNumericalName()
{while (true){string sname = String.Format("{0:D5}", SaveIndex);if (!File.Exists(Path.Combine(SaveFolder, sname))){return sname;}SaveIndex++;}
}
#endregion
4、正样本处理相关源代码(POWER BY 315SOFT.COM)
一键生成 pos.txt 文件;一键生成 pos.vec 文件。
#region 正样本private void tabPage1_SizeChanged(object sender, EventArgs e)
{txtPosFolder.Width = tabPage1.Width - txtPosFolder.Left - btnPosFolder.Width - 60;btnPosFolder.Left = txtPosFolder.Left + txtPosFolder.Width + 5;btnPosFolder.Top = txtPosFolder.Top;
}/// <summary>
/// 浏览并指定 正样本 文件夹
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnPosFolder_Click(object sender, EventArgs e)
{if (folderBrowserDialog1.ShowDialog() == DialogResult.OK){txtPosFolder.Text = folderBrowserDialog1.SelectedPath;txtPosCount.Text = CountImageFile(txtPosFolder.Text) + "";}
}/// <summary>
/// 生成 pos.txt 文件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnPosTxt_Click(object sender, EventArgs e)
{if (txtPosFolder.Text.Length < 1){MessageBox.Show("Please browse the folder contains positive images!");return;}try{// 为复制图片做准备string imgPosFolder = Path.Combine(WorkFolder, @"posdata");if (cbPosCopy.Checked){if (!Directory.Exists(imgPosFolder)){Directory.CreateDirectory(imgPosFolder);}}StringBuilder sb = new StringBuilder();DirectoryInfo fd = new DirectoryInfo(txtPosFolder.Text);FileInfo[] xfiles = fd.GetFiles();foreach (FileInfo fx in xfiles){if (IsImageFile(fx.Extension)){// 将样本图片文件复制到工作文件夹/posdataif (cbPosCopy.Checked){string df = Path.Combine(imgPosFolder, fx.Name);File.Copy(fx.FullName, df);}sb.Append("posdata/");sb.Append(fx.Name + " ");sb.Append(txtSampleCount.Text + " ");sb.Append(txtOriginX.Text + " ");sb.Append(txtOriginY.Text + " ");// 自动获取图片尺寸Image img = Image.FromFile(fx.FullName);sb.Append(img.Width + " ");sb.AppendLine(img.Height + "");// 按最小的图片设置 vector 参数if (txtSampleWidth.Text.Length == 0)txtSampleWidth.Text = img.Width + "";else if (Int32.Parse(txtSampleWidth.Text) > img.Width)txtSampleWidth.Text = img.Width + "";if (txtSampleHeight.Text.Length == 0)txtSampleHeight.Text = img.Height + "";else if (Int32.Parse(txtSampleHeight.Text) > img.Height)txtSampleHeight.Text = img.Height + "";}}if (!Directory.Exists(WorkFolder)){Directory.CreateDirectory(WorkFolder);}File.WriteAllText(Path.Combine(WorkFolder, @"pos.txt"), sb.ToString(), Encoding.Default);webBrowser1.DocumentText = sb.ToString().Replace("\r\n", "<br>\r\n");MessageBox.Show(Path.Combine(WorkFolder, @"pos.txt") + " OK!");}catch (Exception ex){MessageBox.Show(ex.Message);}
}/// <summary>
/// 生成 pos.vec 矢量文件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnPosVec_Click(object sender, EventArgs e)
{string filename = Path.Combine(WorkFolder, @"pos.txt");if (!File.Exists(filename)){MessageBox.Show("Should first create pos.txt !");return;}Directory.SetCurrentDirectory(WorkFolder);StringBuilder sb = new StringBuilder();//sb.Append(WorkFolder + "\\");//sb.Append("opencv_createsamples.exe ");sb.Append("-vec pos.vec ");sb.Append("-info pos.txt ");sb.Append("-num " + txtPosCount.Text + " ");sb.Append("-w " + txtSampleWidth.Text + " ");sb.Append("-h " + txtSampleHeight.Text);Process p = new Process();p.StartInfo.FileName = Path.Combine(WorkFolder, @"opencv_createsamples.exe");p.StartInfo.Arguments = sb.ToString();//是否使用操作系统shell启动p.StartInfo.UseShellExecute = false;//接受来自调用程序的输入信息p.StartInfo.RedirectStandardInput = false;//由调用程序获取输出信息p.StartInfo.RedirectStandardOutput = true;//重定向标准错误输出p.StartInfo.RedirectStandardError = true;//不显示程序窗口p.StartInfo.CreateNoWindow = true;//启动程序p.Start();//p.StandardInput.AutoFlush = false;string output = p.StandardOutput.ReadToEnd();//等待程序执行完退出进程p.WaitForExit();p.Close();webBrowser1.DocumentText = output.Replace("\n", "<br>\n");string filenname = Path.Combine(WorkFolder, @"pos.vec");if (File.Exists(filename)){MessageBox.Show(filename + " OK!");}
}#endregion
5、负样本处理相关源代码
一键生成 neg.txt 文件;
#region 负样本private void tabPage2_SizeChanged(object sender, EventArgs e)
{txtNegFolder.Width = tabPage2.Width - txtNegFolder.Left - btnNegFolder.Width - 60;btnNegFolder.Left = txtNegFolder.Left + txtNegFolder.Width + 5;btnNegFolder.Top = txtNegFolder.Top;
}/// <summary>
/// 浏览并指定 负样本 文件夹
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnNegFolder_Click(object sender, EventArgs e)
{if (folderBrowserDialog1.ShowDialog() == DialogResult.OK){txtNegFolder.Text = folderBrowserDialog1.SelectedPath;txtNegCount.Text = CountImageFile(txtNegFolder.Text) + "";}
}/// <summary>
/// 生成负样本 neg.txt 文件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnNegTxt_Click(object sender, EventArgs e)
{string imgNegFolder = Path.Combine(WorkFolder, @"negdata");StringBuilder sb = new StringBuilder();DirectoryInfo fd = new DirectoryInfo(txtNegFolder.Text);FileInfo[] xfiles = fd.GetFiles();foreach (FileInfo fx in xfiles){if (IsImageFile(fx.Extension)){// 将样本图片文件复制到工作文件夹/negdataif (cbNegCopy.Checked){string df = Path.Combine(imgNegFolder, fx.Name);File.Copy(fx.FullName, df);sb.AppendLine(Path.Combine(imgNegFolder, fx.Name).Replace("\\", "/"));}else{sb.AppendLine(fx.FullName.Replace("\\", "/"));}}}if (!Directory.Exists(WorkFolder)){Directory.CreateDirectory(WorkFolder);}File.WriteAllText(Path.Combine(WorkFolder, @"neg.txt"), sb.ToString(), Encoding.Default);webBrowser1.DocumentText = sb.ToString().Replace("\r\n", "<br>\r\n");MessageBox.Show(Path.Combine(WorkFolder, @"neg.txt") + " OK!");
}#endregion
6、训练源代码
一键生成 xml/cascade.xml 文件;
#region 训练
private void btnTrainning_Click(object sender, EventArgs e)
{string filename = Path.Combine(WorkFolder, @"pos.vec");if (!File.Exists(filename)){MessageBox.Show("Should first create pos.vec !");return;}filename = Path.Combine(WorkFolder, @"neg.txt");if (!File.Exists(filename)){MessageBox.Show("Should first create neg.txt !");return;}Directory.SetCurrentDirectory(WorkFolder);StringBuilder sb = new StringBuilder();sb.Append("-data xml ");sb.Append("-vec " + txtVecFile.Text + " ");sb.Append("-bg " + txtNegFile.Text + " ");sb.Append("-numPos " + txtNumPos.Text + " ");sb.Append("-numNeg " + txtNumNeg.Text + " ");sb.Append("-numStages 20 ");sb.Append("-w " + txtPosWidth.Text + " ");sb.Append("-h " + txtPosHeight.Text + " ");sb.Append("-minHitRate " + txtHitRate.Text + " ");sb.Append("-weightTrimRate " + txtTrimRate.Text + " ");sb.Append("-maxFalseAlarmRate " + txtFalseAlarm.Text + " ");sb.Append("-stagetype " + txtStage.Text + " ");sb.Append("-boosttype " + cxBoost.SelectedItem.ToString() + " ");sb.Append("-featuretype " + cxFeature.SelectedItem.ToString() + " ");sb.Append("-mode " + cxMode.SelectedItem.ToString() + " ");Process p = new Process();p.StartInfo.FileName = Path.Combine(WorkFolder, @"opencv_traincascade.exe");p.StartInfo.Arguments = sb.ToString();//是否使用操作系统shell启动p.StartInfo.UseShellExecute = false;//接受来自调用程序的输入信息p.StartInfo.RedirectStandardInput = false;//由调用程序获取输出信息p.StartInfo.RedirectStandardOutput = true;//重定向标准错误输出p.StartInfo.RedirectStandardError = true;//不显示程序窗口p.StartInfo.CreateNoWindow = true;//启动程序this.Cursor = Cursors.WaitCursor;p.Start();//p.StandardInput.AutoFlush = false;string output = p.StandardOutput.ReadToEnd();//等待程序执行完退出进程p.WaitForExit();p.Close();this.Cursor = Cursors.Default;webBrowser1.DocumentText = output.Replace("\n", "<br>\n");string xmlname = Path.Combine(WorkFolder, @"xml", @"cascade.xml");if (File.Exists(xmlname)){MessageBox.Show(xmlname + " OK!");}
}#endregion
7、基础函数
Form1.cs
using System;
using System.IO;
using System.Text;
using System.Linq;
using System.Drawing;
using System.Diagnostics;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;namespace Legalsoft.CVTrainer
{/// <summary>/// OpenCV 训练集继承生成环境/// 北京联高软件开发有限公司/// Beijing Legal Software Ltd./// </summary>public partial class Form1 : Form{/// <summary>/// 工作目录/// 一般是 CVTrainer.exe 下的 opencv_bin /// </summary>private string WorkFolder { get; set; } = "";public Form1(){InitializeComponent();#region 正样本相关btnPosFolder.Height = txtPosFolder.Height;WorkFolder = Path.Combine(Application.StartupPath, "opencv_bin");lbWorkFolderValue.Text = WorkFolder;cbPosCopy.Checked = true;cbPosCopy.Cursor = Cursors.Hand;btnPosTxt.Cursor = Cursors.Hand;btnPosVec.Cursor = Cursors.Hand;#endregion#region 负样本相关label14.Text = WorkFolder;cbNegCopy.Cursor = Cursors.Hand;btnNegTxt.Cursor = Cursors.Hand;#endregion#region 训练相关label17.Text = WorkFolder;btnTrainning.Cursor = Cursors.Hand;cxBoost.SelectedIndex = 0;cxFeature.SelectedIndex = 0;cxMode.SelectedIndex = 2;#endregion#region 图片预处理相关cbGray.Cursor = Cursors.Hand;txtSaveExt.Text = "";cbNumericName.Cursor = Cursors.Hand;btnNormalize.Cursor = Cursors.Hand;txtFrom.ReadOnly = true;txtFromWidth.ReadOnly = true;txtFromHeight.ReadOnly = true;btnFrom.Cursor = Cursors.Hand;txtSave.ReadOnly = true;btnSave.Cursor = Cursors.Hand;progressBar1.Visible = false;#endregiontabPage1.Text = " Positive Images ";tabPage2.Text = " Negative Images ";tabPage3.Text = " Cascade Train ";tpNormalize.Text = " Image Normalization ";panel1.Dock = DockStyle.Top;tabControl1.Dock = DockStyle.Fill;panel2.Dock = DockStyle.Fill;webBrowser1.Dock = DockStyle.Fill;this.Text = "C#,OpenCV Object Detect Images Trainer ——BEIJING LEGAL SOFTWARE LTD.";this.StartPosition = FormStartPosition.CenterScreen;}private void Form1_Load(object sender, EventArgs e){Summary();}private void tabControl1_SelectedIndexChanged(object sender, EventArgs e){if (tabControl1.SelectedIndex != 0){Summary();}}/// <summary>/// 计算一些概要信息/// </summary>private void Summary(){StringBuilder sb = new StringBuilder();sb.AppendLine("<style>b { font-weight:bold;color:#AA0000; } </style>");sb.AppendLine("Work folder: " + WorkFolder + "<br>");string folder = WorkFolder;if (!Directory.Exists(folder)){sb.AppendLine("!Create Work folder " + WorkFolder + "<br>");MessageBox.Show("Work folder not exist!\nYou can do nothing!");return;}folder = Path.Combine(WorkFolder, "xml");sb.AppendLine("Parameters folder: " + folder + "<br>");if (!Directory.Exists(folder)){sb.AppendLine("!Create parameter(xml) folder " + folder + "<br>");Directory.CreateDirectory(folder);}folder = Path.Combine(WorkFolder, "posdata");sb.AppendLine("Positive folder: " + folder + "<br>");if (!Directory.Exists(folder)){sb.AppendLine("!Create Positive folder " + folder + "<br>");Directory.CreateDirectory(folder);}else{int count = CountImageFile(folder);if (count > 0){sb.AppendLine("There have " + count + " images<br>");txtPosCount.Text = count + "";txtNumPos.Text = count + "";txtPosFolder.Text = folder;}if (File.Exists(Path.Combine(WorkFolder, @"pos.txt"))){sb.AppendLine("There have <b>pos.txt</b><br>");int[] sz = ImageSizes(Path.Combine(WorkFolder, @"posdata"));txtSampleWidth.Text = sz[0] + "";txtSampleHeight.Text = sz[2] + "";txtPosWidth.Text = sz[0] + "";txtPosHeight.Text = sz[2] + "";sb.AppendLine("Image size: " + sz[0] + "," + sz[2] + "<br>");}else{sb.AppendLine("There have't <b>pos.txt</b><br>");}if (File.Exists(Path.Combine(WorkFolder, @"pos.vec"))){sb.AppendLine("There have <b>pos.vec</b><br>");}else{sb.AppendLine("There have <b>not pos.vec</b><br>");}cbPosCopy.Checked = (count == 0);}folder = Path.Combine(WorkFolder, "negdata");sb.AppendLine("Negative folder: " + folder + "<br>");if (!Directory.Exists(folder)){sb.AppendLine("!Create Negative folder " + folder + "<br>");Directory.CreateDirectory(folder);}else{int count = CountImageFile(folder);if (count > 0){sb.AppendLine("There have " + count + " images<br>");txtNegCount.Text = count + "";txtNumNeg.Text = count + "";txtNegFolder.Text = folder;}if (File.Exists(Path.Combine(WorkFolder, @"neg.txt"))){sb.AppendLine("There have <b>neg.txt</b><br>");}else{sb.AppendLine("There have <b>not neg.txt</b><br>");}cbNegCopy.Checked = (count == 0);}webBrowser1.DocumentText = sb.ToString();}//...// 这里添加上面的其他代码}
}
基础函数:
#region 基础函数/// <summary>
/// 文件是图片吗?
/// 按文件后缀判别;可自行添加;
/// </summary>
/// <param name="ext"></param>
/// <returns></returns>
private bool IsImageFile(string ext)
{ext = ext.ToLower();if (ext == ".bmp") return true;if (ext == ".gif") return true;if (ext == ".png") return true;if (ext == ".jpg" || ext == ".jpeg") return true;return false;
}/// <summary>
/// 统计指定目录下的图片文件数量
/// </summary>
/// <param name="folder"></param>
/// <returns></returns>
private int CountImageFile(string folder)
{DirectoryInfo fd = new DirectoryInfo(folder);int count = 0;FileInfo[] xfiles = fd.GetFiles();foreach (FileInfo fx in xfiles){if (IsImageFile(fx.Extension)){count++;}}return count;
}/// <summary>
/// 提取指定文件夹下图片的尺寸(最小、最大的高度、宽度)
/// </summary>
/// <param name="folder"></param>
/// <returns></returns>
private int[] ImageSizes(string folder)
{int min_width = Int16.MaxValue;int max_width = 0;int min_height = Int16.MaxValue;int max_height = 0;DirectoryInfo fd = new DirectoryInfo(folder);FileInfo[] xfiles = fd.GetFiles();foreach (FileInfo fx in xfiles){if (IsImageFile(fx.Extension)){Image img = Image.FromFile(fx.FullName);if (img.Width > max_width) max_width = img.Width;if (img.Width < min_width) min_width = img.Width;if (img.Height > max_height) max_height = img.Height;if (img.Height < min_height) min_height = img.Height;}}return new int[] { min_width, max_width, min_height, max_height };
}/// <summary>
/// 图片转为黑白的
/// 简单的代码,看得懂一些;效率低下;
/// 不过,图片不多的够用了。
/// </summary>
/// <param name="bmp"></param>
private void ToGrayImage(ref Bitmap bmp)
{for (int y = 0; y < bmp.Height; y++){for (int x = 0; x < bmp.Width; x++){Color cc = bmp.GetPixel(x, y);int cx = Math.Min(255, (int)(cc.R * 0.299 + cc.G * 0.587 + cc.B * 0.114));bmp.SetPixel(x, y, Color.FromArgb(cx, cx, cx));}}
}#endregion
8、界面相关代码(略)
以上代码经 验证 基本可用,享受编程的乐趣吧。
相关文章:
C#,人工智能,深度学习,目标检测,OpenCV级联分类器数据集的制作与《层级分类器一键生成器》源代码
一、目标识别技术概述 1、摘要 目标检测是计算机视觉中最基本和最具挑战性的问题之一,它试图从自然图像中的大量预定义类别中定位目标实例。深度学习技术已成为直接从数据中学习特征表示的强大策略,并在通用目标检测领域取得了显著突破。鉴于这一快速发…...
调度系统:Luigi 的主要特性和功能
Luigi 是一个开源的 Python 工作流管理工具,用于构建批处理作业管道,特别适用于数据工程领域。它被设计用来编排任务和处理任务间的依赖关系,支持自动化复杂的 ETL 流程、数据分析、模型训练等任务。 Luigi 的主要特性和功能: 任…...
C# 探险之旅:第二节 - 定义变量与变量赋值
欢迎再次踏上我们的C#学习之旅。今天,我们要聊一个超级重要又好玩的话题——定义变量与变量赋值。想象一下,你正站在一个魔法森林里,手里拿着一本空白的魔法书(其实就是你的代码编辑器),准备记录下各种神奇…...
AUTOSAR:SOME/IP 概念
文章目录 1. 用例与需求1.1 典型用例1.2 对中间件的要求 2. 协议栈示例3. SOME/IP 概念3.1 中间件整体功能与架构3.2 服务组成元素详细解释 4. 服务发现机制深入剖析5. 总结 1. 用例与需求 1.1 典型用例 信息娱乐系统: 后座娱乐系统连接:允许后排乘客连…...
循序渐进kubenetes Service(Cluster ip、Nodeport、Loadbalancer)
文章目录 部署一个web服务Kubernetes Port ForwardKubernetes ServicesClusterIP ServiceNodePort ServiceLoadBalancer Service 部署一个web服务 准备 Kubernetes 集群后,创建一个名为 web 的新 namespace,然后在该 namespace 中部署一个简单的 web 应…...
深入理解 Apache Shiro:安全框架全解析
亲爱的小伙伴们😘,在求知的漫漫旅途中,若你对深度学习的奥秘、JAVA 、PYTHON与SAP 的奇妙世界,亦或是读研论文的撰写攻略有所探寻🧐,那不妨给我一个小小的关注吧🥰。我会精心筹备,在…...
mac 安装CosyVoice (cpu版本)
CosyVoice 介绍 CosyVoice 是阿里研发的一个tts大模型 官方项目地址:https://github.com/FunAudioLLM/CosyVoice.git 下载项目(非官方) git clone --recursive https://github.com/v3ucn/CosyVoice_for_MacOs.git 进入项目 cd CosyVoic…...
币安移除铭文市场的深度解读:背后原因及其对区块链行业的影响
引言: 就在昨天,2024年12月10号,币安宣布将移除铭文市场(Inscriptions Market)。这一消息引发了全球加密货币社区的广泛关注,尤其是在比特币NFT和数字收藏品市场快速发展的背景下。铭文市场自诞生以来迅速…...
深度学习实战野生动物识别
本文采用YOLOv11作为核心算法框架,结合PyQt5构建用户界面,使用Python3进行开发。YOLOv11以其高效的实时检测能力,在多个目标检测任务中展现出卓越性能。本研究针对野生动物数据集进行训练和优化,该数据集包含丰富的野生动物图像样…...
windows安装使用conda
在Windows系统上安装和使用Conda的详细步骤如下: 一、下载Conda安装包 访问Conda的官方网站Anaconda | The Operating System for AI,点击“Downloads”按钮。在下载页面,选择适合您系统的安装包。通常,对于Windows系统…...
手机租赁系统开发全流程解析与实用指南
内容概要 在如今快速发展的科技时代,手机租赁系统已经成为一种新兴的商业模式,非常符合当下市场需求。那么,在开发这样一个系统的时候,首先要从需求分析和市场调研开始。在这一阶段,你需要了解用户需要什么࿰…...
SpringBoot 开发—— YAML文件深度分析
文章目录 一、YAML概述二、数据表示三、YAML 的语法四、YAML 的应用五、YAML 与其他格式的比较1、YAML vs .properties文件可读性和结构数据类型支持扩展性和灵活性使用场景性能和支持2、YAML vs. JSON3、YAML vs. XML六、使用 YAML 的注意事项七、总结YAML 是非常流行的一种配…...
复合机器人整体解决方案
复合机器人是一种集成移动机器人和协作机器人两项功能为一身的新型机器人,更符合人们想象中“脑、眼、手、脚”融合的机器人终极形态。复合机器人的整体解决方案通常涉及多个方面,包括机器人本体、控制系统、感知系统、执行系统以及周边配套设备等。以下…...
【Oracle11g SQL详解】日期和时间函数:SYSDATE、TO_DATE、TO_CHAR 等
日期和时间函数:SYSDATE、TO_DATE、TO_CHAR 等 在 Oracle 数据库中,日期和时间函数用于处理日期和时间数据。它们在记录创建时间、分析时间间隔、格式化输出等场景中非常重要。本文将详细讲解常用的日期和时间函数及其应用。 一、SYSDATE:获…...
VSCode设置字体
参考文章:【面向小白】vscode最佳实践(2)—— 字体设置(fira code更纱黑体),这篇文章末尾给了安装字体的链接。 配置的字体还是很好看的。 ‘Fira Code Retina’, ‘Sarasa Mono Sc’ 需要注意的一个点&am…...
shell编程入门之提取字符并设置rtc时间
awk用法 awk是一款文本处理工具,通常在Unix和Linux操作系统中使用,用于以行为单位对文本进行处理和操作。它可以读取输入文本,对其进行处理,生成报表、统计信息等,并将结果输出到标准输出设备中。 它主要有以下特点&…...
react 不可变数据更新(Immutable Update)合并对象 类似与Java 的BeanUtils.copyProperties
{ ...state, // 保留原有的 state 的其他部分data: { ...state.data, // 保留 state.data 中的其他字段...action.payload // 使用 action.payload 覆盖 state.data 中需要更新的字段} }这段代码是 Redux 中常见的一种状态更…...
Linux GCC基础用法⑦
在 CentOS 7 系统中使用 GCC 与编写 99 乘法表 一、GCC 简介 GCC(GNU Compiler Collection)是一套功能强大的编程语言编译器,在 CentOS 7 系统中广泛用于编译 C、C等多种编程语言的程序。它能够将源代码转换为可执行文件,让计算…...
PyTorch 切片运算 (Slice Operator)
PyTorch 切片运算 {Slice Operator} 1. [:, -1, :]2. [:, [-1], :]References 1. [:, -1, :] https://github.com/karpathy/llama2.c/blob/master/model.py import torchlogits torch.arange(1, 16) print("logits.shape:", logits.shape) print("logits:\n&…...
SpringSecurity Oauth2 -账号密码实现多因子身份认证
1. 密码策略问题 CREATE TABLE t_storage (id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 自增主键,nameSpace varchar(64) NOT NULL COMMENT 隔离字段,groupId varchar(128) NOT NULL COMMENT 分组,比如不同app,dataId varchar(64) NOT NULL COMMENT 数据存储id…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...
【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程
STM32F1 本教程使用零知标准板(STM32F103RBT6)通过I2C驱动ICM20948九轴传感器,实现姿态解算,并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化,适合嵌入式及物联网开发者。在基础驱动上新增…...
HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散
前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说,在叠衣服的过程中,我会带着团队对比各种模型、方法、策略,毕竟针对各个场景始终寻找更优的解决方案,是我个人和我司「七月在线」的职责之一 且个人认为,…...
