学习《OpenCV应用开发:入门、进阶与工程化实践》一书
做真正的OpenCV开发者,从入门到入职,一步到位!
联通组件算子(CCL)
连接组件标记算法(connected component labeling algorithm)是图像分析中最常用的算法之一,算法的实质是扫描一幅图像的每个像素,对于像素值相同的分为相同的组(group),最终得到图像中所有的像素连通组件。扫描的方式可以是从上到下,从左到右,对于一幅有N个像素的图像来说,最大连通组件个数为N/2。扫描是基于每个像素单位,对于二值图像而言,连通组件集合可以是V={1|白色}或者V={0|黑色}, 取决于前景色与背景色的不同。对于灰度图像来说,连图组件像素集合可能是一系列在0 ~ 255之间k的灰度值。OpenCV中相关的两个函数分别是:
// 联通组件标记
int cv::connectedComponents(
InputArray image, // 输入二值图像,黑色背景
OutputArray labels, // 输出的标记图像,背景index=0
int connectivity = 8, // 连通域,默认是8连通
int ltype = CV_32S // 输出的labels类型,默认是CV_32S
)
// 联通组件标记带统计信息
int cv::connectedComponentsWithStats(
InputArray image, // 输入二值图像,黑色背景
OutputArray labels, // 输出的标记图像,背景index=0
OutputArray stats, // 统计信息,包括每个组件的位置、宽、高与面积
OutputArray centroids, // 每个组件的中心位置坐标cx, cy
int connectivity, // 寻找连通组件算法的连通域,默认是8连通
int ltype, // 输出的labels的Mat类型CV_32S
int ccltype // 连通组件算法
)
问题查找与性能优化
最近用户群里有个人跟我说,它有个二值化的图像,然用了OpenCV实验大师的联通组件算子,发现特别耗时,3200x3200大小的图像,耗时居然是几十秒,然后我让他把图发我,我自己测试了一下,发现的确是的。
然后我就把这个保存为流程文件,到的C++引擎库中又测试了一下,发现速度很快,截图如下:
只需要不到50毫秒,而Python版本的居然比C++版本慢了几百倍,我觉得肯定是Python版本哪里实现有不合理的代码,于是我开启了端点执行,单步打印调试….
Python版本调试优化
通过我一通对比自己实现的C++ 与Python代码发现,无论是C++ 还是Python里面调用OpenCV函数都在十几毫秒可以完成,所以Python实现中20多秒的时间损耗肯定来自于Python代码本身,应该与OpenCV无关,一通DEBUG之后我发现是我最后给标签图像赋值颜色的代码造成的,代码如下:
执行耗时如下:
ccl time : 22649.269342422485 ms
然后我看了一下代码,发现了最可能的原因是
result[labels==t] = colors[t]
这行代码导致的,因为我有很多标签,每个标签它都要全图搜索一次,几百个标签,它就全图搜索几百次了,想想在3200x3200的图上遍历搜索几百次,能不成瓶颈吗?我哭,我最初写这个代码觉得这个语法很高大上,鬼斧神工,现在是回旋镖打自己。然后我改成下面这样:
执行时间变成:
ccl time : 4321.542501449585 ms
从22秒下降到了4秒,但是要知道Python里面遍历数组是最慢的操作,如果没有必要千万别这么搞,然后进一步根据颜色表colors数组跟labels的之间的映射关系直接通过下面一行代码即可完成(感谢一位网友的提示):
ccl time : 160.1119 ms
代码比之前更加简洁,执行时间从22000毫秒左右直接下降到160毫秒左右,性能提升了百倍以上。在OpenCV实验大师上面修改代码以后,运行结果如下:
后记:
OpenCV实验大师工具软件 与 OpenCV实验大师工作流引擎库,是作者数十年OpenCV开发的融汇贯通与工程经验的总结之后系统化知识体系的呕心沥血之作,用它们双剑合璧,OpenCV开发效率可提升数十倍,开发能力延展达到工作十年的研发能力,为公司创造更多更大的商业价值是作者的开发这两款软件的初心。
Make OpenCV Development Easy, 永远是我们不变的追求!!!