使用骰子作画
本文参考 阮一峰老师《骰子作画的算法》
原文链接 http://www.ruanyifeng.com/blog/2011/11/dice_portrait.html
1 计算灰度值方法
/* 任何颜色都由红、绿、蓝三基色组成,假如原来某点的颜色为RGB(R,G,B),那么,我们可以通过下面几种方法,将其转换为灰度:
1.浮点算法:Gray=R*0.3+G*0.59+B*0.11
2.整数方法:Gray=(R*30+G*59+B*11)/100
3.移位方法:Gray =(R*77+G*151+B*28)>>8;
4.平均值法:Gray=(R+G+B)/3;
5.仅取绿色:Gray=G;*/
2.骰子作画算法
1.第一步,将图片分割成16像素x16像素的小方块。 (分割的方块越小 ,模拟图生成的效果越好)
2. 计算小方块内的每一个像素点 将每个像素点的灰度值存入数组
3. 计算每一个小方块数组额灰度值的平均值 并用1~6之间的一个整数来表示
4. 用骰子绘制图片
var canvas = document.createElement('canvas'); // 将分好的块绘制在画布上显示处来
var context = canvas.getContext('2d');
var poixl = [];
// 获取图片的原始尺寸
var nImg = new Image();
// nImg.crossOrigin ='anonymous';
nImg.src = './painting.jpg';
var body = document.querySelector('body');
var w = 0,h = 0;
var pieceW = 16; //切割小方块的边长
var imgArr = []; // 绘制额小图标
inintImg();
nImg.onload = function(){
w = nImg.width;
h = nImg.height;
canvas.width = w ;
canvas.height = h ;
b();
}
function inintImg(){
var imgSrc = ['./img/t6.png','./img/t5.png','./img/t4.png','./img/t3.png','./img/t2.png','./img/t1.png'];
for(let i = 0 ; i < imgSrc.length ; i++ ){
var img = new Image();
img.src = imgSrc[i];
imgArr.push(img);
}
}
// 第一步,将图片分割成16像素x16像素的小方块。
function b(){
let can;
let ctx;
let wNum = w/pieceW;
let hNum = h/pieceW;
for(let i = 0 ; i < wNum; i++){
let arr1 = [];
for(let j = 0 ; j < hNum; j++){
can = document.createElement('canvas');
ctx = can.getContext('2d');
can.width = pieceW;
can.height = pieceW;
ctx.drawImage(nImg,pieceW*i,pieceW*j,pieceW,pieceW,0,0,1080,1440);
arr1.push(ctx);
}
poixl.push(arr1);
}
c();
}
//每个小方块内共有256个像素,将每个像素点的灰度值,存入一个数组。
function c(){
let arr = [];
for(let i = 0 ; i < poixl.length ; i++){
let arr1 = [];
for(let n = 0; n < poixl[i].length ; n++){
let arr2 = [];
for(let j = 0 ; j < pieceW ; j++ ){
for(let k = 0 ; k < pieceW ; k++ ){
let data = poixl[i][n].getImageData(j,k,1,1).data;
// 计算灰度值
arr2.push((data[0]+data[1]+data[2])/3);
}
}
arr1.push(arr2);
}
arr.push(arr1);
}
d(arr);
}
// 第三步,计算该数组的平均值,并用1-6之间的一个整数来表示。
// 计算平均值
function d(arr){
let ava = [];
for(let i = 0 ; i < arr.length ; i++){
for(let j = 0 ; j < arr[i].length ; j++){
let val = 0;
for(let k = 0; k < arr[i][j].length ; k++){
val += arr[i][j][k];
}
arr[i][j] = val/arr[i].length;
arr[i][j] = e(arr[i][j]);
}
}
f(arr);
}
// 用1-6直接的整数表示
function e(average){
if(average>=0 && average <= 42){
return 1;
}else if(average>42 && average <= 85){
return 2;
}else if(average>85 && average <= 127){
return 3;
}else if(average>127 && average <= 169){
return 4;
}else if(average>169 && average <= 211){
return 5;
}else{
return 6;
}
}
function f(arr){
console.log(arr);
console.time("time");
let count = 0 ;
for(let i = 0 ; i < arr.length ; i ++){
for(let j = 0 ; j < arr[i].length ; j++){
switch(arr[i][j]){
case 1: context.drawImage(imgArr[0],i*pieceW,j*pieceW,pieceW,pieceW);break;
case 2: context.drawImage(imgArr[1],i*pieceW,j*pieceW,pieceW,pieceW);break;
case 3: context.drawImage(imgArr[2],i*pieceW,j*pieceW,pieceW,pieceW);break;
case 4: context.drawImage(imgArr[3],i*pieceW,j*pieceW,pieceW,pieceW);break;
case 5: context.drawImage(imgArr[4],i*pieceW,j*pieceW,pieceW,pieceW);break;
case 6: context.drawImage(imgArr[5],i*pieceW,j*pieceW,pieceW,pieceW);break;
}
}
}
body.appendChild(canvas);
console.timeEnd("time");
}
原图
//切割小方块的边长
pieceW = 16;
pieceW = 12;
pieceW = 8;
注意:本文是使用js完成 ,在使用getImageData方法获取像素的时候可能会遇到图片源的问题 ,只需要将图片和js代码放在同一服务器下或者放在可以跨越访问的服务器上,我用了hbuilder的内置web服务器避免了图片源污染的问题 。