日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

做形态学方法的团队_图像分割实战-分水岭分割方法和GrabCut 算法

發布時間:2025/3/12 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 做形态学方法的团队_图像分割实战-分水岭分割方法和GrabCut 算法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. 分水嶺分割方法

它是依賴于形態學的,圖像的灰度等級不一樣,如果圖像的灰度等級一樣的情況下怎么人為的把它造成不一樣?可以通過距離變換實現,這樣它們的灰度值就有了階梯狀的變換。風水嶺算法常見的有三種方法:(1)基于浸泡理論的分水嶺分割方法;(2)基于連通圖方法;(3)基于距離變換的方法。OpenCV 中是基于距離變換的分割方法,就相當于我們的小山頭(認為造成的)。

基本的步驟:

例子1 粘連對象分離和計數。

例子代碼:

#include<opencv2/opencv.hpp> #include<iostream> using namespace std; using namespace cv; void test() {Mat srcImg;srcImg = imread("pill_002.png");if (srcImg.empty()){cout << "could not load image...n" << endl;}namedWindow("Original image", CV_WINDOW_AUTOSIZE);imshow("Original image", srcImg);Mat grayImg, binaryImg, shiftedImg;//做濾波,使圖像更加平滑,保留邊緣,類似于雙邊濾波pyrMeanShiftFiltering(srcImg, shiftedImg, 21, 51); namedWindow("shifted", CV_WINDOW_AUTOSIZE);imshow("shifted", shiftedImg);cvtColor(shiftedImg, grayImg, COLOR_BGR2GRAY); //轉為灰度圖像//二值化threshold(grayImg, binaryImg, 0, 255, THRESH_BINARY | THRESH_OTSU); namedWindow("binary", CV_WINDOW_AUTOSIZE);imshow("binary", binaryImg);//距離變換Mat distImg;distanceTransform(binaryImg, distImg, DistanceTypes::DIST_L2, 3, CV_32F);//歸一化,因為距離變換后得出來的值都比較小。normalize(distImg, distImg, 0, 1, NORM_MINMAX); namedWindow("distance", CV_WINDOW_AUTOSIZE);imshow("distance", distImg);//這個二值化的作用是尋找局部最大。threshold(distImg, distImg, 0.4, 1, THRESH_BINARY);namedWindow("distance_binary", CV_WINDOW_AUTOSIZE);imshow("distance_binary", distImg);//生成 markerMat distMaskImg;// distImg 得到的是 0- 1之間的數,轉化成8位單通道的。distImg.convertTo(distMaskImg, CV_8U); vector<vector<Point>>contours;//找到 marker 的輪廓findContours(distMaskImg, contours, RETR_EXTERNAL,CHAIN_APPROX_SIMPLE, Point(0, 0));//create marker 填充 markerMat markersImg = Mat::zeros(srcImg.size(), CV_32SC1);for (int i = 0; i < contours.size(); i++){drawContours(markersImg, contours, static_cast<int>(i),Scalar::all(static_cast<int>(i)+1), -1); }circle(markersImg, Point(5, 5), 3, Scalar(255), -1);//形態學操作 - 彩色圖像,目的是去掉干擾,讓結果更好。Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));morphologyEx(srcImg, srcImg, MORPH_ERODE, kernel);//完成分水嶺變換watershed(srcImg, markersImg);Mat mark = Mat::zeros(markersImg.size(), CV_8UC1);markersImg.convertTo(mark, CV_8UC1);bitwise_not(mark, mark, Mat());namedWindow("watershed", CV_WINDOW_AUTOSIZE);imshow("watershed", mark);//下面的步驟可以不做,最好做出來讓結果顯示更美觀。//生成隨機顏色vector<Vec3b>colors;for (int 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 dstImg = Mat::zeros(markersImg.size(), CV_8UC3);int index = 0;for (int i = 0; i < markersImg.rows; i++){for (int j = 0; j < markersImg.cols; j++){index = markersImg.at<int>(i, j);if (index > 0 && index <= contours.size()){dstImg.at<Vec3b>(i, j) = colors[index - 1];}else{dstImg.at<Vec3b>(i, j) = Vec3b(0, 0, 0);}}}cout << "number of objects:" << contours.size() << endl;namedWindow("Final Result", CV_WINDOW_AUTOSIZE);imshow("Final Result", dstImg); } int main() {test();waitKey(0);return 0; }

效果:

總結:有時候會導致碎片化,過度分割,因為二值化中如果有很多小的黑點或碎片,在分割的時候導致很多 mask ,即小山頭太多了,這個時候我們要考慮怎么去合并它,可以通過聯通區域的直方圖,或者像素值均值相似程度等。

例子2:圖像分割

#include<opencv2/opencv.hpp> #include<iostream> using namespace std; using namespace cv; //執行分水嶺算法函數 Mat watershedCluster(Mat &srcImg, int &numSegments); //結果顯示函數 void DisplaySegments(Mat &markersImg, int numSegments); void test() {Mat srcImg;srcImg = imread("toux.jpg");if (srcImg.empty()){cout << "could not load image...n" << endl;}namedWindow("Original image", CV_WINDOW_AUTOSIZE);imshow("Original image", srcImg);int numSegments;Mat markers = watershedCluster(srcImg, numSegments);DisplaySegments(markers, numSegments); }Mat watershedCluster(Mat &srcImg, int &numSegments) {//二值化Mat grayImg, binaryImg;cvtColor(srcImg, grayImg, COLOR_BGR2GRAY);threshold(grayImg, binaryImg, 0, 255, THRESH_BINARY | THRESH_OTSU);//形態學和距離變換Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));morphologyEx(binaryImg, binaryImg, MORPH_OPEN, kernel, Point(-1, -1));Mat distImg;distanceTransform(binaryImg, distImg, DistanceTypes::DIST_L2, 3, CV_32F);normalize(distImg, distImg, 0.0, 1.0, NORM_MINMAX);//開始生成標記threshold(distImg, distImg, 0.1, 1.0, THRESH_BINARY);normalize(distImg, distImg, 0, 255, NORM_MINMAX);distImg.convertTo(distImg, CV_8UC1); //CV_32F 轉成 CV_8UC1//標記開始vector<vector<Point>>contours;vector<Vec4i>hireachy;findContours(distImg, contours, hireachy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);if (contours.empty()){return Mat();}Mat markersImg(distImg.size(), CV_32S);markersImg = Scalar::all(0);for (int i = 0; i < contours.size(); i++){drawContours(markersImg, contours, i, Scalar(i + 1), -1, 8, hireachy, INT_MAX);}circle(markersImg, Point(5, 5) ,3, Scalar(255), -1);//分水嶺變換watershed(srcImg, markersImg);numSegments = contours.size();return markersImg; }void DisplaySegments(Mat &markersImg, int numSegments) {//生成隨機顏色vector<Vec3b>colors;for (int i = 0; i < numSegments; 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 dstImg = Mat::zeros(markersImg.size(), CV_8UC3);int index = 0;for (int i = 0; i < markersImg.rows; i++){for (int j = 0; j < markersImg.cols; j++){index = markersImg.at<int>(i, j);if (index > 0 && index <= numSegments){dstImg.at<Vec3b>(i, j) = colors[index - 1];}else{dstImg.at<Vec3b>(i, j) = Vec3b(255, 255, 255);}}}cout << "number of objects:" << numSegments << endl;namedWindow("Final Result", CV_WINDOW_AUTOSIZE);imshow("Final Result", dstImg); } int main() {test();waitKey(0);return 0; }

效果圖:

2. GrabCut 算法分割圖像

GrabCut 算法的原理前面有介紹過,這里就不在介紹了,具體可以看下文章末尾往期推薦中閱讀。下面例子實現圖像中對象的摳圖。

基本步驟:

例子代碼:

#include<opencv2/opencv.hpp> #include<iostream> using namespace std; using namespace cv; int numRun = 0; //算法迭代次數 bool init = false; Rect rect; Mat srcImg, MaskImg, bgModel, fgModel;//鼠標回調函數 void onMouse(int event, int x, int y, int flags, void* param); void showImg(); //顯示畫的圖片 void setRoiMask(); //選擇 ROI 的函數 void runGrabCut(); //執行算法函數 static void ShowHelpText(); //提示用戶操作函數void test() {srcImg = imread("toux.jpg");if (srcImg.empty()){cout << "could not load image...n" << endl;}namedWindow("Original image", CV_WINDOW_AUTOSIZE);imshow("Original image", srcImg);//初始化 mask,單通道 8 位MaskImg.create(srcImg.size(), CV_8UC1); //在不知道它是前景還是背景的情況下,把它全部設為背景。MaskImg.setTo(Scalar::all(GC_BGD)); //結果不是 0 就是 1 GC_BGD為0setMouseCallback("Original image", onMouse, 0);while (true){char c = (char)waitKey(0);if (c == 'n') // 按下 n 建開始執行算法{runGrabCut();numRun++;showImg();cout << "current iteative times:" << numRun << endl;}if (c == 27){break;}} }void onMouse(int event, int x, int y, int flags, void* param) {switch (event){case EVENT_LBUTTONDOWN:rect.x = x;rect.y = y;rect.width = 1;rect.height = 1;break;case EVENT_MOUSEMOVE:if (flags& EVENT_FLAG_LBUTTON){rect = Rect(Point(rect.x, rect.y), Point(x, y));showImg();}break;case EVENT_LBUTTONUP:if (rect.width > 1 && rect.height > 1){showImg();}break;default:break;} }void showImg() {Mat result, binMask;binMask.create(MaskImg.size(), CV_8UC1);binMask = MaskImg & 1;if (init){srcImg.copyTo(result,binMask);}else{srcImg.copyTo(result);}rectangle(result, rect, Scalar(0, 0, 255), 2, 8);namedWindow("Original image", CV_WINDOW_AUTOSIZE);imshow("Original image", result); }void setRoiMask() {//GC_BGD = 0 明確屬于背景的像素//GC_FGD = 1 明確屬于前景的像素//GC_PR_BGD = 2 可能屬于背景的像素//GC_PR_FGD = 3 可能屬于前景的像素MaskImg.setTo(GC_BGD); //為了避免選擇越界rect.x = max(0, rect.x);rect.y = max(0, rect.y);rect.width = min(rect.width, srcImg.cols - rect.x);rect.height = min(rect.height, srcImg.rows - rect.y);//把我們選取的那一塊設為前景MaskImg(rect).setTo(Scalar(GC_PR_FGD)); }void runGrabCut() {if (rect.width < 2 || rect.height < 2){return;}if (init){grabCut(srcImg, MaskImg, rect, bgModel, fgModel, 1);}else{grabCut(srcImg, MaskImg, rect, bgModel, fgModel, 1, GC_INIT_WITH_RECT);init = true;} }static void ShowHelpText() {cout << "請先用鼠標在圖片窗口中標記出屬于前景的區域" << endl;cout << "然后再按按鍵【n】啟動算法" << endl;cout << "按鍵【ESC】- 退出程序" << endl; }int main() {ShowHelpText();test();waitKey(0);return 0; }

效果圖:


歡迎關注我的微信公眾號“OpenCV圖像處理算法”,主要是記錄自己學習圖像處理算法的歷程,包括特征提取、目標跟蹤、定位、機器學習和深度學習,每一個例子都會提供源碼和例子所用的資料,歡迎同行的同學關注我和我一起虛度光陰吧!!!

總結

以上是生活随笔為你收集整理的做形态学方法的团队_图像分割实战-分水岭分割方法和GrabCut 算法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 咪咪色在线视频 | av在线浏览 | 色偷偷伊人 | 国产精品99久久久久久久久 | 日韩伦理av | 综合av网| 欧美又粗又大xxxxbbbb疯狂 | 日本女人性视频 | 杨幂毛片午夜性生毛片 | 国内视频一区二区 | 91桃色视频在线观看 | 狼人综合av | 在线视频一区二区三区 | 91精品久久久久久综合五月天 | 每日av在线 | 欧美色xxx | 国产精品高潮呻吟久久aⅴ码 | 91九色在线| 国产精品自慰网站 | 性中国xxx极品hd | 久久传媒| 双性懵懂美人被强制调教 | 少妇视频网站 | 国产无遮挡免费观看视频网站 | 久久公开视频 | 蜜桃一区二区三区 | 成人精品福利 | 日韩精品久久久久久久电影99爱 | 久久视频网 | 三上悠亚激情av一区二区三区 | 国产第一毛片 | 国产精品免费无码 | 欧美在线视频精品 | 久久影视一区 | 日日插插 | 在线免费观看亚洲 | 成人精品国产免费网站 | 涩涩99| 亚洲一区av | 天天草比| 亚洲一区精品视频在线观看 | 人妻少妇被粗大爽9797pw | 经典杯子蛋糕日剧在线观看免费 | 日韩美女久久 | 麻豆av导航 | 三级亚洲欧美 | 日日草夜夜操 | 久草精品在线 | 噜噜噜噜私人影院 | 美女吞精视频 | 久久丁香网 | 黑人黄色片 | 精品国产一区二区三区日日嗨 | 熟妇大屁股一区二区三区视频 | 久久婷婷综合国产 | 国产精品色婷婷 | 久草在在线视频 | 粉嫩精品久久99综合一区 | 国产激情视频一区二区 | 女人下面喷水视频 | 海角社区在线视频播放观看 | 人妻无码一区二区三区久久 | 国产成人精 | 久草视频在线免费看 | 蜜桃视频在线观看污 | a级特黄视频| 婷婷综合网 | 国产男女自拍 | 国产伦精品一区二区三区妓女 | 国产麻豆精品一区二区 | 亚洲一区视频在线播放 | 精品无码久久久久久久久成人 | 91色国产| 亚洲成人v | 国产日韩一区二区三免费高清 | 国产ts网站 | 激情五月婷婷丁香 | 久久aⅴ乱码一区二区三区 亚洲成人18 | 亚洲av综合色区无码另类小说 | 国产激情自拍视频 | 欧美成人一区二区视频 | 懂色av一区二区三区 | 美女被猛网站 | 1000部多毛熟女毛茸茸 | a视频 | 少妇人妻偷人精品无码视频新浪 | 国产成人精品免高潮在线观看 | 欧美日韩亚洲精品一区二区 | 亚色视频 | 中文字幕av专区 | 久久精品美乳 | 成人免费毛片xxx | 色优久久| 落日余晖 | 天堂资源av| 毛片在线视频观看 | 欧美激情3p | 黄色片免费的 | 国产精品免费一区二区三区 |