作者:翟天保Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处
一、场景痛点
在图像处理相关的实际工程中,会出现各式各样的现实复杂问题,有的是因为机械设计导致,有的是因为硬件引起(相机、探测器、传感器等),有的是外部环境引起。这些问题跟我们的图像处理工作带来了困难和挑战。
本文提出的场景是在捕捉图像过程中,图像中出现了某种不在预期的亮缝信息,我们要做的就是对其进行补偿修正,而修正的前提是识别,本文重点关注如何识别亮缝的感兴趣区域ROI。该场景的痛点就在于亮缝信息是覆盖在原数据之上的,而原数据本身的信息复杂度是不固定的,可能会出现各种各样的实体轮廓,因此在设计算法的时候,要尽可能地考虑周全,使得算法具备一定适用性、鲁棒性。
针对此场景,本文提出了一种基于梯度统计学的渐变型亮缝识别算法,接下来将简单介绍下算法原理和流程,并展示相关的效果图。
二、算法原理和流程
亮缝信息往往有不同特征,有的是突变型,这种也是比较好提取的,有的是渐变型,即逐渐变亮再变暗的,本文关注的也是此类亮缝。
2.1 梯度计算
待识别图像如下所示,不难发现图像出现了一层明显的亮缝,对于渐变型亮缝,我们第一时间想到的自然是导数,即数据的变化值,而导数给予方向性后也就是我们常说的梯度。
对其XY方向分别进行导数计算,如下图所示。
进而得到了梯度信息,我所测试的数据是沿X轴移动的亮缝,因此只考虑X方向即可。
2.2 统计提取
观察梯度信息,可以发现亮缝在其移动方向上呈现特征是先上升再平稳后下降的过程,那我们识别亮缝问题就转为了识别一个上升区和一个下降区的组合。对梯度图像中亮缝形体方向即Y方向进行梯度统计。
若梯度值大于0则归为上升,若梯度值小于等于0则归为下降;建立一个上升掩膜和一个下降掩膜;对每一个x而言,遍历y,用上升计数值posCount和下降计数值negCount分别累计梯度的升降数量;若累计上升数超过统计阈值,则在上升掩膜中,将该x对应的所有y值设为255;若累计下降数超过统计阈值,则在下降掩膜中,将该x对应的所有y值设为255。
统计后的掩膜图如下所示,先上升掩膜,后下降掩膜:
如上所示,一个上升区和一个下降区就构成了亮缝,接下来要进行进一步的处理。
2.3 图像处理
虽然上面的图看起来比较理想,但前文也说过,若亮缝所处图像的基底图像信息复杂度偏高,此时的掩膜信息中就会出现如下几种异常情况。
- 掩膜中出现某个很窄的区。这不是亮缝的一部分,而是原图像基底的某种特征与上述识别原理在一定程度上重合引起的。
- 掩膜中上升区或下降区并非是完整的,中间可能存在很窄的一列空洞。这是因为亮缝叠加了某些信息后,其梯度变化收到了一定程度的干扰,呈非连续态。
- 只识别到亮缝的上升区或下降区,或者都没识别到。亮缝叠加了某些信息后,其特征不再是渐变特征,而是变成了不规则态。
针对上述三种常见情况,第三种因为亮缝本身的特征偏离了算法识别的核心原理,因此无法成功识别。而第一种情况,可通过开运算先腐蚀后膨胀的方式处理掉,第二种情况,可通过闭运算先膨胀后腐蚀的方式处理掉。
2.4 亮缝识别
经过图像处理后的上升掩膜和下降掩膜,分别提取其连通域轮廓信息,计算中心点;基于欧氏距离,计算上升掩膜中各个区和下降掩膜中各个区的中心点距离,取最短距离且符合先上升后下降特征的一对组合,作为目标亮缝的上升区和下降区;两区进行连接,即可得到亮缝的ROI。
2.5 算法流程图
综上,该算法的流程图可简化为:
三、代码分享
main.cpp
#include "globalfunc.h"int main()
{// 文件夹目录string folder = "data/";// 文件路径string path;path = folder + "1.his";// 读取源数据cv::Mat src = GlobalFunc::readHisPicture(path);// 基于梯度统计学的渐变型亮缝识别算法(单缝)cv::Mat look;cv::Rect roi;bool findFlag = GlobalFunc::identifyBrightSeamBasedOnGradientStatistics(src, look, roi);// 显示imshow("Ori", src);imshow("Result", look);cv::waitKey(0);return 0;
}
本文仅用于本人复盘技术思路,C++完整代码不进行分享,有想要技术交流的同学可以私聊我,大家共同进步。