1. 程式人生 > >區域生長演算法的一種C++實現

區域生長演算法的一種C++實現

https://www.cnblogs.com/xuhui24/p/6262011.html

 

區域生長演算法是一種影象分割方法,能夠將影象中具有相同特徵的連通區域分割出來,同時保證較好的邊緣資訊。

  區域生長演算法的優點是簡單,容易實現;但空間和時間複雜度較高,對分割影象要求較高,否則容易形成孔洞和過分割。

  區域生長演算法的基本思想是首先獲取分割區域的一個種子點,然後在種子點的周圍搜尋與該種子點有相似性質的畫素點,合併到種子區域中。然後將合併的畫素作為新的種子點繼續搜尋,直到種子區域中所有畫素周圍沒有相似的畫素點,演算法結束。

  如果要實現區域生長演算法,基本演算法流程是:

  1. 選取種子點p(x0,y0),用堆疊表示種子區域,將種子點push到種子堆疊中

  2. 將種子堆疊中第一個種子點pop出堆疊,並以該點為中心,遍歷該中心8鄰域畫素

  3. 判斷遍歷畫素點是否已經在種子區域中,如果否,判斷遍歷畫素點是否滿足相鄰種子點相似性,如果畫素點(x,y)滿足相似性,將(x,y)push到堆疊中

  4. 重複步驟 2-3,直至種子堆疊為空。

  從基本思想可以知道,影響區域生長演算法的要素有三個:種子點的選取搜尋路徑的選擇畫素相似性的判斷

  種子點的選取:一般情況下,區域生長演算法是半互動式的分割演算法,需要使用者選取種子點。也可以是通過其他演算法計算出來的種子點。

  搜尋路徑的選擇:搜尋路徑一般選擇相鄰的畫素,以二維影象為例,一般為8鄰域搜尋,或者4鄰域搜尋;以三維影象為例,一般為26鄰域搜尋或者6鄰域搜尋。

  畫素相似性的判斷:相似性一般以畫素值的相近程度為判斷標準,例如,可以設定一定灰度範圍做為相似的標準。也可以通過計算滿足某種形狀或者性質作為判斷標準。

  接著根據上文中提到的演算法,作者提出一種C++的實現方法,該實現不基於任何類庫,以二維影象為例,假設影象的資料型別為char型。

首先,為了便於操作,需要定義種子點的類:

class Point2D
{
public:
    Point2D(){}
    Point2D(int ix, int iy)
    {
        this->x = ix;
        this->y = iy;
    }

    ~Point2D(){}

    Point2D operator+(const Point2D& a) const
    {
        return Point2D(x + a.x, y + a.y);
    }

    Point2D operator-(const Point2D& a) const
    {
        return Point2D(x - a.x, y - a.y);
    }

    bool operator=(const Point2D & a)
    {
        return (x == a.x && y == a.y);
    }

    int x;
    int y;
};

 

然後,定義種子點的鄰域資訊:

 

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;
};

 

然後,是區域生長演算法類的實現:

#include "RegionGrowing.h"
#include <stack>

RegionGrowing::RegionGrowing()
{
    this->InputData = nullptr;
    this->OutputData = nullptr;
}

RegionGrowing::~RegionGrowing()
{

}

void RegionGrowing::SetInputData(char *pData, int width, int height)
{
    this->InputData = pData;
    this->Width = width;
    this->Height = height;
}

void RegionGrowing::SetSeedPoint(Point2D &p)
{
    this->SeedPoint = p;
}

void RegionGrowing::SetThreshold(int low, int high)
{
    this->LowThreshold = low;
    this->HighThreshold = high;
}

bool RegionGrowing::RegionGrow2D()
{
    if (this->InputData == nullptr || this->OutputData == nullptr)
    {
        return false;
    }

    int index = this->SeedPoint.y * this->Width + this->SeedPoint.x;
    int seedValue = this->InputData[index];

    std::stack<Point2D> pointStack;
    pointStack.push(this->SeedPoint);

    memset(this->OutputData, 0, sizeof(char)*this->Width*this->Height);

    while (!pointStack.empty())
    {
        Point2D topPoint = pointStack.top();
        pointStack.pop();

        for (int i = 0; i < 8; i++)
        {
            Point2D p = topPoint + PointShift2D[i];

            index = p.y * this->Width + p.x;

            if (this->InputData[index] > this->LowThreshold &&
        this->InputData[index] < this->HighThreshold &&
              this->OutputData[index] == 0)
            {
                this->OutputData[index] = 126;
                pointStack.push(p);
            }
        }
    }

    return true;
}

char* RegionGrowing::GetOutput()
{
    return this->OutputData;
}