kmeans,FCM聚类iris和sonar数据集,以及图像分割
kmeans
问题概述
kmeans
kmeans非常好理解了,本质上其实只有三步(做可视化时候可能需要归一化我们先不说)
拿iris举例,天气太冷了,120
(
样
本
个
数
)
_ {(样本个数)}
(样本个数)个小伙伴在操场上站着直哆嗦,这时,学校搬来3
(
类
别
个
数
)
_(类别个数)
(类别个数)个大火炉,我们的目的就是在同学都不动的情况下把火炉放到合适的位置,从而使得所有同学都能尽可能感受到火炉的温暖
首先,学校把火炉随机放在某个地方(当然这个地点坐标可能是二维的也可能是高维,和元素维度保持一致),即中心点初始化。
第二步,开始循环,让每个同学面向离它们最近的火炉(归类)
第三步,面向同一个火炉的同学们求出大家坐标的中心,把火炉搬到中间(更新样本中心点)
然后跳到第二步循环直到中心点啊,轮廓系数什么的收敛,或者循环次数达到某个阈值结束训练
运行效果
初始化(白色为火炉)(样本点初始化为深蓝色,颜色偏暗,可能不太容易看清楚)
迭代一次
代码部分
结构总览
整形m用于限制算法迭代次数
bool is_iris用于切换iris和sonar数据集
int main()
{
int m=500;
bool is_iris=0;
kmeans k;
k.load_iris();
k.load_sonar();
k.init_kmeans(is_iris);
while(m--)
{
k.sort(is_iris);
k.reload_z(is_iris);
cout<<k.load_sc(is_iris)<<endl;
if(is_iris)
k.fenxi(2,1);
if(is_iris)
cv::waitKey(0);
}
return 0;
}
函数1载入数据load_iris(),load_sonar()
将iris和sonar数据的信息分别载入到二维数组data_iris和data_sonar中
其中每一数据的最后一维用于保存聚类后的分类信息,倒数第二维用于保存数据集原来的分类信息(用于可视化处理时作为对照)
void kmeans::load_iris()
{
int i,m=27;
char ch,ch_1[35];
int high,low;
int d[2];
FILE *f;
if ((f = fopen("/home/jojo/jason_cpp/iris.data", "rb+")) == NULL)
{
perror("fail to read");
}
if(f != NULL)
{
ch = 'a';
while(ch != EOF)
{
putchar(ch);
ch = fgetc(f);
if(ch!='\n')ch_1[tag_a++]=ch;
else
{
data_iris[tag_b++][0]=(ch_1[0]-'0')+(ch_1[2]-'0')*0.1;
data_iris[tag_b-1][1]=(ch_1[4]-'0')+(ch_1[6]-'0')*0.1;
data_iris[tag_b-1][2]=(ch_1[8]-'0')+(ch_1[10]-'0')*0.1;
data_iris[tag_b-1][3]=(ch_1[12]-'0')+(ch_1[14]-'0')*0.1;
//类别看taga(每行长度)大小
if(tag_a==27)data_iris[tag_b-1][4]=0;
else if(tag_a==31)data_iris[tag_b-1][4]=1;
else data_iris[tag_b-1][4]=2;
tag_a=0;
}
}
}
else
printf("fail to open! \n");
fclose(f);
for(tag_b=0;tag_b<4;tag_b++)
{
yu_iris[tag_b][0]=500;
yu_iris[tag_b][1]=-500;
}
for(tag_a=0;tag_a<150;tag_a++)
for(tag_b=0;tag_b<4;tag_b++)
{
if(yu_iris[tag_b][0]>data_iris[tag_a][tag_b])yu_iris[tag_b][0]=data_iris[tag_a][tag_b];
if(yu_iris[tag_b][1]<data_iris[tag_a][tag_b])yu_iris[tag_b][1]=data_iris[tag_a][tag_b];
}
}
void kmeans::load_sonar()
{
int i,m=27;
char ch,ch_1[500];
int high,low;
int d[2];
FILE *f;
if ((f = fopen("/home/jojo/jason_cpp/sonar.txt", "rb+")) == NULL)
{
perror("fail to read");
}
char data_b[7];
if(f != NULL)
{
for(tag_c=0;tag_c<208;tag_c++)
{
for(tag_b=0;tag_b<60;tag_b++)
{
data_sonar[tag_c][tag_b]=0;
for(tag_a=0;tag_a<7;tag_a++)
{
if(ch!=EOF)
{
putchar(ch);
ch = fgetc(f);
if(ch=='\n')ch = fgetc(f);
data_b[tag_a]=ch;
}
}
data_sonar[tag_c][tag_b]+=(data_b[0]-'0')*1;
data_sonar[tag_c][tag_b]+=(data_b[2]-'0')*0.1;
data_sonar[tag_c][tag_b]+=(data_b[3]-'0')*0.01;
data_sonar[tag_c][tag_b]+=(data_b[4]-'0')*0.001;
data_sonar[tag_c][tag_b]+=(data_b[5]-'0')*0.0001;
}
putchar(ch);
ch = fgetc(f);
if(ch=='R')data_sonar[tag_c][60]=0;
else data_sonar[tag_c][60]=1;
putchar(ch);
ch = fgetc(f);
}
}
else
printf("fail to open! \n");
fclose(f);
for(tag_b=0;tag_b<60;tag_b++)
{
yu_sonar[tag_b][0]=500;
yu_sonar[tag_b][1]=-500;
}
for(tag_a=0;tag_a<118;tag_a++)
for(tag_b=0;tag_b<60;tag_b++)
{
if(yu_sonar[tag_b][0]>data_sonar[tag_a][tag_b])yu_sonar[tag_b][0]=data_sonar[tag_a][tag_b];
if(yu_sonar[tag_b][1]<data_sonar[tag_a][tag_b])yu_sonar[tag_b][1]=data_sonar[tag_a][tag_b];
}
}
函数2初始化样本中心点init_kmeans(bool is_iris)
iris数据在载入数据过程中计算了样本范围,这里将样本中心点初始化为在样本范围内的随机数,sonar直接取值0.001和0.5
void kmeans::init_kmeans(bool is_iris)
{
if(is_iris)
{
point_iris[0][0]=(yu_iris[0][1]-yu_iris[0][0])*((rand()%100)/200+0.5)+yu_iris[0][0];
point_iris[0][1]=(yu_iris[1][1]-yu_iris[1][0])*((rand()%100)/200+0.5)+yu_iris[1][0];
point_iris[0][2]=(yu_iris[2][1]-yu_iris[2][0])*((rand()%100)/200+0.5)+yu_iris[2][0];
point_iris[0][3]=(yu_iris[3][1]-yu_iris[3][0])*((rand()%100)/200+0.5)+yu_iris[3][0];
point_iris[1][0]=(yu_iris[0][1]-yu_iris[0][0])*((rand()%100)/200+0.5)+yu_iris[0][0];
point_iris[1][1]=(yu_iris[1][1]-yu_iris[1][0])*((rand()%100)/200+0.5)+yu_iris[1][0];
point_iris[1][2]=(yu_iris[2][1]-yu_iris[2][0])*((rand()%100)/200+0.5)+yu_iris[2][0];
point_iris[1][3]=(yu_iris[3][1]-yu_iris[3][0])*((rand()%100)/200+0.5)+yu_iris[3][0];
point_iris[2][0]=(yu_iris[0][1]-yu_iris[0][0])*((rand()%100)/200+0.5)+yu_iris[0][0];
point_iris[2][1]=(yu_iris[1][1]-yu_iris[1][0])*((rand()%100)/200+0.5)+yu_iris[1][0];
point_iris[2][2]=(yu_iris[2][1]-yu_iris[2][0])*((rand()%100)/200+0.5)+yu_iris[2][0];
point_iris[2][3]=(yu_iris[3][1]-yu_iris[3][0])*((rand()%100)/200+0.5)+yu_iris[3][0];
}
else
{
for(tag_a=0;tag_a<60;tag_a++)
{
point_sonar[0][tag_a]=0.001;
point_sonar[1][tag_a]=0.5;
}
}
}
函数3 分类函数sort(bool is_iris)
计算数据和各类中心点point_iris或point_sonars的距离,进而将数据进行归类(iris给数据第6维赋值,sonar给数据第62维赋值)
其中dis(double a[],double b[],int add_a,int add_b,int deep_a,int num)
函数用于计算a数组的第add_a行和b数组的第add_b行的前num列元素的二范数,deep_a是a数组每行拥有的列数
void kmeans::sort(bool is_iris)
{
if(is_iris)
{
double(*p)[6]=data_iris;
double(*p_1)[4]=point_iris;
for(tag_a=0;tag_a<150;tag_a++)
{
if(dis(*p,*p_1,tag_a,0,6,4)<=dis(*p,*p_1,tag_a,1,6,4)&&dis(*p,*p_1,tag_a,0,6,4)<=dis(*p,*p_1,tag_a,2,6,4))
data_iris[tag_a][5]=0;
else if(dis(*p,*p_1,tag_a,1,6,4)<=dis(*p,*p_1,tag_a,0,6,4)&&dis(*p,*p_1,tag_a,1,6,4)<=dis(*p,*p_1,tag_a,2,6,4))
data_iris[tag_a][5]=1;
else data_iris[tag_a][5]=2;
}
}
else
{
double(*p)[62]=data_sonar;
double(*p_1)[60]=point_sonar;
for(tag_a=0;tag_a<208;tag_a++)
{
//double a=dis(*p,*p_1,tag_a,0,62,60);
//double b=dis(*p,*p_1,tag_a,1,62,60);
if(dis(*p,*p_1,tag_a,0,62,60)>=dis(*p,*p_1,tag_a,1,62,60))
data_sonar[tag_a][61]=0;
else data_sonar[tag_a][61]=1;
}
}
}
函数4 更新样本中心点 reload_z(bool is_iris)
kmeans方法采用求各类均值的方式进行中心点的更新中心分别存放在数组point_iris和point_sonar中
void kmeans::reload_z(bool is_iris)
{
if(is_iris)
{
//各类总数
int number[3]={0,0,0};
double cent[3][4]={0,0,0,0,0,0,0,0,0,0,0,0};
for(tag_a=0;tag_a<120;tag_a++)
{
for(tag_b=0;tag_b<4;tag_b++)
cent[int(data_iris[tag_a][5])][tag_b]+=data_iris[tag_a][tag_b];
number[int(data_iris[tag_a][5])]++;
}
for(tag_a=0;tag_a<3;tag_a++)
for(tag_b=0;tag_b<4;tag_b++)
if(number[tag_a]!=0)
point_iris[tag_a][tag_b]=cent[tag_a][tag_b]/number[tag_a];
}
else
{
int number[2]={0,0};
double cent[2][60];
for(tag_a=0;tag_a<60;tag_a++)
for(tag_b=0;tag_b<2;tag_b++)
cent[tag_b][tag_a]=0;
for(tag_a=0;tag_a<208;tag_a++)
{
for(tag_b=0;tag_b<60;tag_b++)
cent[int(data_sonar[tag_a][61])][tag_b]+=data_sonar[tag_a][tag_b];
number[int(data_sonar[tag_a][61])]++;
}
for(tag_a=0;tag_a<2;tag_a++)
for(tag_b=0;tag_b<60;tag_b++)
point_sonar[tag_a][tag_b]=cent[tag_a][tag_b]/number[tag_a];
}
}
函数5 计算轮廓系数
轮廓系数公式:
S
(
i
)
=
b
(
i
)
−
a
(
i
)
m
a
x
(
b
(
i
)
,
a
(
i
)
)
S_{(i)}=\frac{b_{(i)}-a_{(i)}}{max(b_{(i)},a_{(i)})}
S(i)=max(b(i),a(i))b(i)−a(i)
其中
a
(
i
)
a_{(i)}
a(i) = average(i向量到所有它属于的簇中其它点的距离)
b
(
i
)
b_{(i)}
b(i) = min (i向量到与它相邻最近的一簇内的所有点的平均距离)
double kmeans::load_sc(bool is_iris)
{
if(is_iris)
{
int b_num=0,a_num=0;
double data[120][3],dataa;
for(tag_a=0;tag_a<120;tag_a++)
for(tag_b=0;tag_b<3;tag_b++)
data[tag_a][tag_b]=0;
for(tag_a=0;tag_a<120;tag_a++)
for(tag_b=0;tag_b<120;tag_b++)
{
if(tag_b==0)b_num=0;
if(tag_b==0)a_num=0;
if(data_iris[tag_a][5]==data_iris[tag_b][5])
{
a_num++;
dataa=0;
for(tag_c=0;tag_c<3;tag_c++)
dataa+=pow((data_iris[tag_a][tag_c]-data_iris[tag_b][tag_c]),2);
data[tag_a][0]+=pow(dataa,0.5);
}
else
{
b_num++;
dataa=0;
for(tag_c=0;tag_c<3;tag_c++)
dataa+=pow((data_iris[tag_a][tag_c]-data_iris[tag_b][tag_c]),2);
data[tag_a][1]+=pow(dataa,0.5);
}
if(tag_b==119)
{
data[tag_a][0]/=a_num;
data[tag_a][1]/=b_num;
}
}
for(tag_a=0;tag_a<120;tag_a++)
{
if(data[tag_a][1]>data[tag_a][0])
data[tag_a][2]=(data[tag_a][1]-data[tag_a][0])/data[tag_a][1];
else
data[tag_a][2]=(data[tag_a][1]-data[tag_a][0])/data[tag_a][0];
}
dataa=0;
for(tag_a=0;tag_a<120;tag_a++)
dataa+=data[tag_a][2];
return dataa/120;
}
else
{
int b_num=0,a_num=0;
double data[208][3],dataa;
for(tag_a=0;tag_a<208;tag_a++)
for(tag_b=0;tag_b<3;tag_b++)
data[tag_a][tag_b]=0;
for(tag_a=0;tag_a<208;tag_a++)
for(tag_b=0;tag_b<208;tag_b++)
{
if(tag_b==0)b_num=0;
if(tag_b==0)a_num=0;
if(data_sonar[tag_a][61]==data_sonar[tag_b][61])
{
a_num++;
dataa=0;
for(tag_c=0;tag_c<60;tag_c++)
dataa+=pow((data_sonar[tag_a][tag_c]-data_sonar[tag_b][tag_c]),2);
data[tag_a][0]+=pow(dataa,0.5);
}
else
{
b_num++;
dataa=0;
for(tag_c=0;tag_c<60;tag_c++)
dataa+=pow((data_sonar[tag_a][tag_c]-data_sonar[tag_b][tag_c]),2);
data[tag_a][1]+=pow(dataa,0.5);
}
if(tag_b==207)
{
if(a_num!=0)
data[tag_a][0]/=a_num;
if(b_num!=0)
data[tag_a][1]/=b_num;
}
}
for(tag_a=0;tag_a<208;tag_a++)
{
if(data[tag_a][1]>data[tag_a][0])
data[tag_a][2]=(data[tag_a][1]-data[tag_a][0])/data[tag_a][1];
else
data[tag_a][2]=(data[tag_a][1]-data[tag_a][0])/data[tag_a][0];
}
dataa=0;
for(tag_a=0;tag_a<208;tag_a++)
dataa+=data[tag_a][2];
return dataa/208;
}
}
dis函数
double kmeans::dis(double a[],double b[],int add_a,int add_b,int deep_a,int num)
{
double num_all=0;
for(int tag_a=0;tag_a<num;tag_a++)
{
num_all+=(a[add_a*deep_a+tag_a]-b[add_b*num+tag_a])*(a[add_a*deep_a+tag_a]-b[add_b*num+tag_a]);
}
return pow(num_all,0.5);
}
FCM
问题概况
问题同kmeans,步骤如下:
step1: 对隶属度矩阵U使用(0,1)之间的随机数进行初始化,使其满足约束:
KaTeX parse error: Can't use function '$' in math mode at position 25: …1}^c{u_{ij}}=1,$̲ $\forall$i=1,.…
step2: 计算c个聚类中心,j=1,…,c
z
j
=
∑
i
=
1
m
u
i
j
α
x
i
∑
i
=
1
m
u
i
j
α
z_j=\frac{\sum^m_{i=1}u_{ij}^\alpha x_i}{\sum_{i=1}^mu_{ij}^\alpha}
zj=∑i=1muijα∑i=1muijαxi
step3: 计算代价函数。如果他小于某个阈值,或者它与上一次迭代的代价函数值的变化小于某个阈值,则算法停止。
J
(
U
,
z
1
,
.
.
.
,
z
c
)
=
∑
j
=
1
c
J
j
=
∑
j
=
1
c
∑
i
=
1
m
u
i
j
α
d
i
j
2
J(U,z_1,...,z_c)=\sum^c_{j=1}J_j=\sum^c_{j=1}\sum^m_{i=1}u^\alpha_{ij}d^2_{ij}
J(U,z1,...,zc)=j=1∑cJj=j=1∑ci=1∑muijαdij2
step4: 计算新的U矩阵。返回step2
u
i
j
=
1
∑
k
=
1
c
(
d
i
j
/
d
i
k
)
2
/
(
α
−
1
)
u_{ij}=\frac{1}{\sum^c_{k=1}(d_{ij}/d_{ik})^{2/(\alpha-1)}}
uij=∑k=1c(dij/dik)2/(α−1)1
代码
结构总览
int main()
{
FCM f;
int m=30;//用于计数
bool is_iris=0;//切换数据集
f.load_iris();//载入数据
f.load_sonar();//载入数据
f.init_u(is_iris);//初始化u矩阵
while(m--)
{
f.reload_z(is_iris);//更新z矩阵
f.reload_u(is_iris);//更新u矩阵
f.sort(is_iris);//归类
if(is_iris)
f.fenxi(1,2);//可视化iris数据
cout<<"cs:"<<f.load_sc(is_iris)<<endl;//输出轮廓系数
if(is_iris)
waitKey(0);
}
return 0;
}
函数6 FCM更新中心点 f.reload_z(is_iris);
根据FCM公式更新样本中心点(step2)
sum[3]用来存放分母 ∑ i = 1 m u i j α ( j = 1 , . . . , c ) \sum^m_{i=1}u_{ij}^\alpha(j=1,...,c) ∑i=1muijα(j=1,...,c)
point_iris用来存放聚类中心
z j = ∑ i = 1 m u i j α x i ∑ i = 1 m u i j α z_j=\frac{\sum^m_{i=1}u_{ij}^\alpha x_i}{\sum_{i=1}^mu_{ij}^\alpha} zj=∑i=1muijα∑i=1muijαxi
void FCM::reload_z(bool is_iris)
{
if(is_iris)
{
for(tag_b=0;tag_b<4;tag_b++)
for(tag_c=0;tag_c<3;tag_c++)
point_iris[tag_b][tag_c]=0;
double sum[3];
for(tag_a=0;tag_a<3;tag_a++)
sum[tag_a]=0;
for(tag_a=0;tag_a<120;tag_a++)
for(tag_b=0;tag_b<3;tag_b++)
sum[tag_b]+=pow(u_iris[tag_a][tag_b],alpha);
for(tag_a=0;tag_a<120;tag_a++)
for(tag_b=0;tag_b<4;tag_b++)
for(tag_c=0;tag_c<3;tag_c++)
point_iris[tag_c][tag_b]+=pow(u_iris[tag_a][tag_c],alpha)*data_iris[tag_a][tag_b];
for(tag_c=0;tag_c<3;tag_c++)
for(tag_b=0;tag_b<4;tag_b++)
point_iris[tag_c][tag_b]/=sum[tag_c];
}
else
{
for(tag_b=0;tag_b<2;tag_b++)
for(tag_c=0;tag_c<60;tag_c++)
point_sonar[tag_b][tag_c]=0;
double sum[2];
for(tag_a=0;tag_a<2;tag_a++)
sum[tag_a]=0;
for(tag_a=0;tag_a<208;tag_a++)
for(tag_b=0;tag_b<2;tag_b++)
sum[tag_b]+=pow(u_sonar[tag_a][tag_b],alpha);
for(tag_a=0;tag_a<208;tag_a++)
for(tag_b=0;tag_b<60;tag_b++)
for(tag_c=0;tag_c<2;tag_c++)
point_sonar[tag_c][tag_b]+=pow(u_sonar[tag_a][tag_c],alpha)*data_sonar[tag_a][tag_b];
for(tag_c=0;tag_c<2;tag_c++)
for(tag_b=0;tag_b<60;tag_b++)
point_sonar[tag_c][tag_b]/=sum[tag_c];
}
}
函数7 更新隶属度矩阵u函数 reload_u(bool is_iris)step4
u i j = 1 ∑ k = 1 c ( d i j / d i k ) 2 / ( α − 1 ) u_{ij}=\frac{1}{\sum^c_{k=1}(d_{ij}/d_{ik})^{2/(\alpha-1)}} uij=∑k=1c(dij/dik)2/(α−1)1
这里的d_iris(int a,int b),d_sonar函数用来求数据集中第a组数据和第b组数据的欧式距离
void FCM::reload_u(bool is_iris)
{
if(is_iris)
{
for(tag_a=0;tag_a<120;tag_a++)
for(tag_b=0;tag_b<3;tag_b++)
{
for(tag_c=0;tag_c<3;tag_c++)
{
u_iris[tag_a][tag_b]+=pow(d_iris(tag_a,tag_b)/d_iris(tag_a,tag_c),2/(alpha-1));
}
u_iris[tag_a][tag_b]=1/u_iris[tag_a][tag_b];
}
}
else
{
for(tag_a=0;tag_a<208;tag_a++)
for(tag_b=0;tag_b<2;tag_b++)
{
for(tag_c=0;tag_c<2;tag_c++)
{
u_sonar[tag_a][tag_b]+=pow(d_sonar(tag_a,tag_b)/d_sonar(tag_a,tag_c),2/(alpha-1));
}
u_sonar[tag_a][tag_b]=1/u_sonar[tag_a][tag_b];
}
}
}
函数8 根据隶属度的归类函数 sort(bool is_iris)
void FCM::sort(bool is_iris)
{
double(*p)[3]=u_iris;
double(*p1)[2]=u_sonar;
if(is_iris)
{
for(tag_a=0;tag_a<120;tag_a++)
data_iris[tag_a][5]=max(*p,tag_a,3);
}
else
{
for(tag_a=0;tag_a<208;tag_a++)
data_sonar[tag_a][61]=max(*p1,tag_a,2);
}
}
d_iris和d_sonar函数
double FCM::d_iris(int a,int b)
{
double fin=0;
for(int tag=0;tag<4;tag++)
fin+=(data_iris[a][tag]-point_iris[b][tag])*(data_iris[a][tag]-point_iris[b][tag]);
return sqrt(fin);
}
double FCM::d_sonar(int a,int b)
{
double fin=0;
for(int tag=0;tag<60;tag++)
fin+=(data_sonar[a][tag]-point_sonar[b][tag])*(data_sonar[a][tag]-point_sonar[b][tag]);
return sqrt(fin);
}
iris图片显示函数
void kmeans::fenxi(int a,int b)
{
cv::Mat fra=cv::Mat(cv::Size(800,800), CV_8UC3);
cv::Mat fra_new=cv::Mat(cv::Size(800,800), CV_8UC3);
for(tag_a=0;tag_a<800;tag_a++)
for(tag_b=0;tag_b<800;tag_b++)
{
fra.at<cv::Vec3b>(tag_a,tag_b)[0]=0;
fra.at<cv::Vec3b>(tag_a,tag_b)[1]=0;
fra.at<cv::Vec3b>(tag_a,tag_b)[2]=0;
fra_new.at<cv::Vec3b>(tag_a,tag_b)[0]=0;
fra_new.at<cv::Vec3b>(tag_a,tag_b)[1]=0;
fra_new.at<cv::Vec3b>(tag_a,tag_b)[2]=0;
}
for(tag_a=0;tag_a<120;tag_a++)
{
fra.at<cv::Vec3b>(data_iris[tag_a][a]*100,data_iris[tag_a][b]*100-1)[data_iris[tag_a][4]]=255;
fra.at<cv::Vec3b>(data_iris[tag_a][a]*100,data_iris[tag_a][b]*100+1)[data_iris[tag_a][4]]=255;
fra.at<cv::Vec3b>(data_iris[tag_a][a]*100,data_iris[tag_a][b]*100)[data_iris[tag_a][4]]=255;
fra.at<cv::Vec3b>(data_iris[tag_a][a]*100-1,data_iris[tag_a][b]*100)[data_iris[tag_a][4]]=255;
fra.at<cv::Vec3b>(data_iris[tag_a][a]*100+1,data_iris[tag_a][b]*100)[data_iris[tag_a][4]]=255;
fra_new.at<cv::Vec3b>(data_iris[tag_a][a]*100,data_iris[tag_a][b]*100-1)[data_iris[tag_a][5]]=255;
fra_new.at<cv::Vec3b>(data_iris[tag_a][a]*100,data_iris[tag_a][b]*100+1)[data_iris[tag_a][5]]=255;
fra_new.at<cv::Vec3b>(data_iris[tag_a][a]*100,data_iris[tag_a][b]*100)[data_iris[tag_a][5]]=255;
fra_new.at<cv::Vec3b>(data_iris[tag_a][a]*100-1,data_iris[tag_a][b]*100)[data_iris[tag_a][5]]=255;
fra_new.at<cv::Vec3b>(data_iris[tag_a][a]*100+1,data_iris[tag_a][b]*100)[data_iris[tag_a][5]]=255;
}
for(tag_a=0;tag_a<3;tag_a++)
for(tag_c=0;tag_c<3;tag_c++)
for(tag_b=-2;tag_b<3;tag_b++)
for(int tag=-2;tag<3;tag++)
fra_new.at<cv::Vec3b>(point_iris[tag_a][a]*100+tag,point_iris[tag_a][b]*100+tag_b)[tag_c]=255;
char m[1];
m[0]=a+'0';
cv::imshow(m,fra);
m[0]=a+'3';
cv::imshow(m,fra_new);
}
ps kmeans类,FCM类
class kmeans
{
private:
//计数用
int tag_a,tag_b,tag_c;
//数据阈值(初始化中心时用到)
double yu_iris[4][2],yu_sonar[60][2];
//载入数据
double data_iris[120][6],data_sonar[208][62];
//数据中心z
//double point_iris[3][4],point_sonar[2][60];
public:
double dis(double a[],double b[],int add_a,int add_b,int deep_a,int num);
public:
double point_iris[3][4],point_sonar[2][60];
//载入数据
void load_iris();
void load_sonar();
void init_kmeans(bool is_iris);
void sort(bool is_iris);
void reload_z(bool is_iris);
void show();
void fenxi(int a,int b);
double load_sc(bool is_iris);
};
FCM
class FCM
{
private:
//计数用0
int tag_a,tag_b,tag_c;
double alpha=2;
//数据阈值(初始化中心时用到)
double yu_iris[4][2],yu_sonar[60][2];
//载入数据
double data_iris[120][6],data_sonar[208][62];
double u_iris[120][3]={
0.2,0.4,0.4,0.2,
0.4,0.2,0.4,0.2,
0.4,0.4,0.2,0.6,
};
double u_sonar[208][2];
//数据中心z
//double point_iris[3][4],point_sonar[2][60];
public:
double d_iris(int a,int b);
double dis(double a[],double b[],int add_a,int add_b,int deep_a,int num);
public:
double point_iris[3][4],point_sonar[2][60];
//载入数据
void load_iris();
void load_sonar();
void init_u(bool is_iris);
void sort(bool is_iris);
void reload_z(bool is_iris);
void reload_u(bool is_iris);
int max(double a[],int num,int wide);
void show();
void fenxi(int a,int b);
double load_sc(bool is_iris);
double d_sonar(int a,int b);
};
FCM进行图片特征提取
代码只需将图片信息载入到data[m][4]即可(m是图片像素数,第四维存放分类信息):
void FCM::load_pic()
{
Mat a=imread("2.bmp",1);
imshow("src",a);
int tag=0;
for(tag_a=0;tag_a<a.cols;tag_a++)
for(tag_b=0;tag_b<a.rows;tag_b++)
{
for(tag_c=0;tag_c<3;tag_c++)
{
data[tag][tag_c]=a.at<Vec3b>(tag_b,tag_a)[tag_c];
}
tag++;
}
}
后面的同上
效果:
结语
作者水平有限,若发现问题还望慷慨指正