环境准备
win10+VS2015+opencv3.4
图像分割
根据图像像素点像素值,进行聚类、分割。
//图形分割
void segment(Mat img) {
namedWindow("srcImg", 0);
imshow("srcImg", img);
int wid = img.cols;
int hig = img.rows;
int dim = img.channels();
int sampleCount = wid*hig; //像素点个数,即样本点数量
int clusterCount = 3; //分类数量
//颜色索引表
Scalar colorTab[5] = {
Scalar(255,0,255),
Scalar(0,0,255),
Scalar(0,255,0),
Scalar(255,0,0),
Scalar(255,255,0),
};
Mat points(sampleCount, dim, CV_32F, Scalar(10)); //sampleCount行,dim列
int index = 0;
//图像转数据点
for (int i=0;i<hig;i++)
{
for (int j=0;j<wid;j++)
{
index = i*wid + j;
Vec3b bgr = img.at<Vec3b>(i, j);
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]);
}
}
//kmeans聚类
Mat lables;
Mat centers(clusterCount, 1, points.type()); //clusterCount行,1列
kmeans(points, clusterCount, lables, TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 0.1), 3, KMEANS_PP_CENTERS, centers);
//聚类结果点集转图像
Mat segImg = Mat::zeros(img.size(), img.type());
for (int i=0;i<hig;i++)
{
for (int j=0;j<wid;j++)
{
index= i*wid + j;
int lable = lables.at<int>(index, 0);
Vec3b vec(colorTab[lable][0], colorTab[lable][1], colorTab[lable][2]);
segImg.at<Vec3b>(i, j) = vec;
}
}
//输出类中心,注意,非坐标值,而是像素值
for (int i=0;i<clusterCount;i++)
{
printf("Count%i:%f,%f,%f\n", i, centers.ptr<float>(i)[0], centers.ptr<float>(i)[1], centers.ptr<float>(i)[2]);
}
namedWindow("segmentation", 0);
imshow("segmentation", segImg);
//waitKey(0);
//背景替换
//Point p(100, 100); //根据情况,背景中的一点
//int lable = lables.at<int>(p.y*wid+p.x, 0);
//for (int i = 0; i < hig; i++)
//{
// for (int j = 0; j < wid; j++)
// {
// if (lable == lables.at<int>(i*wid + j, 0))
// {
// Vec3b vec(0, 0, 255);//替换为红色
// img.at<Vec3b>(i, j) = vec;
// }
// }
//
//}
//namedWindow("replace", 0);
//imshow("replace", img);
waitKey(0);
}
结果
速度有点儿慢,用做实时替换肯定不行。
结果比较粗糙,可以对图像提前进行预处理等,做到精准背景替换。