文章24
标签14
分类5

图片的主要颜色提取——中位切分算法的应用


因为这个工具直接放在 Typecho 的文章会报错运行不了,所以只能另外开一个页面来放这个工具了 工具地址
另外因为有 canvas 的跨域问题,所以如果图片是 Vinking.top 以外的域名会无法输出。



之前在取色网站取色的时候,看见网站可以获取背景图片的主要颜色,一直想弄清楚是怎么做到的,经过一晚上的探索,终于弄清楚了其中的原理。

本着能用就行的原则,以及网上的大佬,写了一个可以获取图片的主要颜色的工具,除去一些奇奇怪怪的问题懒得解决 其实是不会 ,还是可以正常的运行。与在图像处理中降低图像位元深度的算法相同,它们的核心原理都是“ 中位切分法 ”。

所谓的“ 中位切分法 ”其实很简单,首先建立一个三维 RGB 空间,把图片的所有像素颜色都放到这个 RGB 空间里,然后划出一个包含了这张图片所有像素颜色的三维 RGB 区域,第三步取这个 RGB 区域最长的边作中位切割,使得切割之后的两个新的 RGB 区域包含相同的像素点,然后反复进行第三步,直到切出长方体数量等于图片主要颜色数为止,再取小长方体区域的像素平均值就可以作为这张图片的主要颜色啦~ 至于为什么要切割,切割是为了尽量让相似的颜色均匀地分布在长方体内,到最后取平均值的时候就可以用一个平均颜色来代表一整个区域的颜色了。

是不是很简单~是不是!是不是!

下面上代码:

代码参考 CSDN 的 业余_玩家大佬 ,代码出处:https://blog.csdn.net/qq_28401309/article/details/104209199

//HTML
<img src="#" alt="" id="myimage">
<canvas id="mycanvas"></canvas>
<div id="imagecolor" style="display: flex;width: 100%;"></div>

//JavaScript
var qulity = 100,count = 0;
window.onload = function () {
var img = document.getElementById("myimage");
var image = new Image();
image.src = img.src;
var canvas = document.getElementById("mycanvas");
var ctx = canvas.getContext('2d');//指定二维绘图
ctx.drawImage(img,0,0,image.width,image.height,0,0,300,150);//在画布上绘制图像
var data = ctx.getImageData(0, 0,image.width,image.height).data;//复制画布上指定矩形的像素数据
var rgbArray=new Array();
for(var i=0;i<data.length;i+=4){//获取到的值有4个信息,分别是red,green,blue,alpha
   var rdata=data[i];
    var gdata=data[i+1];
    var bdata=data[i+2];
    var adata=data[i+3];
    if(adata>125){
        rgbArray.push([rdata,gdata,bdata,adata]);//向数组添加元素,并返回新的长度
    }
}
console.log(rgbArray);//控制台输出像素数据
GetColor(rgbArray);
console.log(count);
}

//中位切分法开始
function GetColor(cube){
    var maxr=cube[0][0],minr=cube[0][0],maxg=cube[0][1],ming=cube[0][1],maxb=cube[0][2],minb=cube[0][2];
    for(var i=0;i<cube.length;i++)
    {
        if(cube[i][0]>maxr){
            maxr=cube[i][0];
        }
        if(cube[i][0]<minr){
            minr=cube[i][0];
        }
        if(cube[i][1]>maxg){
            maxg=cube[i][1];
        }
        if(cube[i][1]<ming){
            ming=cube[i][1];
        }
        if(cube[i][2]>maxb){
            maxb=cube[i][2];
        }
        if(cube[i][2]<minb){
            minb=cube[i][2];
        }
    }

    if((maxr-minr)<qulity&&(maxg-ming)<qulity&&(maxb-minb)<qulity){
    //若得到的长方体少于100个像素点时停止切割
        var r=0,g=0,b=0;
        for(var i=0;i<cube.length;i++){
        //将块里的所有像素数值加起来
            r+=cube[i][0];
            g+=cube[i][1];
            b+=cube[i][2];
        }
        var divcolor=document.createElement("div");
        divcolor.style.backgroundColor="rgba("+r/(cube.length)+","+g/(cube.length)+","+b/(cube.length)+")";
        //输出块里所有像素的平均值
        divcolor.style.width="70px";
        divcolor.style.height="70px";
        divcolor.style.borderRadius="70px";
        divcolor.style.margin="10px";
        var html=document.getElementById("imagecolor");
        html.appendChild(divcolor);
    }else{
        var maxrgb=0;
        var rgbindex=0;
        var rgbmiddle=0;
        //中位切分
        if((maxr-minr)>maxrgb)
        {
            maxrgb=(maxr-minr);
            rgbmiddle=(maxr+minr)/2
            rgbindex=0;
        }
        if((maxg-ming)>maxrgb)
        {
            maxrgb=(maxg-ming);
            rgbmiddle=(maxg+ming)/2;
            rgbindex=1;
        }
        if((maxb-minb)>maxrgb)
        {
            maxrgb=(maxb-minb);
            rgbmiddle=(maxb+minb)/2;
            rgbindex=2;
        }
        
        //排序
        cube.sort(function(x,y){
            return x[rgbindex]-y[rgbindex];
        });
        var cubea=new Array();
        var cubeb=new Array();
        for(var i=0;i<cube.length;i++){
            if(cube[i][rgbindex]<rgbmiddle){
                cubea.push(cube[i]);
            }else{
                cubeb.push(cube[i]);
            }
        }
        GetColor(cubeb);
        GetColor(cubea);
    }     
}}

这方法真的是牛批!


    

    已经有 0 个评论啦

    评论已关闭

    '