JS实现图像像素聚类

在此次实践中,对于Kmeans聚类算法交互式改变簇数的时候,我发现我的button按钮必须点击两次才行,目前还未找出原因。
说明:对于图像的画布显示用Canvas,柱状图、饼图采用的是Echarts模板展示。
需要连接python 服务器,管理员cmd进入当前目录,采用python -m http.server 80000方式建立,后直接在浏览器中输入http://localhost:8000即可。

<!DOCTYPE html>
<!--
1.此次实践实现图片显示以及图片的聚类柱状图饼形图显示。
2.实现图片选择的交互式,仅支持打开JPG图像
3.实现柱状图、条形图切换
4.可视化聚类中心颜色即是柱状图或者饼状图颜色,数量,中心RGB具体值显示需鼠标接触显示
5.实现交互式改变kmeans的簇数,簇数不能为1,实践中没有进行非法处理,不然会出现问题(该过程加载缓慢)最好点击两次
-->
<html>
<head>
	<meta charset="utf-8">
	<title>Lab01</title>
</head>
<body>
<!--设置div绝对位置-->
<!--border-style:solid;
	border-color:blue;-->
<style type = "text/css"> 
.div2{
	height:600px;
	background-color:white;
	position:absolute;
	top:20px;
	left:710px;
	right:5%;
}
#div4bm{
	height:100px;
	width:400px;
	background-color:white;
	position:absolute;
	top:470px;
	left:590px;
  }
  #mybutton{
  margin-left:50px;
}
#myform{
	background-color:white;
	margin-left:40%;
}
#container{
	height:70%;
	width:100%;
}
</style>

<script type="text/javascript" src="echarts.min.js"></script>
<!--script type="text/javascript" src="jquery-1.8.2.min.js"></script-->
<!-- 
	一个画布
	画布相关代码参考:https://www.w3school.com.cn/html5/html_5_canvas.asp
-->
<canvas id="myCanvas" width="690" height="457" style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>

<div id="div4bm" >
  <!--input[button] 触发 file click事件-->
  <input type="button" value="选择文件" id="mybutton" class="mybtn" onclick="Id('file').click();" />
  <!--file 隐藏起来 触发onchange事件-->
  <input type="file" name="file" accept="image/jpg" id="file" onchange="changeToop(this);" style="display:none;" />
 </div>
<div class = "div2">
<div id="container" ></div>
<!--设置Radio按钮,实现柱状图与饼状图的选择-->
<form action="" method="get" id = "myform"> 
	<label>输入簇数:<input name="k_means" type="text" id="myks" style="width:30px;height:20px"/></label>
	<label><input name="get" type="button" value="提交(点两次)" onclick = "change_k()"/></label><br/>
	<label><input name="charts" type="radio" id="0" onclick = "changechart();" checked/>柱状图 </label> 
	<label><input name="charts" type="radio" id="1" onclick = "changechart();"/>饼状图</label> 
  </form>
</div>

<script type="text/javascript">

	//响应kmeans簇数k的改变
	function change_k()
	{
		myks = document.getElementById("myks").value;
		myload();
	}

	//响应展示图Radio按钮改变事件函数
	function changechart(){
		if(document.getElementById("0").checked){ //柱状图
			var dom = document.getElementById("container");
			var myChart = echarts.init(dom);
			var app = {};
			var option;
			option = {
				tooltip: {
					trigger: 'axis',
					axisPointer: {
					type: 'shadow'
					}
				},
				xAxis: [{
					type: 'category',
					data: colorList,
					show:true,
					axisTick: {
						alignWithLabel: true
					},
					axisLabel:{
						interval:(index,value) =>{return false}//设置X轴数据不显示
					}
				}],
				yAxis: [{
					type: 'value',
					show:true
				}],
				grid:{
					containLabel:true
				},
			
				series: [{
					name: '数量',
					data: mycnt,
					type: 'bar',
					barWidth: '50%',
					itemStyle: {   
	        //每个柱子的颜色即为colorList数组里的每一项,如果柱子数目多于colorList的长度,则柱子颜色循环使用该数组
						color: function (params){
							//console.log(params.dataIndex);
							//console.log(colorList[params.dataIndex]);
							return colorList[params.dataIndex];
						}
					}
				}]
			};
			if (option && typeof option === 'object') {
				myChart.setOption(option);
			}
		}
		else{									//饼状图
			var dom = document.getElementById("container");
			var myChart = echarts.init(dom);
			var app = {};
			var option;
			var piedata = new Array();
			for(var i = 0; i < ks ; i++){
				piedata.push({value:mycnt[i],name:colorList[i],itemStyle:{color:colorList[i]}});
			}
			piedata.sort(function (a, b) {
				return a.value - b.value;
			 });
		
			option = {
				xAxis: [{show:false}],
				yAxis: [{show:false}],
				tooltip: {
					trigger: 'item'
				},
				series: [{
					name:"",
					labelLine: {show:false},
					label:{show:false},
					type: 'pie',
					radius: '55%',
					center: ['50%', '50%'],
					data: piedata,
					roseType: 'radius',
					animationType: 'scale',
					animationEasing: 'elasticOut',
					animationDelay: function (idx) {
						return Math.random() * 200;
					}
				}]
			};
			if (option && typeof option === 'object') {
				myChart.setOption(option);
			}
		}
	}
	
	//通过JQuery方法响应radio事件
	/*$('input[type=radio][name=charts]').change(function () {
    // 获取input radio选中值,方法一
    var myvalue = $(this).val();
	if(myvalue!=check)
		changechart(myvalue);
	check = myvalue;
	console.log(check);
	});*/
	
	//加载打开图片并且进行聚类分析
	function myload(){
		if(ks == myks)
		{
		var context = document.getElementById('myCanvas').getContext('2d');
		context.drawImage(img, 0, 0);
		// data中保存了图片所有像素的颜色信息,每个像素的RGBA信息占数组中4位
		// RGBA为像素的红色、绿色、蓝色、透明度四个分量	
		//但此次聚类我分析的只是颜色,故聚类RGB
		 var data = context.getImageData(0, 0, 690, 457).data;
		}
		else
		{
			ks = myks;
			colorList.length = 0;
		}
		//console.log(data);
		var cnt = 690*457; //图片中总的像素个数
		
		var point = [];//创建数组保留像素的RGB值
		var layout = [];//记录每个簇的点的在point中的标号,就是分在哪个簇
		var k = 0;//记录data索引

		for(var i = 0; i < cnt; i++)
		{
			layout[i] =[];
			layout[i][0] = 0;
			layout[i][1] = 200000;
			point[i] = [];
			point[i][0] = data[k];
			k++;
			point[i][1] = data[k];
			k++;
			point[i][2] = data[k];
			k++;
			//point[i][3] = data[k];
			k++; //透明度A直接跳过
		}
			
		//kmeans具体算法
		//01.选择初始化的点(随便,或者函数点) 利用随机函数
		var centroids = [];
		console.log(ks);
		for (var i = 0;i < ks; i ++)
		{
			centroids[i] = [];
			var index = Math.round(Math.random()*(cnt));
			centroids[i][0] = point[index][0];
			centroids[i][1] = point[index][1];
			centroids[i][2] = point[index][2];
			//centroids[i][3] = point[i][3];
		}
		
		var change = true;//标志簇是否改变
		while (change==true)
		{
			change = false;
			for ( var i = 0; i < cnt; i++)
			{
				var mindist =  200000;
				var minindex = 0;
				//02.每个点找到离得最近的簇
				for (var j = 0; j < ks; j++)
				{
					var dis = Math.sqrt(Math.pow(point[i][0]-centroids[j][0],2)+Math.pow(point[i][1]-centroids[j][1],2)+
								Math.pow(point[i][2]-centroids[j][2],2));
					if (dis < mindist)
					{
						mindist = dis;
						minindex = j;
					}
				}
				if (layout[i][0] != minindex)
				{
					change = true;
					layout[i][0] = minindex;
					layout[i][1] = mindist;
				}
				
			}
			console.log(change);
			//03.更新簇
			var mysum = [];
			for (var i = 0; i < ks;i++)
			{
				mysum[i] = [];
				mysum[i][0] = 0;
				mysum[i][1] = 0;
				mysum[i][2] = 0;
				//mysum[i][3] = 0;
				mycnt[i] = 0;
			} 
			for ( var i = 0; i < cnt;i++)
			{
				for(var j = 0; j< ks; j++)
				{
					if(layout[i][0] == j)
					{
						mysum[j][0] += point[i][0];
						mysum[j][1] += point[i][1];
						mysum[j][2] += point[i][2];
						//mysum[j][3] += point[i][3];
						mycnt[j]++;
						break;
					}
				}
			}
			for(var i = 0; i < ks; i ++)//对于每个坐标每次都需要四舍五入取整数
			{
				centroids[i][0] = Math.round(mysum[i][0]/mycnt[i]);
				centroids[i][1] = Math.round(mysum[i][1]/mycnt[i]);
				centroids[i][2] = Math.round(mysum[i][2]/mycnt[i]);
				//centroids[i][3] = Math.round(mysum[i][3]/mycnt[i]);
			}
			
		}
		
		
		//记录颜色数组
		for (var i = 0; i < ks; i++)
		{
			colorList[i] = 'rgb('+centroids[i][0]+','+centroids[i][1]+','+centroids[i][2]+')';
			console.log(colorList[i]);
		}
		//聚类图显示
		centroids.length=0;
		point.length = 0;
		layout.length=0;
		mysum.length = 0;
		data.length = 0;
		changechart();
	}

	function Id(id){
		return document.getElementById(id);
	}
	function changeToop(){
		var file = document.getElementById("file");
		if(file.value==''){
			//设置默认图片
			img.src='images/01.jpg';
		}
		else{
			preImg("file");
		}
	}
	//得到打开图片地址
	function getFileUrl(fileId) {
		var url;
		var file = document.getElementById(fileId);
		var agent = navigator.userAgent;
		if (agent.indexOf("MSIE")>=1) {
			url = file.value;
		} 
		else if(agent.indexOf("Firefox")>0) {
			url = window.URL.createObjectURL(file.files.item(0));
		} 
		else if(agent.indexOf("Chrome")>0) {
		  url = window.URL.createObjectURL(file.files.item(0));
		}
		console.log(url);
		return url;
	}
	//读取图片后预览
	function preImg(fileId) {
		img.src = getFileUrl(fileId);
		
		console.log(img.src);
		img.onload=function(){
			myload();
		};
		myload();
	}
	//myload();
	//初次加载图片
	var img = new Image();
	img.onload=function(){
		myload();
	};
	var colorList = [];//记录簇的颜色
	var mycnt = [];//记录某种簇的个数
	var ks = 4; //设置kmeans的簇数 如果画出的图某些位置为空,说明初始点选择出现问题
	var myks = 4; //设置输入框的值,只有输入框的值与k相等才需要重新绘图,否则,改变簇数即可
	//给予图像初始化地址,刚开始展示该图
	img.src='images/01.jpg';
</script>

</body>
</html>

实践效果:
在这里插入图片描述

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值