前段时间写了个简单的图像识别程序,主要实现了对螺丝、螺母、硬币和小扳手的识别。现在来简单地做一个总结。
该程序的主要思路如下:
- 将采集到的RGB图像转化为灰度图像
- 应用OSTU算法对图像进行阈值分割并二值化
- 使用区域生长算法将各个待检测目标提取出来
- 根据目标的形状特征对目标进行分类
接下来对各个步骤做一些分析。
图像预处理
图像预处理是本实验的第一步。其目的是将目标物体的图像从背景中分割出来,这样我们才方便做后续的识别。
首先将RGB图像转换为灰度图像,是为了去除冗余的色彩信息,同时也简化了计算。
在灰度图像的基础上在进行图像分割。我们这里采取比较简单又较为常用的阈值分割法来进行图像分割。这里使用的OSTU算法是一种具有一定自适应性的阈值分割法,网络上有许多对这个算法的详细说明,我们这里不加赘述。
区域生长
虽然通过阈值分割我们已经得到了所有目标物体的像素分布,但是仅凭这个我们无法对每个物体的特征进行分析。因为我们并不知道单独的每个目标的像素分布。所以我们要寻找一种方法,将每个物体的像素信息分布保存起来。这种方法就是区域生长算法。区域生长的核心思想就是从种子点开始向相邻的点逐点搜索,从而将整个连通区域提取出来。
以下是该部分的源代码:
//返回生长区域点的个数
int CMainFrame::RegionGrow(Point init, vector<Point> &result, int **mark)
{
stack<Point> 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/