A-A+

[Motion] 移动检测开源代码Motion学习 — 去杂算法

2017年12月13日 Motion, 关键技术 评论 1 条 阅读 1,068 次

在学习Motion代码的算法部分,在去杂的算法上,motion选择了使用腐蚀(erode)和膨胀(dilate)开运算则方式来进行去杂运算。有erode9/5、dilate9/5分别两种级别的腐蚀和膨胀算法,9指使用的集合是3x3九宫格形式的,5指使用十字行5个格子的形式。

Motion去杂函数如下:


/**
 * alg_despeckle
 *      Despeckling routine to remove noisy detections.
 */
int alg_despeckle(struct context *cnt, int olddiffs)
{
    int diffs = 0;
    unsigned char *out = cnt->imgs.img_motion.image_norm;
    int width = cnt->imgs.width;
    int height = cnt->imgs.height;
    int done = 0, i, len = strlen(cnt->conf.despeckle_filter);
    unsigned char *common_buffer = cnt->imgs.common_buffer;

    for (i = 0; i < len; i++) { switch (cnt->conf.despeckle_filter[i]) {
        case 'E':
            if ((diffs = erode9(out, width, height, common_buffer, 0)) == 0)
                i = len;
            done = 1;
            break;
        case 'e':
            if ((diffs = erode5(out, width, height, common_buffer, 0)) == 0)
                i = len;
            done = 1;
            break;
        case 'D':
            diffs = dilate9(out, width, height, common_buffer);
            done = 1;
            break;
        case 'd':
            diffs = dilate5(out, width, height, common_buffer);
            done = 1;
            break;
        /* No further despeckle after labeling! */
        case 'l':
            diffs = alg_labeling(cnt);
            i = len;
            done = 2;
            break;
        }
    }

    /* If conf.despeckle_filter contains any valid action EeDdl */
    if (done) {
        if (done != 2)
            cnt->imgs.labelsize_max = 0; // Disable Labeling
        return diffs;
    } else {
        cnt->imgs.labelsize_max = 0; // Disable Labeling
    }

    return olddiffs;
}

腐蚀和膨胀是数学形态学上的名词,如果用于图像处理上则就称为图像二值形态学。
形态学主要是为了获取物体的拓扑和结构信息,通过物体和结构元素相互作用的某些运算,得到物体更本质的形态。当形态学运用到图像处理中,它的主要作用是利用形态学的基本运算,如腐蚀和膨胀运算,对图像进行观察和处理,从而达到改善图像质量的目地;描述和定义图像的各种几何参数和特征。

二值图像的腐蚀和膨胀操作

腐蚀&膨胀的具体操作

用一个结构元素(也可以说成操作数矩阵)一般为3×3大小的,也可以看成一个卷积模板,它们的区别就在于卷积模板是以算术运算为基础的,而结构元素是以集合运算为基础的。扫描图像中的每一个像素(关于图像边缘的处理见下面详细分析),用操作数矩阵扫描图像中的每一个像素,操作数矩阵中每一个像素与覆盖的像素做“与”操作,如果全部为1,则图像中的该像素为1,反之为0,而膨胀操作正好相反,全部为0时,则图像素中的该像素为0,反之为1。

腐蚀的作用是消除物体的边界点,使目标缩小,这个根据操作的过程可以显然的想到,物体的边界处像素值肯定是有0和1,腐蚀操作后这些紧邻着为1的像素点都会变成0,所以腐蚀操作会消除那些小的且无意义的物体,使边界向内部收缩的过程。相反,膨胀的作用当然是使目标增大,填充物体内细小的空洞,并且平滑物体的边界,边界向外部扩张的作用。

开运算和闭运算

开运算是先腐蚀后膨胀的过程,可以消除图像上细小的噪声,并平滑物体的边界。
闭运算是先膨胀后腐蚀的过程,可以填充物体内细小的空洞,并平滑物体边界。
注:在Motion中,默认配置中使用的是开运算,先腐蚀2次再膨胀2次,分别对应的函数是erode9-erode5-dilate5-dilate9。推荐使用默认配置。

通常,由于噪声的影响,图象在阈值化后所得到边界往往是很不平滑的,物体区域具有一些噪声孔,背景区域上散布着一些小的噪声物体。连续的开和闭运算可以有效地改善这种情况。有时需要经过多次腐蚀之后再加上相同次数的膨胀,才可以产生比较好的效果。

图像边缘的腐蚀和膨胀运算

结构元素在扫描图像中的每个像素时,结构元素的邻域有部分会在图像外面。比如当结构元素扫描图像上方第一行像素值(这里默认结构元素为3×3),结构元素会有部分在图像的外面,此时,为了有效处理边界像素,进行形态学运算的函数通常都会给出超出图像、未指定数值的像素指定一个数值,这样就类似于函数给图像填充了额外的行和列。对于膨胀和腐蚀操作,它们对像素进行填充的值是不同的。规则如下:

腐蚀:超出图像边界的像素值定义为该数据类型允许的最大值,对于二进制图像,这些像素值设置为1;对于灰度图像,unit8类型的最小值也为255。

膨胀:超出图像边界的像素值定义为该数据类型允许的最小值,对于二进制图像,这些像素值设置为0;对于灰度图像,unit8类型的最小值也为0。

通过对膨胀操作使用最小值填充和对腐蚀操作使用最大值填充,可以有效地消除边界效应(输出图像靠近边界处的区域与图像其它部分不连续)。否则,如果腐蚀操作使用最小值进行填充,则进行腐蚀操作后,输出图像会围绕着一个黑色边框。(此处根据腐蚀和膨胀的具体操作过程应该不难理解,因为当图像边缘都是白色时也就是像素值全为1,此时如果图像边缘外面的像素值填充为最小值,如果二值图像的话则像素值为0,根据腐蚀操作,相与后肯定为0,这时图像边缘处便会成为黑色)。

结构元素

膨胀和腐蚀操作的最基本组成部分,用于测试输出图像,通常要比待处理的图像小的多。二维平面结构元素由一个数值为0或1的矩阵组成。结构元素的原点指定了图像中需要处理的像素范围,结构元素中数值为1的点决定结构元素的邻域像素在进行膨胀或腐蚀操作时是否需要参与计算。三维或非平面的结构元素使用0,1定义结构元素在x和y平面上的范围,第三维z定义高度。

Motion上腐蚀和膨胀的算法解析

TODO

1 条留言  访客:0 条  博主:0 条   引用: 1 条

来自外部的引用: 1 条

  • [Motion] 移动检测开源代码Motion学习 — 重要变量或结构 | 码农部落

给我留言