九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
分水嶺算法(理論 opencv實現(xiàn))

????

作者:寂寞的小乞丐

個人博客:hhttp://www.cnblogs.com/wjy-lulu/

往期回顧:

高斯混合模型(理論+opencv實現(xiàn))

從意思上就知道通過用水來進行分類,學術上說什么基于拓撲結構的形態(tài)學。。。其實就是根據(jù)把圖像比作一副地貌,然后通過最低點和最高點去分類!

原始的分水嶺:

就是上面說的方式,接下來用一幅圖進行解釋---->>>

把圖像用一維坐標表示,二維和三維不好畫,必須用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();="">

    {

        //這里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;="">

    {

        Mat sample;

        samples.push_back(sample);

    }

    for (size_t i = 0; i < segments.rows;="">

    {

        for (size_t j = 0; j < segments.cols;="">

        {

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

            if (index >= 0 && index <=>

            {

                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 <=>

            //    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;="">

    {

        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();="">

    {

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

        {

            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;="">

                            {

                                for (size_t k = 0; k < segments.cols;="">

                                {

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

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

                                }

                            }

                        }

                    }

                }

            }

        }

    }

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

}



參考:

    http://blog.csdn.net/iracer/article/details/49225823

    http://www.cnblogs.com/mikewolf2002/p/3304118.html

    http://lib.csdn.net/article/opencv/22776

    《opencv圖像處理編程實例》

    代碼參考賈老師視頻,原理早就看了毛星云的書本,但是當時一知半解,現(xiàn)在從頭看一下子就懂了。




本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Opencv之<vec3b>是什么東東 </vec3b>
OpenCV(C++版)輪廓(contour)檢測
OpenCV-繪制簡易直方圖DrawHistImg
【從零學習OpenCV 4】直方圖均衡化
opencv實戰(zhàn)機器視覺檢測和計數(shù)(讀入圖像形態(tài)學二值化消除噪聲)
opencv 中函數(shù)的一相關說明,如:cvtColor和cvCvtColor區(qū)別
更多類似文章 >>
生活服務
熱點新聞
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服