本案例基于k-means机器学习算法进行遥感图像分割。主要是用到了OpenCV 中的kmeans API。关于kmeans聚类算法原理大家自行查找资料学习,也比较容易理解,我这里就示范一下如何调用OpenCV中的API进行图像分割。
原图如图所示,我们想要的效果是将该图像中白色部分作为前景像素,黑色部分作为背景像素进行分割出来,属于一个二分类问题。对于这个简单的二分类也可以直接使用阈值分割将图像前景与背景分割出来。我这里是使用kmeans聚类算法将图像进行一个二分类。
首先,需要将图像中的像素灰度存储为一个mat格式,width*height行,channel列。
//图像宽、高、通道
int width = src.cols;
int height = src.rows;
int channel = src.channels();
Mat data(width*height, channel, CV_32FC1);//mat类型数据,用于存储图像灰度信息-width*height行,channel列
int index = 0;//图像像素索引
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
index = i * width + j;//图像像素索引
for (int c = 0; c < channel; c++)
{
data.at<float>(index, c) = saturate_cast<int>(src.at<Vec3b>(i, j)[c]);//将当前像素灰度值存储进mat数据里面
}
}
}
准备好数据之后,就可以调用OpenCV中的kmeans API了。
double kmeans( InputArray data, //聚类数据,浮点型数据,每行为一个样本
int K, //类别数
InputOutputArray bestLabels, //每一个样本分类结果,整型数据
TermCriteria criteria, //算法停止迭代的标准
int attempts,//判断某个样本为某个类的最少聚类次数,比如值为3时,则某个样本聚类3次都为同一个类,则确定下来。
int flags, //确定簇心的计算方式。有三个值可选:KMEANS_RANDOM_CENTERS 表示随机初始化簇心。KMEANS_PP_CENTERS 表示用kmeans++算法来初始化簇心,KMEANS_USE_INITIAL_LABELS 表示第一次聚类时用用户给定的值初始化聚类,后面几次的聚类,则自动确定簇心。
OutputArray centers = noArray() //用来初始化簇心的。与前一个flags参数的选择有关。如果选择KMEANS_RANDOM_CENTERS随机初始化簇心,则这个参数可省略。
);
Mat labels;//数据分类标签
int k = 2;//2类,前景、背景
kmeans(data, k, labels, TermCriteria(TermCriteria::COUNT | TermCriteria::EPS, 100, 0.01), 3, KMEANS_RANDOM_CENTERS);
#include
#include
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("test.bmp");
if (src.empty())
{
cout << "can not read the image..." << endl;
system("pause");
return -1;
}
//图像宽、高、通道
int width = src.cols;
int height = src.rows;
int channel = src.channels();
Mat data(width*height, channel, CV_32FC1);//mat类型数据,用于存储图像灰度信息-width*height行,channel列
int index = 0;//图像像素索引
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
index = i * width + j;//图像像素索引
for (int c = 0; c < channel; c++)
{
data.at<float>(index, c) = saturate_cast<int>(src.at<Vec3b>(i, j)[c]);//将当前像素灰度值存储进mat数据里面
}
}
}
Mat labels;//数据分类标签
int k = 2;//2类,前景、背景
kmeans(data, k, labels, TermCriteria(TermCriteria::COUNT | TermCriteria::EPS, 100, 0.01), 3, KMEANS_RANDOM_CENTERS);
Scalar color[] =
{
Scalar(255,0,0),
Scalar(255,255,0)
};
//进行图像像素分类,并将同一类像素绘制相同的颜色
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
index = i * width + j;
for (int c = 0; c < channel; c++)
{
src.at<Vec3b>(i, j)[c] = color[labels.at<int>(index)][c];
}
}
}
imwrite("result.bmp", src);
namedWindow("test", WINDOW_NORMAL);
imshow("test", src);
waitKey(0);
destroyAllWindows();
system("pause");
return 0;
}
本文使用OpenCV C++ 进行遥感图像分割,主要操作有以下几点。
1、将图像像素灰度存储为mat数据格式,用于kmeans分类。
2、进行像素分类以及结果显示