三點區域生長演算法
阿新 • • 發佈:2018-11-08
影象分割是一種重要的影象處理技術,而區域生長是影象分割技術的一種。區域生長的基本思想是將具有相似性的畫素集合起來構成區域。首先對每個需要分割的區域找出一個種子畫素作為生長的七點,然後將種子畫素周圍鄰域中與種子有相同或相似性質的畫素(根據事先確定的生長或相似準則來確定)合併到種子畫素所在的區域中。而新的畫素繼續作為種子向四周生長,直到再沒有滿足條件的畫素可以包括進來,一個區域就生長而成了。
種子區域生長(region seeds growing, RSG)演算法在實踐中關鍵的問題是種子的選取和相似區域判定準則的確定。種子的選擇可以人工選擇,也可以通過一些方法自動選取;灰度圖的判定準則一般用灰度差值小於某個閾值來表示,不同的判定準則可能會產生不同的分割結果。
為了說明區域是如何生長的,本文從最簡單的情況出發:使用二值影象;人工選取種子;判定準則為是否是前景畫素。
區域生長實現的步驟如下:
1. 對影象順序掃描!找到第1個還沒有歸屬的畫素, 設該畫素為(x0, y0);
2. 以(x0, y0)為中心, 考慮(x0, y0)的8鄰域畫素(x, y)如果(x0, y0)滿足生長準則, 將(x, y)與(x0, y0)合併(在同一區域內), 同時將(x, y)壓入堆疊;
3. 從堆疊中取出一個畫素, 把它當作(x0, y0)返回到步驟2;
4. 當堆疊為空時!返回到步驟1;
5. 重複步驟1 - 4直到影象中的每個點都有歸屬時。生長結束。
#include <iostream> #include <stack> #include <opencv2\opencv.hpp> using namespace std; using namespace cv; // 8 鄰域 static Point connects[8] = { Point(-1, -1), Point(0, -1), Point(1, -1), Point(1, 0), Point(1, 1), Point(0, 1), Point(-1, 1), Point(-1, 0)}; int main() { // 原圖 Mat src = imread("C://6.png", 0); imshow("原圖",src); // 結果圖 Mat res = Mat::zeros(src.rows, src.cols, CV_8U); // 用於標記是否遍歷過某點 Mat flagMat; res.copyTo(flagMat); // 二值影象 Mat bin; threshold(src, bin, 80, 255, CV_THRESH_BINARY); // 初始3個種子點 stack<Point> seeds; seeds.push(Point(0, 0)); seeds.push(Point(186, 166)); seeds.push(Point(327, 43)); res.at<uchar>(0, 0) = 255; res.at<uchar>(166, 186) = 255; res.at<uchar>(43, 327) = 255; while (!seeds.empty()) { Point seed = seeds.top(); seeds.pop(); // 標記為已遍歷過的點 flagMat.at<uchar>(seed.y, seed.x) = 1; // 遍歷8鄰域 for (size_t i = 0; i < 8; i++) { int tmpx = seed.x + connects[i].x; int tmpy = seed.y + connects[i].y; if (tmpx < 0 || tmpy < 0 || tmpx >= src.cols || tmpy >= src.rows) continue; // 前景點且沒有被標記過的點 if (bin.at<uchar>(tmpy, tmpx) != 0 && flagMat.at<uchar>(tmpy, tmpx) == 0) { res.at<uchar>(tmpy, tmpx) = 255; // 生長 flagMat.at<uchar>(tmpy, tmpx) = 1; // 標記 seeds.push(Point(tmpx, tmpy)); // 種子壓棧 } } } imshow("三點區域生長演算法效果圖",res); imwrite("4.jpg", res); waitKey(0); return 1; }
上面的程式碼通過人工選擇了三個種子,它們在原圖中的大致位置如下(紅色十字中心):
區域生長的過程:
大致的可以看見 瞳孔裡面的 光斑消失不見了! 三點區域生長演算法可以去除光斑。