OpenCV利用K-means實現(xiàn)根據(jù)顏色進行圖像分割
K-means算法分割
K-means是一種經(jīng)典的無監(jiān)督聚類算法---不需要人工干預。
算法原理:
(1)隨機選擇兩個中心點;

(2)計算每個點到這兩個中心點的距離,最近的分成一類(連接起來);

(3)重新計算中心點(平均值計算),計算新的中心點到舊的中心點的差值如果小于輸入的值,就說明中心的位置發(fā)生了變化,,那么到(2)步重新計算中心點到每個點的距離,開始下一次循環(huán);

(4)執(zhí)行多個迭代之后,滿足收斂時,得到最終的分類

應用:分類
根據(jù)顏色分類
#include<opencv2/opencv.hpp>
#include<iostream>
int main(int argc, char** argv) {
cv::Mat img(500, 500, CV_8UC3);
cv::RNG rng(12345);
cv::Scalar colorTab[] = {
cv::Scalar(0, 0, 255),
cv::Scalar(0, 255, 0),
cv::Scalar(255, 0, 0),
cv::Scalar(0, 255, 255),
cv::Scalar(255, 0, 255)
};
int numCluster = rng.uniform(2, 5);
printf("種類數(shù)量 : %d\n", numCluster);
//4
int sampleCount = rng.uniform(2, 1000);//隨機樣本
printf("樣本數(shù)量 : %d\n", sampleCount);
//591
cv::Mat points(sampleCount, 1, CV_32FC2);
cv::Mat labels;
cv::Mat centers;
for (int k = 0; k < numCluster; k++) {
cv::Point center;
center.x = rng.uniform(0, img.cols);//隨機坐標
center.y = rng.uniform(0, img.rows);
cv::Mat pointChunk = points.rowRange(k * sampleCount / numCluster, k == numCluster - 1 ? sampleCount : (k + 1) * sampleCount / numCluster);
//每一類占1/numCluster 行
//rng.fill(pointChunk, cv::RNG::NORMAL, cv::Scalar(center.x, center.y), cv::Scalar(img.cols * 0.05, img.rows * 0.05));//用隨機數(shù)填充矩陣
rng.fill(pointChunk, cv::RNG::UNIFORM, 0, 255);//用隨機數(shù)填充矩陣
}
randShuffle(points, 1, &rng);//算法打亂元素排列順序
kmeans(points, numCluster, labels, cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 10, 0.1), 3, cv::KMEANS_PP_CENTERS, centers);
/*【根據(jù)參數(shù)1的坐標進行分類】
參數(shù)1:為cv::Mat類型,每行代表一個樣本,即特征,即mat.cols=特征長度,mat.rows=樣本數(shù),數(shù)據(jù)類型僅支持float
參數(shù)2:K 指定聚類時劃分為幾類
參數(shù)3:為cv::Mat類型,是一個長度為(樣本數(shù),1)的矩陣,即mat.cols=1,mat.rows=樣本數(shù);為K-Means算法的結果輸出,指定每一個樣本聚類到哪一個label中【指定每一個樣本聚類到哪一類中】
參數(shù)4:TermCriteria類,算法進行迭代時終止的條件,可以指定最大迭代次數(shù),也可以指定預期的精度,也可以這兩種同時指定;
參數(shù)1:int type
type=TermCriteria::MAX_ITER/TermCriteria::COUNT 迭代到最大或迭代次數(shù)終止
type= TermCriteria::EPS 迭代到閾值終止
type= TermCriteria::MAX_ITER+ TermCriteria::EPS 上述兩者都作為迭代終止條件
參數(shù)2:int maxCount 迭代的最大次數(shù)
參數(shù)3:double epsilon 閾值(中心位移值)
參數(shù)5:指定K-Means算法執(zhí)行的次數(shù),每次算法執(zhí)行的結果是不一樣的,選擇最好的那次結果輸出
參數(shù)6:初始化均值點的方法,目前支持三種:KMEANS_RANDOM_CENTERS、KMEANS_PP_CENTERS、KMEANS_USE_INITIAL_LABELS
參數(shù)7:為cv::Mat類型,輸出最終的均值點,mat.cols=特征長度,mat.rols=K 【每個類的中心點】
*/
// 用不同顏色顯示分類
//初始化圖片顏色。
img = cv::Scalar::all(255);
for (int i = 0; i < sampleCount; i++) {
int index = labels.at<int>(i);
//獲取ponint點
cv::Point p = points.at<cv::Point2f>(i);
//填充
circle(img, p, 2, colorTab[index], -1, 8);
}
// 每個聚類的中心來繪制圓
for (int i = 0; i < centers.rows; i++) {
int x = centers.at<float>(i, 0);
int y = centers.at<float>(i, 1);
printf("c.x= %d, c.y=%d", x, y);
circle(img, cv::Point(x, y), 40, colorTab[i], 1, cv::LINE_AA);
}
imshow("KMeans-Data-Demo", img);
cv::waitKey(0);
return 0;
}實例
2.png

#include<opencv2/opencv.hpp>
#include<iostream>
int main(int argc, char** argv) {
cv::Scalar colorTab[] = {
cv::Scalar(0, 0, 255),
cv::Scalar(0, 255, 0),
cv::Scalar(255, 0, 0),
cv::Scalar(0, 255, 255),
};
cv::Mat src = cv::imread("D:/bb/tu1/2.png");
if (!src.data)
{
printf("圖像讀取失敗...\n");
return -1;
}
cv::imshow("src", src);
int width = src.cols;
int height = src.rows;
int dims = src.channels();
int sampleCount = width * height; //總像素
int clusterCount = 4; //分類數(shù)量
cv::Mat points(sampleCount, dims,CV_32F,cv::Scalar(10));
//一個像素為一行
cv::Mat labels;
cv::Mat centers(clusterCount,1, points.type());
//保存中心坐標
//把RGB數(shù)據(jù)轉換成樣本數(shù)據(jù)
int index = 0;//像素序號
for (int row = 0; row < height;row++) {
for (int col = 0; col < width;col++) {
index = row * width + col;
cv::Vec3b bgr = src.at<cv::Vec3b>(row, col);
points.at<float>(index, 0) = static_cast<int>(bgr[0]);
points.at<float>(index, 1) = static_cast<int>(bgr[1]);
points.at<float>(index, 2) = static_cast<int>(bgr[2]);
}
}
cv::TermCriteria criteria = cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS,10,0.1);
//kmeans的終止的條件
kmeans(points, clusterCount, labels, criteria, 3, cv::KMEANS_PP_CENTERS, centers);//運行kmeans
//顯示圖像分割結果
cv::Mat result = cv::Mat::zeros(src.size(),src.type());
for (int row = 0; row < height;row++) {
for (int col = 0; col < width;col++) {
index = row * width + col;
int label = labels.at<int>(index, 0); //獲取類序號
result.at<cv::Vec3b>(row, col)[0] = colorTab[label][0];
result.at<cv::Vec3b>(row, col)[1] = colorTab[label][1];
result.at<cv::Vec3b>(row, col)[2] = colorTab[label][2];
}
}
cv::imshow("result", result);
cv::waitKey(0);
return 0;
}
以上就是OpenCV利用K-means實現(xiàn)根據(jù)顏色進行圖像分割的詳細內(nèi)容,更多關于OpenCV K-means圖像分割的資料請關注腳本之家其它相關文章!
相關文章
Qt串口通信開發(fā)之Qt串口通信模塊QSerialPort開發(fā)完整實例(串口助手開發(fā))
這篇文章主要介紹了Qt串口通信開發(fā)之Qt串口通信模塊QSerialPort開發(fā)完整實例(串口助手開發(fā)),需要的朋友可以參考下2020-03-03

