使用“K-中心点聚类算法”对图像的像素点进行K类划分
实验要求:用VC或Java实现K-中心点聚类算法,分别以迭代次数及分配不再发生变化为算法终止条件,用图片(自己选择)作为数据集,比较运行时间(画出时间与像素点的关系曲线图),提交实验报告与源代码。
思路:图像处理(rgb2gray)->图像数据采集(生成灰度矩阵)->数据结构定义和程序设计->应用算法实现主程序->测试以及优化各个环节->记录实验结果->分析实验结果制作实验报告。
图像原型以及图像处理代码(使用了matlab进行处理):在文件中可以下载浏览。
1 f=imread('D:\tree.jpg'); % 读取图像;
2 f=rgb2gray(f); %转换为灰度图
3 [x,y]=size(f); % x,y为图像的行数和列数;
4 m=1800;n=2500; % 手动定义子图像的行数和列数;
5 s=zeros(m,n); % s表示子矩阵;
6 rx=1:m:x;
7 cy=1:n:y; % rx和cy是子图像左上角的坐标;
8 rowhigh=rx+m-1; % rowhigh和colhigh是子图像历遍的终点,即为右下角的坐标;
9 colhigh=cy+n-1;
10 xcount=0; % 设置x方向的计数器;
11 for r=rx:rowhigh; % rx,cy为子图像左上角的坐标;
12 xcount=xcount+1;
13 ycount=0;
14 for c=cy:colhigh;
15 ycount=ycount+1;
16 s(xcount,ycount)=f(r,c);
17 end
18 end
19 save(‘D:\tree.dat’,'s','-ASCII'); %保存为dat文件,后续程序使用该文件
因为目前像素点目前只有一个维度的特征——灰度,并且该维度是用一个字节大小的整型值来描述的,所以可以先统计在各个灰度值上像素点的个数,然后
再做算法分析,找出k个灰度中心点,划分为k个灰度范围。
预处理统计程序如下:
//读入文件
int t[256];
for(int i=0;i<256;i++)t[i]=0;
double c=0;
fstream out;
out.open("tree.dat",ios::in);
if(!out)
{cout<<"open fail\n";
return;
}
while(!out.eof()){
out>>c; //从数据流读文件
int a=(int)c; //文件中的数值类型为double,这里进行一个转换作为数组下标
t[a]++; //统计在各个灰度值上的像素点的个数
}
out.close();
fstream in;
in.open("gray.dat",ios::out);
if(!in)
{cout<<"open fail\n";
return;
}
for(int i=0;i<256;i++ ){in<<t[i];in<<" ";}
in.close();
然后可以得到一个统计结果的文件,保存出来gray.dat(以后要用统计结果的话就方便些)。
数据结构定义和算法设计:
double tc=5000000000; //当前代价
int t[256]; //灰度分布像素个数记录
int tt[256]; //各个灰度被分配的类号
int kk[256]; //中心点
代码:
#include<iostream>
#include<fstream>
#include<time.h>
#include<cstdlib>
using namespace std;
void swap(int i,int j);
int account(int k);//统计总代价比较并返回代价类内最小的点
void kstars(int k); //分类
void show(); //显示结果
double tc=5000000000; //当前代价
int t[256]; //灰度分布像素个数记录
int tt[256]; //各个灰度被分配的类号
int kk[256]; //中心点
void main()
{
for(int i=0;i<256;i++)tt[i]=0;
for(int i=0;i<256;i++)t[i]=0;
double c=0;
fstream out;
out.open("tree.dat",ios::in);
if(!out)
{cout<<"open fail\n";
return;
}
time_t begin = clock() ; // 记录开始时候的时间
int pix=1000000;
int n=0;
while(pix>n&&!out.eof()){
out>>c; //从数据流读文件
int a=(int)c; //文件中的数值类型为double,这里进行一个转换作为数组下标
t[a]++; //统计在各个灰度值上的像素点的个数
n++;
}
out.close();
fstream in;
in.open("gray.dat",ios::out);
if(!in)
{cout<<"open fail\n";
return;
}
for(int i=0;i<256;i++ ){in<<t[i];in<<" ";}
in.close();
//分析数据集
// do something here
int k=3;
kstars(k);
//for(int i=0;i<256;i++ ){cout<<tt[i]<<" ";}
cout<<endl;
time_t end = clock() ; // 记录结束时间
time_t cost = end - begin ; // 耗费时间 毫秒级
cout<<cost;
int xx;
cin>>xx;
}
int account(int k)//把所有点分类并求得总代价
{
int sum=0;
for(int i=0;i<256;i++)
{
int min=300;
int temp=0;
for(int j=0;j<k;j++)//找出最优中心点
{
temp=abs(kk[j]-i);
if(temp<min)
{
min=temp;
tt[i]=j;//将第i点分为j类
}
}
sum+=min*t[i];//加到总代价
}
return sum;
}
void kstars(int k)
{
for(int i=0;i<k;i++){
srand(time(0)); //seed
kk[i]=rand() % 256;
}
int temp=0;
for(int i=0;i<256;i++){
for(int j=0;j<k;j++)
{
int kv=kk[j];
kk[j]=i;//把i记为第j个中心点
temp=account(k);
if(tc>temp)
{
tc=temp;
}
else{
kk[j]=kv;
}
}
}
}
浙公网安备 33010602011771号