基于K-MEANS聚类的胡萝卜纯色背景去除方法

所谓的聚类是指,将一个数据集中的某些方面相似的数据成员进行分类的过程,聚类就是一种发现这种内在结构的技术,聚类技术经常被称为无监督学习。k均值聚类是最著名的划分聚类算法,由于简洁和效率使得他成为所有聚类算法中最广泛使用的。给定一个数据点集合和需要的聚类数目k,k由用户指定,k均值算法根据某个距离函数反复把数据分入k个聚类中。
  1. k均值算法描述
先随机选取K个对象作为初始的聚类中心。然后计算每个对象与各个种子聚类中心之间的距离,把每个对象分配给距离它最近的聚类中心。聚类中心以及分配给它们的对象就代表一个聚类。一旦全部对象都被分配了,每个聚类的聚类中心会根据聚类中现有的对象被重新计算。这个过程将不断重复直到满足某个终止条件。终止条件可以是以下任何一个:
1)没有(或最小数目)对象被重新分配给不同的聚类。
2)没有(或最小数目)聚类中心再发生变化。
3)误差平方和局部最小。
 
而基于K均值的胡萝卜图像的分类,则是利用分类的思想,将目标区与背景区分成两类,所以,在此处将 K 的值,设置为 2;因为,是根据灰度值进行划分,则误差设置为1作为终止条件;
算法具体实现代码如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
IplImage* img = cvCloneImage(m_sourceImage);
         IplImage* grayImage = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
         //IplImage* redImage = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
 
         //cvSplit(img, NULL, NULL, redImage, NULL);
 
         cvCvtColor(img, grayImage, CV_RGB2GRAY);
         //IplImage* img = cvCreateImage(cvGetSize(m_sourceImage), IPL_DEPTH_8U, 1);
         //cvCvtColor(m_sourceImage, img, CV_RGB2GRAY);
         int  total = img->height*img->width;
         int  cluster_num = 2;
         CvMat *row = cvCreateMat(img->height, img->width, CV_32FC3);
         //cvConvert(redImage, row);
         cvConvert(img, row); //转一下类型!
         CvMat *clusters = cvCreateMat(total, 1, CV_32SC1);
 
//      CvArr* cvReshapeMatND(const CvArr* arr,
//          int sizeof_header, CvArr* header,
//          int new_cn, int new_dims, int* new_sizes);
//
//      arr :输入数组
//      sizeof_header :输出头的大小,对于IplImage, CvMat 和 CvMatND 各种结构输出的头均是不同的.
//      header:被添充的输出头.
//      new_cn:新的通道数,如果new_cn = 0 则通道数保持原样
//      new_dims:新的维数.如果new_dims = 0 则维数保持原样。
//          new_sizes
//          新的维大小.只有当 new_dims = 1值被使用,因为要保持数组的总数一致,因此如果 new_dims = 1, new_sizes 是不被使用的
 
 
         cvReshape(row, row, 0, total);                       //把图像转成数据矩阵,但注意实际数据未变,只是访问顺序变了。
         cvKMeans2(row, cluster_num, clusters, cvTermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 1.0));
         cvReshape(clusters, clusters, 0, img->width);         //聚类完的结果再reshape回来比较方便看~
         int  i = 0, j = 0;
         CvScalar s;
         IplImage* resImg = cvCreateImage(cvSize(img->width, img->height), 8, 1); //生成用来显示结果的图像
         s = cvGet2D(img, i, j);
 
         vector < int > v1, v2;       //存放分类后的灰度值
 
 
         for  (i = 0; i < img->height; i++)
         {
             for  (j = 0; j < img->width; j++)
             {
                 double  val = cvGetReal2D(grayImage, i, j);
 
                 if  (clusters->data.i[i*img->width + j] == 0)
                 {
                     v1.push_back(val);               //处理完成后的图像的白色区域
                     s.val[0] = 255;
                     cvSet2D(resImg, i, j, s); //注意循环顺序
                 }
                 else
                 {
                     v2.push_back(val);               //处理完成后的图像的黑色区域
                     s.val[0] = 0;
                     cvSet2D(resImg, i, j, s);
                 }
             }
         }
 
         double  thresh1 = accumulate(v1.begin(), v1.end(), 0) / v1.size();
         double  thresh2 = accumulate(v2.begin(), v2.end(), 0) / v2.size();
 
         if  (thresh2 > thresh1)        //如果黑色区域的灰度值均值大于白色区域
         {
             cvNot(resImg, resImg);   //图像取反
         }
 
         IplConvKernel *element = cvCreateStructuringElementEx(5, 5, 2, 2, CV_SHAPE_ELLIPSE);
         cvSmooth(resImg, resImg, CV_MEDIAN);
         cvErode(resImg, resImg, element, 1);
         cvDilate(resImg, resImg, element, 1);
         cvReleaseStructuringElement(&element);
 
         cvSaveImage( "s2.jpg" , m_sourceImage);
         cvSaveImage( "b2.jpg" , resImg);
 
         ShowImage(resImg, IDC_PIC2);
 
         int  key = cvWaitKey(0);
         cvReleaseImage(&img); //记得释放内存
         cvReleaseImage(&resImg);
         cvReleaseMat(&row);
         cvReleaseMat(&clusters);

  上述代码,对图像的处理结果进行了校正,因为,K-Mean聚类,只是简单的将目标区与背景区进行分类,而不能明确的标记出目标区还是背景区,所以,根据经验,将灰度值均值较大的部分作为目标区;

而灰度值较小的部分标记为背景区;

以下为未校正图像与校正后图像的对比:

如上图所示:左侧图像为未做校正的处理效果,右侧图像为校正后的图像;

由于此方法只是简单的根据图像的灰度值对图像进行二值化,所以,很难对复杂背景的图像进行分割;相关的算法,在以后的学习中再进行完善与补充。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值