一、分水嶺算法
1、概述
??分水嶺算法是一種圖像分割常用的算法,可以有效地將圖像中的目標(biāo)從背景中分離出來。本文以O(shè)penCV庫中的分水嶺算法為基礎(chǔ),介紹圖像分割中的常用概念和算法原理,并結(jié)合實(shí)際案例展示分水嶺算法的應(yīng)用。
2、圖像分割概念
??圖像分割指的是將圖像分成多個(gè)不同的區(qū)域或?qū)ο蟮倪^程。圖像分割是計(jì)算機(jī)視覺和圖像處理領(lǐng)域中的重要問題,包括物體檢測(cè)、形狀分析、三維重建、醫(yī)學(xué)圖像處理等眾多應(yīng)用。對(duì)于圖像分割,有四種典型的方法:
-
閾值分割:基于給定的閾值將圖像分成兩個(gè)區(qū)域。
-
區(qū)域生長:從種子像素開始生長,合并與種子相鄰的像素來形成區(qū)域。
-
邊緣檢測(cè):通過檢測(cè)圖像中的邊緣,將圖像分割成不同的對(duì)象。
-
基于聚類的方法:利用聚類算法將圖像分成多個(gè)區(qū)域。
3、分水嶺算法原理
??分水嶺算法是一種基于圖論的圖像分割算法,它將圖像看成一個(gè)拓?fù)鋱D,把亮度值看成高度,水從高處向低處流動(dòng),在高處建立分界線,將圖像分割成多個(gè)區(qū)域。分水嶺算法包含以下四個(gè)步驟:
-
載入圖像并轉(zhuǎn)化為灰度圖像。
-
對(duì)灰度圖像進(jìn)行形態(tài)學(xué)變換,以抑制圖像中的噪聲和平滑圖像。
-
計(jì)算距離變換,找到不同區(qū)域之間的分界線,將其看成浸沒的水平面。
-
利用分界線將圖像分成多個(gè)區(qū)域。
二、主要函數(shù)
??cv::watershed
函數(shù)實(shí)現(xiàn)了基于距離變換的分水嶺算法。該函數(shù)的原型如下:
void watershed(InputArray image,
InputOutputArray markers
);
-
image
:輸入的圖像,必須為8位的3通道彩色圖像。 -
markers
:輸出的標(biāo)記圖像,必須為單通道32位整型圖像。
在使用cv::watershed
函數(shù)進(jìn)行分水嶺算法分割時(shí),需要先進(jìn)行前期處理,包括圖像的預(yù)處理和創(chuàng)建標(biāo)記圖像。
三、C++代碼
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
Mat img, imgGray, imgMask;
Mat maskWaterShed; // watershed()函數(shù)的參數(shù)
img = imread("HoughLines.jpg"); //原圖像
if (img.empty())
{
cout << "請(qǐng)確認(rèn)圖像文件名稱是否正確" << endl;
return -1;
}
cvtColor(img, imgGray, COLOR_BGR2GRAY);
//提取邊緣并進(jìn)行閉運(yùn)算
Canny(imgGray, imgMask, 150, 300);
Mat k = getStructuringElement(0, Size(3, 3));
morphologyEx(imgMask, imgMask, MORPH_CLOSE, k);
imshow("邊緣圖像", imgMask);
imshow("原圖像", img);
//計(jì)算連通域數(shù)目
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(imgMask, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
//在maskWaterShed上繪制輪廓,用于輸入分水嶺算法
maskWaterShed = Mat::zeros(imgMask.size(), CV_32S);
for (int index = 0; index < contours.size(); index++)
{
drawContours(maskWaterShed, contours, index, Scalar::all(index + 1),
-1, 8, hierarchy, INT_MAX);
}
//分水嶺算法 需要對(duì)原圖像進(jìn)行處理
watershed(img, maskWaterShed);
vector<Vec3b> colors; // 隨機(jī)生成幾種顏色
for (int i = 0; i < contours.size(); i++)
{
int b = theRNG().uniform(0, 255);
int g = theRNG().uniform(0, 255);
int r = theRNG().uniform(0, 255);
colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
}
Mat resultImg = Mat(img.size(), CV_8UC3); //顯示圖像
for (int i = 0; i < imgMask.rows; i++)
{
for (int j = 0; j < imgMask.cols; j++)
{
// 繪制每個(gè)區(qū)域的顏色
int index = maskWaterShed.at<int>(i, j);
if (index == -1) // 區(qū)域間的值被置為-1(邊界)
{
resultImg.at<Vec3b>(i, j) = Vec3b(255, 255, 255);
}
else if (index <= 0 || index > contours.size()) // 沒有標(biāo)記清楚的區(qū)域被置為0
{
resultImg.at<Vec3b>(i, j) = Vec3b(0, 0, 0);
}
else // 其他每個(gè)區(qū)域的值保持不變:1,2,…,contours.size()
{
resultImg.at<Vec3b>(i, j) = colors[index - 1]; // 把些區(qū)域繪制成不同顏色
}
}
}
resultImg = resultImg * 0.6 + img * 0.4;
imshow("分水嶺結(jié)果", resultImg);
waitKey(0);
return 0;
}
四、結(jié)果展示
1、原始圖像
2、分割結(jié)果
文章來源:http://www.zghlxwxcb.cn/news/detail-526897.html
五、參考鏈接
[1] 【OpenCv】圖像分割——分水嶺算法文章來源地址http://www.zghlxwxcb.cn/news/detail-526897.html
到了這里,關(guān)于OpenCV——分水嶺算法的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!