LC-Finder 0.3.0 Beta 开发日志

发表于2018年12月15日

2019-03-10

之前看到 vscode 的源代码管理界面提示 darknetlib 有几十个更新,虽然知道是子模块 darknet 的更新,但还是点了同步,结果现在编译 darknetlib 一堆错误,在一堆警告中找错误很费劲,代码改起来也麻烦,有点记不起之前都加了哪些代码。感觉直接改 darknet 的源码会更方便点,这样处理冲突时编辑器也能够直观的呈现差异,不用像现在这样手动复制粘贴文件内容然后用编辑器查看文件差异。

2019-02-19

用检测器检测了一些图片,查看图片的标注面板时发现标注的边界框位置都不对,仔细对比 darknetlib 和 darknet 的边界框处理代码后才发现是边界框的坐标算错了,之前以为是左上角的坐标,实际上却是边界框中心的坐标。其实 darknet 的 README 文档上也有说明。

2019-02-04

找带标记的图包挺麻烦的,标记数据可以靠现有的识别功能自动标记生成,只找图包就够了。

找到了 cocodataset,看到 coco 才发现 darknet 的一个预训练模型就是用 coco 数据集来训练的。上面提供的图包很多,选了一个体积小点的下载,解压图包后有四万多张图片,导入到 LCFinder 里后内存占用飙升,界面卡顿,缩略图加载功能几乎停滞,看样子要做优化了。

2019-02-03

图片标记功能差不多完成了,接下来是训练功能,测试训练功能需要数据集,而且是已经标记好的,简单搜索了一下,找到了一个路标的数据集,在准备好配置文件后开始测试,结果输出一堆 nan。

2019-02-01

图片标记框数据的读写操作比较耗时,把它放在工作线程上进行的话就要考虑数据有效性和线程安全问题,而且还必须只在一个线程上进行,因为多个工作线程乱序执行读或写操作会容易产生冲突。在工作线程加载标记框完后,还要切回 UI 线程然后将数据渲染到界面上,这数据通信实现起来挺麻烦的。

标记框应该仅在打开标记面板后显示,减少多余的文件读操作。

添加、更新、删除标记时应该同步到文件的标签列表,当同名的标记数量小于 1 时移除对应的标签。在切换到详情面板时标签列表不会更新,要么加个方法让它更新标签列表,要么让详情面板只在打开时加载数据。

很多源文件里都有的 view、self 这样的全局变量,即便用了 static 来修饰,在 VS2017 的调试模式下也无法识别出它们的类型,真麻烦,必要时还得改名。

2019-01-30

标记框的颜色改成根据名称来生成,也就是简单累加每个字符然后取模,这样同名的标记框就能有相同的颜色。

2019-01-20

创建模型时复制一百多兆的文件估计要好几秒钟时间,这段时间里需要显示个操作中的提示,限于现在的条件无法实现常见的转圈动画,那就只能弄个简单的图标切换效果了,至少能让用户知道界面还在活动。

2019-01-17

训练任务是否完成取决于平均 loss 值,loss 值会随着迭代次数的增加而越来越小,直到稳定在某一数值附近时可以停止训练。看了相关资料,当 loss 值低于 0.06 时差不多可以停止训练,估计 loss 值的递减量会越来越小,为了让进度条稍微均匀的增长,可以将进度拆成两段来计算:

原计划是由训练任务来生成一个新模型,但仔细想想以后若要基于现有模型来训练会有点麻烦,所以还是拆分成两个功能来实现。

考虑到训练时要更新 classes、train 等配置项,为了不影响现有的模型,应该创建一个文件夹来存放当前训练的模型相关文件副本,等训练完成后再将文件覆盖到模型目录里对应的文件。

2019-01-12

darknet 在处理错误时是调用 exit() 退出的,一个图形界面程序在出错时直接闪退会影响用户体验,用户都看不到错误信息,不利于排查问题,需要改造 darknet 的错误处理方式。以前在添加 png 图片读取功能时有了解到 setjmp(),可以用它实现,但感觉直接调用不太方便,于是搜索到了这篇文章《Exceptions in C with Longjmp and Setjmp》,可以用宏定义来包装一下 setjmp() 和 longjmp()。

darknet 的错误处理已调整,现在 LCFinder 可以捕获到它的错误并输出到界面上,效果如下:

LCFinder detector error

2019-01-06

图片检测功能已经完成,测试时内存占用 1.6GB 以上,测了几次后会出现 "no CUDA-capable device is detected" 错误,无法继续使用。

CUDA 和 cuDNN 库的体积很大,加起来有 400 MB 以上,再算上一些预训练模型文件话,占用空间近 1 GB,这以后就不能宣称“轻量级”的工具了,等发布时需要考虑把文件拆分开来下载,比如拆分成:基础版 + GPU 加速版 + 检测器配置文件。

2019-01-03

配置文件里的文件路径是相对于当前工作目录的,如果把它们放到自定义目录里的话会找不到配置里指定的文件,有两个解决方案:

2019-01-02

准备添加识别功能,darknet 的文档里有给出现成的配置文件和预训练好的模型,可以直接拿来用,接下来需要考虑该如何存放和读写这些文件,“设置”界面还需要给个下拉框让用户选择。

现在的训练就一个开始和结束操作,没其它可配置的,假如用户只想拿某个文件夹内的图片给检测器训练,该如何处理?

2019-01-01

决定将检测器的设置项放到“设置”界面里。

识别和训练任务在开始后,需要显示当前进度、剩余时间,任务的操作只有开始和停止,暂不添加暂停功能。

2018-12-31

需要一个界面来控制检测器的识别和训练任务,还要能切换和新建配置文件,把这些配置项全放到“设置”里的话感觉有点不太适。

2018-12-30

粗略的看了下 darknet 的代码,感觉比较乱,部分核心功能模块里还夹杂了一些命令行交互的代码,不适合直接当成函数库来调用。考虑到 LCFinder 在训练时需要显示进度,而 darknet 没有直接提供相关接口,因此决定自己动手改代码。直接改源代码的话,以后合并上游代码比较麻烦,可以写个封装库,重新定义一些接口,接口命名风格参考 levedb/c.h

编译了个无 GPU 加速的版本,识别一张图要 80 多秒,挺慢的,改用带 GPU 加速的版本后耗时只需 0.06 秒,这提升挺大的。

2018-12-23

已完成图片区域标记功能,界面细节有待继续改进,也发现了 LCUI 的几个 bug,接下来需要考虑数据存储策略和 darknet 的调用方式。

LCFinder label boxes

2018-12-22

标签框模块需要的数据有:文件路径、图片所处的容器、图片焦点坐标、浏览区域的偏移量,可以定义个结构体装载这些数据,然后在图片查看器的数据变化时将这些数据传给它。

图片中标记区域需要存储到文件里,可选的文件位置有两个:

2018-12-17

标记框已经完成,接下来是添加标记面板,然后将标记功能整合到图片查看器。标记面板需要展示已标记的区域信息列表和可添加的标记列表,实现起来比较简单,复杂的是后者,在图片切换时需要重置标记区域,缩放和移动图片浏览区域时需要更新标记框的位置和尺寸,两个功能模块的数据通信有些让人纠结。

2018-12-15

准备添加图像识别功能。之前有了解过 TensorFlow,它有提供 C、C++ 接口,也有现成的用 C++ 实现的图片识别示例,本打算将这个示例改用 C 接口实现然后给 LCFinder 调用,但看了 C 接口和相关资料后觉得很麻烦,比如 TF_SessionRun() 的参数需要什么内容,这些内容表示什么,怎么生成?无脑复制粘贴相关代码再凭感觉改会让人有点迷茫,在写代码前还是先了解 TensorFlow 的工作原理和相关示例代码好些。

现在打算用 yolo 来实现图像识别功能,官方示例的效果能够标记出图片中的对象和名称,正好符合需求。

yolo example

在添加图像识别功能之前需要给 LCFinder 加上区域标记功能,能够像 Yolo_mark 一样标记图片中各个对象的边界框并输出到文件,以便使用 darknet 训练 yolo 模型。

yolo mark

LCFinder 的图片查看器是把图片当成背景图来呈现的,不是一个单独的部件,如何定位已标记的边界框并根据缩放比例调整它的尺寸?

标记框要做成四边+四角可拖动调整尺寸的话有点麻烦,简单点,只允许点击拖动右下角来调整框的尺寸。

对此文章有疑问?你可以点击此链接反馈你的问题