區域生長算法是一種圖像分割方法,能夠將圖像中具有相同特征的連通區域分割出來,同時保證較好的邊緣信息。
區域生長算法的優點是簡單,容易實現;但空間和時間復雜度較高,對分割圖像要求較高,否則容易形成孔洞和過分割。
區域生長算法的基本思想是首先獲取分割區域的一個種子點,然后在種子點的周圍搜索與該種子點有相似性質的像素點,合並到種子區域中。然后將合並的像素作為新的種子點繼續搜索,直到種子區域中所有像素周圍沒有相似的像素點,算法結束。
如果要實現區域生長算法,基本算法流程是:
1. 選取種子點p(x0,y0),用堆棧表示種子區域,將種子點push到種子堆棧中
2. 將種子堆棧中第一個種子點pop出堆棧,並以該點為中心,遍歷該中心8鄰域像素
3. 判斷遍歷像素點是否已經在種子區域中,如果否,判斷遍歷像素點是否滿足相鄰種子點相似性,如果像素點(x,y)滿足相似性,將(x,y)push到堆棧中
4. 重復步驟 2-3,直至種子堆棧為空。
從基本思想可以知道,影響區域生長算法的要素有三個:種子點的選取;搜索路徑的選擇;像素相似性的判斷。
種子點的選取:一般情況下,區域生長算法是半交互式的分割算法,需要用戶選取種子點。也可以是通過其他算法計算出來的種子點。
搜索路徑的選擇:搜索路徑一般選擇相鄰的像素,以二維圖像為例,一般為8鄰域搜索,或者4鄰域搜索;以三維圖像為例,一般為26鄰域搜索或者6鄰域搜索。
像素相似性的判斷:相似性一般以像素值的相近程度為判斷標准,例如,可以設置一定灰度范圍做為相似的標准。也可以通過計算滿足某種形狀或者性質作為判斷標准。
接着根據上文中提到的算法,作者提出一種C++的實現方法,該實現不基於任何類庫,以二維圖像為例,假設圖像的數據類型為char型。
首先,為了便於操作,需要定義種子點的類:
1 class Point2D 2 { 3 public: 4 Point2D(){} 5 Point2D(int ix, int iy) 6 { 7 this->x = ix; 8 this->y = iy; 9 } 10 11 ~Point2D(){} 12 13 Point2D operator+(const Point2D& a) const 14 { 15 return Point2D(x + a.x, y + a.y); 16 } 17 18 Point2D operator-(const Point2D& a) const 19 { 20 return Point2D(x - a.x, y - a.y); 21 } 22 23 bool operator=(const Point2D & a) 24 { 25 return (x == a.x && y == a.y); 26 } 27 28 int x; 29 int y; 30 };
然后,定義種子點的鄰域信息:
const Point2D PointShift2D[8] = { Point2D(1, 0), Point2D(1, -1), Point2D(0, -1), Point2D(-1, -1), Point2D(-1, 0), Point2D(-1, 1), Point2D(0, 1), Point2D(1, 1) };
然后,定義區域生長算法類的頭文件:
class RegionGrowing { public: RegionGrowing(); ~RegionGrowing(); void SetInputData(char *pData, int width, int height); void SetSeedPoint(Point2D &p); void SetThreshold(int low, int hight); bool RegionGrow2D(); char* GetOutput(); private: int LowThreshold; int HighThreshold; int Width; int Height; char *InputData; char *OutputData; Point2D SeedPoint; };
然后,是區域生長算法類的實現:
1 #include "RegionGrowing.h" 2 #include <stack> 3 4 RegionGrowing::RegionGrowing() 5 { 6 this->InputData = nullptr; 7 this->OutputData = nullptr; 8 } 9 10 RegionGrowing::~RegionGrowing() 11 { 12 13 } 14 15 void RegionGrowing::SetInputData(char *pData, int width, int height) 16 { 17 this->InputData = pData; 18 this->Width = width; 19 this->Height = height; 20 } 21 22 void RegionGrowing::SetSeedPoint(Point2D &p) 23 { 24 this->SeedPoint = p; 25 } 26 27 void RegionGrowing::SetThreshold(int low, int high) 28 { 29 this->LowThreshold = low; 30 this->HighThreshold = high; 31 } 32 33 bool RegionGrowing::RegionGrow2D() 34 { 35 if (this->InputData == nullptr || this->OutputData == nullptr) 36 { 37 return false; 38 } 39 40 int index = this->SeedPoint.y * this->Width + this->SeedPoint.x; 41 int seedValue = this->InputData[index]; 42 43 std::stack<Point2D> pointStack; 44 pointStack.push(this->SeedPoint); 45 46 memset(this->OutputData, 0, sizeof(char)*this->Width*this->Height); 47 48 while (!pointStack.empty()) 49 { 50 Point2D topPoint = pointStack.top(); 51 pointStack.pop(); 52 53 for (int i = 0; i < 8; i++) 54 { 55 Point2D p = topPoint + PointShift2D[i]; 56 57 index = p.y * this->Width + p.x; 58 59 if (this->InputData[index] > this->LowThreshold && 60 this->InputData[index] < this->HighThreshold && 61 this->OutputData[index] == 0) 62 { 63 this->OutputData[index] = 126; 64 pointStack.push(p); 65 } 66 } 67 } 68 69 return true; 70 } 71 72 char* RegionGrowing::GetOutput() 73 { 74 return this->OutputData; 75 }
聲明本博客文章未特殊注明均為原創,轉載請注明作者和原地址
