一个极其简单的图像识别小程序

前段时间写了个简单的图像识别程序,主要实现了对螺丝、螺母、硬币和小扳手的识别。现在来简单地做一个总结。
该程序的主要思路如下:

  1. 将采集到的RGB图像转化为灰度图像
  2. 应用OSTU算法对图像进行阈值分割并二值化
  3. 使用区域生长算法将各个待检测目标提取出来
  4. 根据目标的形状特征对目标进行分类

接下来对各个步骤做一些分析。

图像预处理

图像预处理是本实验的第一步。其目的是将目标物体的图像从背景中分割出来,这样我们才方便做后续的识别。
首先将RGB图像转换为灰度图像,是为了去除冗余的色彩信息,同时也简化了计算。
在灰度图像的基础上在进行图像分割。我们这里采取比较简单又较为常用的阈值分割法来进行图像分割。这里使用的OSTU算法是一种具有一定自适应性的阈值分割法,网络上有许多对这个算法的详细说明,我们这里不加赘述。

区域生长

虽然通过阈值分割我们已经得到了所有目标物体的像素分布,但是仅凭这个我们无法对每个物体的特征进行分析。因为我们并不知道单独的每个目标的像素分布。所以我们要寻找一种方法,将每个物体的像素信息分布保存起来。这种方法就是区域生长算法。区域生长的核心思想就是从种子点开始向相邻的点逐点搜索,从而将整个连通区域提取出来。
以下是该部分的源代码:

//返回生长区域点的个数
int CMainFrame::RegionGrow(Point init, vector &result, int **mark)
{
    stack seedStack;
    Point seed(0,0);
    int n = 0;  //区域内点的数量

    mark[init.y][init.x] = 1;
    seedStack.push(init);
    Point tmp(seed.x,seed.y);
    while (1)
    {
        seed = seedStack.top();
        seedStack.pop();
        if(seed.x < m_pBmpInfo->bmiHeader.biWidth-1)
        {
            tmp.x = seed.x + 1;
            tmp.y = seed.y;
            if(!mark[tmp.y][tmp.x] && gImageBuffer[tmp.y*m_pBmpInfo->bmiHeader.biWidth+tmp.x] == 0)
            {
                seedStack.push(tmp);
                result.push_back(tmp);
                mark[tmp.y][tmp.x] = 1;    //将已被生长的点标记为1
                n++;    //区域点的数量加一
            }
        }
        if(seed.y < m_pBmpInfo->bmiHeader.biHeight-1)
        {
            tmp.x = seed.x;
            tmp.y = seed.y + 1;
            if(!mark[tmp.y][tmp.x] && gImageBuffer[tmp.y*m_pBmpInfo->bmiHeader.biWidth+tmp.x] == 0)
            {
                seedStack.push(tmp);
                result.push_back(tmp);
                mark[tmp.y][tmp.x] = 1; 
                n++;
            }
        }
        if(seed.x > 0)
        {
            tmp.x = seed.x - 1;
            tmp.y = seed.y;
            if(!mark[tmp.y][tmp.x] && gImageBuffer[tmp.y*m_pBmpInfo->bmiHeader.biWidth+tmp.x] == 0)
            {
                seedStack.push(tmp);
                result.push_back(tmp);
                mark[tmp.y][tmp.x] = 1; 
                n++;
            }
        }
        if(seed.y > 0)
        {
            tmp.x = seed.x;
            tmp.y = seed.y - 1;
            if(!mark[tmp.y][tmp.x] && gImageBuffer[tmp.y*m_pBmpInfo->bmiHeader.biWidth+tmp.x] == 0)
            {
                seedStack.push(tmp);
                result.push_back(tmp);
                mark[tmp.y][tmp.x] = 1;  
                n++;
            }
        }

        if(seedStack.empty())
            break;
    }
    return n;
}

目标识别

在得到了各个目标的像素信息后,如何对目标进行分类呢?由于我们要识别的物体仅限于螺丝、螺母、硬币这样形状简单的物体,我们只需通过一些简单的特征就能将他们区分开来。

  • 螺母的中心为空,而螺丝、小扳手均为实心
  • 小扳手为L形的细杆,其长轴和短轴之比远大于螺丝
  • 硬币为圆形

凭借以上三条规则,就足以将螺丝、螺母、硬币和扳手区分开来了。

小结

本文主要是整理思路,细节的地方并未涉及,希望能对读者有一些帮助~
P.S. 此文在我新搭建的独立博客亦有发表:
http://cyanair.me/2016/03/31/a-simple-objection-recognition-program/

你可能感兴趣的:(一个极其简单的图像识别小程序)