1.项目说明
这是自己写着玩的一个小项目,结合了遗传算法和图像分割的算法,实现了图像的边缘提取。图像分割的算法采用了大津阈值法,在该算法中,改造成使用遗传算法来寻找最佳阈值。该项目通过每隔1秒刷新界面的方式实时展示边缘提取的过程,并通过动态图表的方式展示每次遗传算法算出的最佳阈值。
2.效果展示
3.环境配置
- 本项目采用HTML/CSS/JS编写,请使用chrome/firefox等主流浏览器查看。
- 由于很多浏览器存在禁止跨域访问的问题,因此我把该项目部署到了服务器上。具体使用到的工具是tomcat。部署到服务器上后,直接点击starter.html即可运行。
4.算法知识介绍
- 大津阈值法
最大类间方差法是由日本学者大津于1979年提出的,是一种自适应的阈值确定的方法,又叫大津法,简称OTSU。它是按图像的灰度特性,将图像分成背景和目标2部分。背景和目标之间的类间方差越大,说明构成图像的2部分的差别越大,当部分目标错分为背景或部分背景错分为目标都会导致2部分差别变小。因此,使类间方差最大的分割意味着错分概率最小。对于图像I(x,y),前景(即目标)和背景的分割阈值记作T,属于前景的像素点数占整幅图像的比例记为ω0,其平均灰度μ0;背景像素点数占整幅图像的比例为ω1,其平均灰度为μ1。图像的总平均灰度记为μ,类间方差记为g。假设图像的背景较暗,并且图像的大小为M×N,图像中像素的灰度值小于阈值T的像素个数记作N0,像素灰度大于阈值T的像素个数记作N1,则有:
ω0=N0/ M×N (1)
ω1=N1/ M×N (2)
N0+N1=M×N (3)
ω0+ω1=1 (4)
μ=ω0*μ0+ω1*μ1 (5)
g=ω0(μ0-μ)^2+ω1(μ1-μ)^2 (6)
将式(5)代入式(6),得到等价公式:
g=ω0ω1(μ0-μ1)^2 (7)
采用遍历的方法得到使类间方差最大的阈值T,即为所求。 遗传算法
种群(Population):生物的进化以群体的形式进行,这样的一个群体称为种群。
个体:组成种群的单个生物。
基因 ( Gene ) :一个遗传因子。
染色体 ( Chromosome ) :包含一组的基因。
生存竞争,适者生存:对环境适应度高的、牛B的个体参与繁殖的机会比较多,后代就会越来越多。适应度低的个体参与繁殖的机会比较少,后代就会越来越少。
遗传与变异:新个体会遗传父母双方各一部分的基因,同时有一定的概率发生基因变异。简单说来就是:繁殖过程,会发生基因交叉( Crossover ) ,基因突变 ( Mutation ) ,适应度( Fitness )低的个体会被逐步淘汰,而适应度高的个体会越来越多。那么经过N代的自然选择后,保存下来的个体都是适应度很高的,其中很可能包含史上产生的适应度最高的那个个体。
借鉴生物进化论,遗传算法将要解决的问题模拟成一个生物进化的过程,通过复制、交叉、突变等操作产生下一代的解,并逐步淘汰掉适应度函数值低的解,增加适应度函数值高的解。这样进化N代后就很有可能会进化出适应度函数值很高的个体。
5.代码实现
1.创建一个类,用来实现遗传算法的交叉,突变,产生下一代操作
var Genetic=function(src){
this.count=1000;//迭代次数
this.curchromo=new Array();//初始种群
this.nextchromo=new Array();//更新后种群
this.popnum=4;//初始化种群个数
this.genenum=8;//基因位数
this.myfun=myfun;
this.crossrate=0.8;
this.muterate=0.1;
this.cmax=-1;
this.canvas=document.getElementById("can");
this.ctx=this.canvas.getContext('2d');
//this.img=new Image();
this.px;
this.init=function(){
var img=new Image();
img.src='img/ss.jpg';
ctx.drawImage(img,0,0,222,269);
this.px=ctx.getImageData(0,0,222,269);
}
this.accute=function(){
this.updatePop(this.curchromo,this.nextchromo);
this.selection(this.nextchromo);
this.crossover(this.nextchromo);
this.mutation(this.nextchromo);
this.updatePop(nextchromo,curchromo);
this.cmax(curchromo);
}
this.cmax=function(curchromo){
for (var i = 0; i <this.popnum; i++) {
var maxval=(curchromo[i].fitValue>this.max)?curchromo[i].fitValue:this.max;
}
}
//创建初始种群
this.randCreatePop=function(curchromo){
for(var i=0;i<this.popnum;i++){
for(var j=0;j<this.genenum;j++){
var randvalue=random();
// this.curchromo[i]={
// "geneBit":new Array(),
// "fitValue":0
// }
var chromo=new Chromo();
chromo.geneBit.length=0;//初始化
chromo.geneBit.push(randvalue);
}
var value=this.binToDec(chromo);
chromo.fitValue=this.calFitValue(value);//计算染色体的适应度值
this.curchromo.push(chromo);//生成实验组
}
}
//选择优良的个体
this.selection=function(curchromo){
for(var s=this.popnum;s>0;s--){
for(var m=0;m<s-1;s++){
if(curchromo[m+1].fitValue>curchromo[m].fitValue){
var tem=curchromo[m+1];
curchromo[m+1]=pop[m];
pop[m]=tem;
}
}
}//排序
var sumFitValue=0;
for(var i=0;i<this.popnum;i++){
sumFitValue+=curchromo[i].fitValue;
}
var avFitValue=sumFitValue/this.popnum;
var choicePro=new Array(this.popnum);
for(var j=0;j<this.popnum;j++){
choicePro[j]=(curchromo[j].fitValue/sumFitValue)/(avFitValue/sumFitValue);
}
//根据选择概率来繁殖优良个体
for(var t=0;t<this.popnum;t++){
if((int)(choicePro[t]+0.55)==0)
curchromo[this.popnum-1]=curchromo[0];
}
}
//交叉染色体的片段
this.crossover=function(curchromo){
if(Math.random()>this.crossrate){
return;
}
for(var i=0;i<this.popnum;i+=2){
var randPos=Math.round(Math.random()*(this.genenum-1));
var s=i+1;
for(var j=0;j<randPos;j++){
var tmp=curchromo[i].geneBit[j];
curchromo[i].geneBit[j]=curchromo[s].geneBit[j];
curchromo[s].geneBit[j]=tmp;
}
}
for(i=0;i<this.popnum;i++){
curchromo[i].fitValue=this.calFitValue(binToDec(curchromo[i]));
}
}
//变异:随机改变染色体片段的值
this.mutation=function(curchromo){
var rndvalue=Math.round(Math.random()*100);
if(rndvalue>=this.muterate*100){
return;
}
var randgene=Math.round(Math.random()*(this.genenum-1));
var randchromo=Math.round(Math.random()*(this.popnum-1));
curchromo[randchromo].geneBit[randgene]=(curchromo[randchromo].geneBit[randgene]=='0')?'1':'0';
curchromo[randchromo].fitValue=calFitValue(binToDec(curchromo[randchromo]));
}
2.使用遗传算法计算最佳阈值
this.calFitValue=function(target){
var W0=0,W1=0,NUM0=0,NUM1=0,U0=0,U1=0,U,Gnow=0;
var N0=0,N1=0;
for(var i=0;i<LENGTH;i+=4){
if(px.data[i]<=target){
N0+=1;
NUM0+=px.data[i];
}else{
N1+=1;
NUM1+=px.data[i];
}
}
W0=numberFormat(N0/(M*N),2);//前景像素点站整幅图的比例
//W1=numberFormat(N1/(M*N),2);
W1=numberFormat(1-W0,2);//后经像素点占整幅图的比例
U0=(N0==0)?0:(NUM0/N0);//前景平均灰度
U1=(N1==0)?0:(NUM1/N1);//后经平均灰度
U=NUM0/(M*N)+NUM1/(M*N);//总平均灰度
Gnow=W0*Math.pow((U0-U),2)+W1*Math.pow((U1-U),2);//g=ω0ω1(μ0-μ1)^2 //写入函数
return Gnow;
}
3.实时展示
function draw(){
genetic.accute();
var target=genetic.cmax;
for(var i=0;i<px.data.length;i+=4){ if(px.data[i]<=target){ px.data[i]=0;px.data[i+1]=0;px.data[i+2]=0;px.data[i+3]=255; }else{ px.data[i]=255;px.data[i+1]=255;px.data[i+2]=255;px.data[i+3]=255; }
}
genetic.ctx.putImageData(px,0,0);
}
6.源码下载
https://github.com/whuzxq/GA_engine
如果觉得帮助到你,就star一下吧~!