0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

分水嶺算法(理論+opencv實現(xiàn))

lviY_AI_shequ ? 來源:未知 ? 作者:李建兵 ? 2018-03-17 11:06 ? 次閱讀

???把圖像用一維坐標表示,二維和三維不好畫,必須用matlab了,我不會用,意思可以表述到位

第一步:找到圖像的局部最低點,這個方法很多了,可以用一個內(nèi)核去找,也可以一個一個比較,實現(xiàn)起來不難。

第二步:從最低點開始注水,水開始網(wǎng)上滿(圖像的說法就是梯度法),其中那些最低點已經(jīng)被標記,不會被淹沒,那些中間點是被淹沒的。

第三步:找到局部最高點,就是圖中3位置對應的兩個點。

第四步:這樣基于局部最小值,和找到的局部最大值,就可以分割圖像了。

分類圖

模擬結果圖

是不是感覺上面的方法很好,也很簡單?接著看下面的圖:

利用上面的步驟,第一步找到了三個點,然后第二步開始漫水,這三個點都被記錄下來了,又找到兩個局部最大值。

這是我們想要的嗎?

回答是否定的!其中中間那個最小值我們不需要,因為只是一個很少并且很小的噪點而已,我們不需要圖像分割的那么細致。

缺陷顯露出來了吧?沒關系,下面我們的opencv把這個問題解決了。

模擬分類圖

模擬結果圖

opencv改進的分水嶺算法

針對上面出現(xiàn)的問題,我們想到的是能不能給這種小細節(jié)一個標記,讓它不屬于我們找的最小的點呢?

opencv對其改進就是使用了人工標記的方法,我們標記一些點,基于這些點去引導分水嶺算法的進行,效果很好!

比如我們對上面的圖像標記了兩個三角形,第一步我們找到三個局部最小點,第二步淹沒的時候三個點都被淹沒了,然而中間那個沒被標記,那就淹死了(沒有救生圈),其余兩個點保留,這樣就可以達到我們的想要的結果了。

注釋:這里的標記是用不同的標號進行的,我為了方便使用了同樣的三角形了。因為標記用來分類,所以不同的標記打上不同的標號!這在下面opencv程序中體現(xiàn)了。。。

模擬分類圖

模擬結果圖

注釋:具體的實現(xiàn)沒有完成,感覺原理懂了會使用了這樣就可以了,當你需要深入的時候再去研究實現(xiàn)的算法,當你淺淺的使用懂了原理應該會改一點,面試過了完全可以??!哈哈哈~~

opencv實現(xiàn):

#include

#include

using namespace cv;

using namespace std;

void waterSegment(InputArray& _src, OutputArray& _dst, int& noOfSegment);

int main(int argc, char** argv) {

Mat inputImage = imread("coins.jpg");

assert(!inputImage.data);

Mat graImage, outputImage;

int offSegment;

waterSegment(inputImage, outputImage, offSegment);

waitKey(0);

return 0;

}

void waterSegment(InputArray& _src,OutputArray& _dst,int& noOfSegment)

{

Mat src = _src.getMat();//dst = _dst.getMat();

Mat grayImage;

cvtColor(src, grayImage,CV_BGR2GRAY);

threshold(grayImage, grayImage, 0, 255, THRESH_BINARY | THRESH_OTSU);

Mat kernel = getStructuringElement(MORPH_RECT, Size(9, 9), Point(-1, -1));

morphologyEx(grayImage, grayImage, MORPH_CLOSE, kernel);

distanceTransform(grayImage, grayImage, DIST_L2, DIST_MASK_3, 5);

normalize(grayImage, grayImage,0,1, NORM_MINMAX);

grayImage.convertTo(grayImage, CV_8UC1);

threshold(grayImage, grayImage,0,255, THRESH_BINARY | THRESH_OTSU);

morphologyEx(grayImage, grayImage, MORPH_CLOSE, kernel);

vector> contours;

vector hierarchy;

Mat showImage = Mat::zeros(grayImage.size(), CV_32SC1);

findContours(grayImage, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(-1, -1));

for (size_t i = 0; i < contours.size(); i++)

{

//這里static_cast(i+1)是為了分水嶺的標記不同,區(qū)域1、2、3。。。。這樣才能分割

drawContours(showImage, contours, static_cast(i), Scalar::all(static_cast(i+1)), 2);

}

Mat k = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));

morphologyEx(src, src, MORPH_ERODE, k);

watershed(src, showImage);

//隨機分配顏色

vector colors;

for (size_t i = 0; i < contours.size(); i++) {

int r = theRNG().uniform(0, 255);

int g = theRNG().uniform(0, 255);

int b = theRNG().uniform(0, 255);

colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));

}

// 顯示

Mat dst = Mat::zeros(showImage.size(), CV_8UC3);

int index = 0;

for (int row = 0; row < showImage.rows; row++) {

for (int col = 0; col < showImage.cols; col++) {

index = showImage.at(row, col);

if (index > 0 && index <= contours.size()) {

dst.at(row, col) = colors[index - 1];

}

else if (index == -1)

{

dst.at(row, col) = Vec3b(255, 255, 255);

}

else {

dst.at(row, col) = Vec3b(0, 0, 0);

}

}

}

}

分水嶺合并代碼:

void segMerge(Mat& image, Mat& segments, int& numSeg)

{

vector samples;

int newNumSeg = numSeg;

//初始化變量長度的Vector

for (size_t i = 0; i < newNumSeg; i++)

{

Mat sample;

samples.push_back(sample);

}

for (size_t i = 0; i < segments.rows; i++)

{

for (size_t j = 0; j < segments.cols; j++)

{

int index = segments.at(i, j);

if (index >= 0 && index <= newNumSeg)//把同一個區(qū)域的點合并到一個Mat中

{

if (!samples[index].data)//數(shù)據(jù)為空不能合并,否則報錯

{

samples[index] = image(Rect(j, i, 1, 1));

}

else//按行合并

{

vconcat(samples[index], image(Rect(j, i, 2, 1)), samples[index]);

}

}

//if (index >= 0 && index <= newNumSeg)

// samples[index].push_back(image(Rect(j, i, 1, 1)));

}

}

vector hist_bases;

Mat hsv_base;

int h_bins = 35;

int s_bins = 30;

int histSize[2] = { h_bins , s_bins };

float h_range[2] = { 0,256 };

float s_range[2] = { 0,180 };

const float* range[2] = { h_range,s_range };

int channels[2] = { 0,1 };

Mat hist_base;

for (size_t i = 1; i < numSeg; i++)

{

if (samples[i].dims > 0)

{

cvtColor(samples[i], hsv_base, CV_BGR2HSV);

calcHist(&hsv_base, 1, channels, Mat(), hist_base, 2, histSize, range);

normalize(hist_base, hist_base, 0, 1, NORM_MINMAX);

hist_bases.push_back(hist_base);

}

else

{

hist_bases.push_back(Mat());

}

}

double similarity = 0;

vector merged;//是否合并的標志位

for (size_t i = 0; i < hist_bases.size(); i++)

{

for (size_t j = i+1; j < hist_bases.size(); j++)

{

if (!merged[j])//未合并的區(qū)域進行相似性判斷

{

if (hist_bases[i].dims > 0 && hist_bases[j].dims > 0)//這里維數(shù)判斷沒必要,直接用個data就可以了

{

similarity = compareHist(hist_bases[i], hist_bases[j], HISTCMP_BHATTACHARYYA);

if (similarity > 0.8)

{

merged[j] = true;//被合并的區(qū)域標志位true

if (i != j)//這里沒必要,i不可能等于j

{

newNumSeg --;//分割部分減少

for (size_t p = 0; p < segments.rows; p++)

{

for (size_t k = 0; k < segments.cols; k++)

{

int index = segments.at(p, k);

if (index == j) segments.at(p, k) = i;

}

}

}

}

}

}

}

}

numSeg = newNumSeg;//返回合并之后的區(qū)域數(shù)量

}

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • OpenCV
    +關注

    關注

    29

    文章

    624

    瀏覽量

    41214

原文標題:分水嶺算法(理論+opencv實現(xiàn))

文章出處:【微信號:AI_shequ,微信公眾號:人工智能愛好者社區(qū)】歡迎添加關注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關推薦

    關于分水嶺的圖像分割求指點

    `我想對這幅圖像中的水稻進行圖像分割,采取了基于控制標記的距離變換分水嶺分割程序如下rgb = imread('C:UserschenxuanDesktop稻子原圖.jpg&
    發(fā)表于 08-27 13:46

    【HiSpark IPC DIY Camera試用連載 】第三篇 分水嶺算法測試

    自己唯一的編號,輪廓的定位可以通過Opencv中findContours方法實現(xiàn),這個是執(zhí)行 分水嶺之前的要求。接下來執(zhí)行分水嶺會發(fā)生什么呢?算法
    發(fā)表于 01-21 23:38

    分水嶺算法在重疊細胞圖象分割中的應用

    分水嶺算法是一種廣泛使用的分割方法,將其用于細胞圖象分割可以克服由于細胞交疊造成的圖象分析困難,但缺陷在于它的過分割結果。本文給出一種針對分水嶺過分割問題的解
    發(fā)表于 06-26 08:31 ?24次下載

    多晶硅“門檻”定調(diào):2010或成行業(yè)分水嶺

    多晶硅“門檻”定調(diào):2010或成行業(yè)分水嶺   山雨欲來,一場多晶硅行業(yè)的政策風暴正在醞釀。   近日,記者獨家獲
    發(fā)表于 02-01 10:04 ?523次閱讀

    分水嶺算法_《OpenCV3編程入門》書本配套源代碼

    OpenCV3編程入門》書本配套源代碼:分水嶺算法
    發(fā)表于 06-06 15:39 ?8次下載

    OpenCV3編程入門-源碼例程全集-分水嶺算法

    OpenCV3編程入門-源碼例程全集-分水嶺算法,感興趣的小伙伴們可以瞧一瞧。
    發(fā)表于 09-18 16:55 ?0次下載

    基于分水嶺算法的尿沉渣圖像處理方法研究_逄涵涵

    基于分水嶺算法的尿沉渣圖像處理方法研究_逄涵涵
    發(fā)表于 03-17 09:41 ?2次下載

    一種新的彩色圖像分割算法

    本文提出一種新的結合分水嶺與種子區(qū)域生成、區(qū)域合并的彩色圖像分割算法。首先將RGB顏色空間轉(zhuǎn)換成HSI間,應用分水嶺算法對圖像進行初始化分割,形成過分割效果。接著基于
    發(fā)表于 12-14 14:41 ?1次下載
    一種新的彩色圖像分割<b class='flag-5'>算法</b>

    2018年將為全球供應鏈數(shù)碼化分水嶺

    據(jù)報導,隨著企業(yè)積極響應政府和政府間組織的新倡議,2018年將成為全球供應鏈數(shù)碼化的分水嶺。而能促成全球供應鏈數(shù)碼化的關鍵,可從下面幾格趨勢來觀察:
    發(fā)表于 01-22 08:43 ?1058次閱讀

    中國互聯(lián)網(wǎng)未來5年趨勢是如何的?分水嶺大時代到來。

    報告指出,分水嶺大時代即將到來:“分水嶺”將成為未來五年中國互聯(lián)網(wǎng)的關鍵詞;從淺水區(qū)向深水區(qū)過度,引發(fā)競爭格局的強弱勢轉(zhuǎn)化;分水嶺區(qū)不存在直道競爭,冷靜和變化成為主旋律。
    的頭像 發(fā)表于 09-09 09:18 ?6631次閱讀

    國產(chǎn)手機市場的爭奪還在繼續(xù) 華為小米手機業(yè)務走到了分水嶺

    2018年對小米和華為來說是一個轉(zhuǎn)折點。國產(chǎn)手機市場的爭奪還在繼續(xù),但是兩家的業(yè)務布局在悄然變化,手機業(yè)務對集團的戰(zhàn)略支撐,走到了分水嶺
    發(fā)表于 12-19 14:10 ?1197次閱讀

    “史上最嚴”能效令發(fā)布 空調(diào)市場即將迎來分水嶺

    近日,隨著“史上最嚴”空調(diào)能效標準發(fā)布這一權威消息不脛而走,深陷價格戰(zhàn)泥潭的空調(diào)市場即將迎來分水嶺。記者從相關渠道獲悉,長虹空調(diào)將繼主推的超一級能效產(chǎn)品Q5Ks之后,即可發(fā)布兩款新品——Q5A好睡眠空調(diào)和Q5D AI舒適空調(diào),搶占能效調(diào)整帶來的最大一波變頻紅利。
    發(fā)表于 01-06 10:05 ?531次閱讀

    站在從4G向5G跨越的分水嶺上,四大廠商2019年的業(yè)績表現(xiàn)如何

    對于通信行業(yè)而言,2019年是真正意義上的5G元年,雖然全球范圍內(nèi)的5G網(wǎng)絡建設仍未大規(guī)模啟動,但隨著韓國、美國和中國等主要市場相繼宣布5G商用,2019年已成為通信行業(yè)從4G向5G跨越的分水嶺。
    的頭像 發(fā)表于 04-10 15:19 ?2327次閱讀
    站在從4G向5G跨越的<b class='flag-5'>分水嶺</b>上,四大廠商2019年的業(yè)績表現(xiàn)如何

    超全分水嶺算法匯總

    超全分水嶺算法匯總
    發(fā)表于 10-08 10:27 ?0次下載

    opencv實戰(zhàn)——機器視覺檢測和計數(shù)

    由于之前網(wǎng)購的維生素片,有時候忘了今天有沒有吃過,就想對瓶子里的藥片計數(shù)...在學習opencv以后,希望實現(xiàn)對于維生素片分割計數(shù)算法。本次實戰(zhàn)在基于形態(tài)學的基礎上又衍生出基于距離變換的分水嶺
    的頭像 發(fā)表于 03-03 11:54 ?1898次閱讀