前段時間寫了個簡單的圖像識別程序,主要實現了對螺絲、螺母、硬幣和小扳手的識別。現在來簡單地做一個總結。
該程序的主要思路如下:
- 將采集到的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/