Pixy原理及Opencv实现

版权声明: https://blog.csdn.net/wubaobao1993/article/details/54809558

Pixy原理

Pixy的基本思想其实是简单的:利用颜色空间来除去所有用户不感兴趣的背景,提取出前景。但是在实际的环境下却并不好做,特别是摄像头看到的颜色会受到光线的影响,导致颜色的变化(对于这一点,笔者觉得确实是没有办法的,比如红色在黑暗的条件下确实看起来是红色,那么依靠任何颜色空间看到的其实都是黑色,无法区别),因此,对于Pixy这样神奇的产品来讲,他的识别也需要颜色尽量鲜艳,饱和度尽量好的物体,对于背景来讲,也尽量是光线较好、不突变的环境。否则Pixy是“学习”不来的。

在笔者看到的Pixy的对于颜色处理的源码中,其核心思想有2个部分,这也是笔者借鉴最多的地方:

1、对像素点的处理
Pixy接收到摄像头的信息格式应该是YUV格式的,在源码的colorlut.cpp的nextHelper函数中,Pixy做了两件事:1、将YUV转为RGB的;2、处理该像素值得到U和V的值,这里的U和V并不是YUV中的UV通道,而是经过了处理,具体处理的代码如下:其中CL_LUT_ENTRY_SCALE变量为15

        if (uv)
        {
            c = r+g1+b;
            if (c<miny)
            {
                m_x += 2;
                continue;
            }
            u = ((r-g1)<<CL_LUT_ENTRY_SCALE)/c;
            c = r+g2+b;
            if (c<miny)
            {
                m_x += 2;
                continue;
            }
            v = ((b-g2)<<CL_LUT_ENTRY_SCALE)/c;

            uv->m_u = u;
            uv->m_v = v;
        }
    这样做的好处是在U和V的值中,加入亮度的影响,这样得到的U和V值就考虑到了光线亮度对于物体颜色的影响。

2、对感兴趣域的比较统计
对于得到的U和V,Pixy将其作为“学习”的依据,即下面的学习算法均是依靠此处的U和V来进行的,在colorlut.cpp的calcRatios函数中,Pixy对于得到的U和V值进行了如下处理:其中sig是个结构体,其中的元素代表该感兴趣前景的U和V的上下阈值

    while(ip->next(&uv))
    {
        if (uv.m_u>sig->m_uMin)
            counts[0]++;

        if (uv.m_u<sig->m_uMax)
            counts[1]++;

        if (uv.m_v>sig->m_vMin)
            counts[2]++;

        if (uv.m_v<sig->m_vMax)
            counts[3]++;

        n++;
    }

    // calc ratios
    ratios[0] = (float)counts[0]/n;
    ratios[1] = (float)counts[1]/n;
    ratios[2] = (float)counts[2]/n;
    ratios[3] = (float)counts[3]/n;
    // calc mean (because it's cheap to do it here)
    sig->m_uMean = (sig->m_uMin + sig->m_uMax)/2;
    sig->m_vMean = (sig->m_vMin + sig->m_vMax)/2;
    在上段代码中,Pixy对用户给出区域的像素点与上下阈值进行比较统计,得到的统计值决定了“学习”的方向。

3、根据统计进行“学习”
由上部分得到的ratios数组表征了用户给定区域的像素在该阈值左右的分布,假定给定一个该分布情况的界限,则阈值就可以根据当前分布与给定分布之间的大小进行自动调整(Pixy默认的界限是80%,即该阈值可以提取出图像区域80%的像素值):以U值为例,当图像在该阈值作用下,大于U阈值最小值的像素点有90%,则说明U阈值的最小值过小,此时应该向下调整,使该阈值增大,反之则反之。具体的代码见下: 其中m_ratio为0.8

for (scale=1<<30, sig->m_uMin=sig->m_uMax=sig->m_vMin=sig->m_vMax=0; scale!=0; scale>>=1)
    {
        calcRatios(ip, sig, ratios);
        if (ratios[0]>m_ratio)
            sig->m_uMin += scale;
        else
            sig->m_uMin -= scale;

        if (ratios[1]>m_ratio)
            sig->m_uMax -= scale;
        else
            sig->m_uMax += scale;

        if (ratios[2]>m_ratio)
            sig->m_vMin += scale;
        else
            sig->m_vMin -= scale;

        if (ratios[3]>m_ratio)
            sig->m_vMax -= scale;
        else
            sig->m_vMax += scale;
    }
    根据上述代码可以看到,Pixy在学习的过程中对一幅图像(用户感兴趣)学习了30次,最终根据反馈得到了较好的阈值。

Opencv实现

其实知道了原理之后,想用Opencv对一幅图像进行处理并得到较好的阈值是比较容易的,笔者也对该算法进行了尝(chao)试(xi),但是效果十分不好,1、不能进行较好的前景提取;2、处理速度十分慢。对于以上两个问题,个人认为还是对于YUV的格式没有把握好,导致中间运算出现问题(悼念三分钟尝试失败)。

但是笔者并没有放弃,把该算法移植到了HSV空间上,说是移植,其实中间去掉了一些处理,比如移植的算法没有考虑亮度对颜色的影响(> <),但是确实可以给定一个区域进行自“学习”了,收获还是不小,想要进行参考的同学可以到该地址进行下载http://download.csdn.net/detail/wubaobao1993/9745837

最后上两个图,是该算法的实际效果
这里写图片描述

猜你喜欢

转载自blog.csdn.net/wubaobao1993/article/details/54809558