Get colors from the image

Asked

Viewed 5,355 times

26

There is a possibility (with plugins or not) to catch the [main] colors or the predominant colors, similar to Adobe Kuler, image?

Example

I have this image:

inserir a descrição da imagem aqui

And I wanted to take her main colors, which would be Blue

  • 2

    Doing on the arm is not something trivial, you should take a look at this Javascript plugin: Color Thief

  • To do this "on the wrist" you would have to read all the pixels of the image, capture the code RGB or Hex (Potato or Potato IMO), feed an array and then select the major occurrences. Nothing trivial. It is worth academic study, of course. There is a good case study (in C#, I don’t know about the possibility of doing it in PHP) here: http://www.c-sharpcorner.com/UploadFile/0f68f2/color-detecting-in-an-image-in-C-Sharp/

  • Most image processing libraries for PHP (Cairo, GD, Exif, Gmagix, Imagemagick) have a function to pick up the color of a single pixel. You can pass a picture like input and then scroll through all your pixels to assemble an array of colors. After that, it would only be a matter of setting up a frequency table to find the most prevalent color(s) (s) in the image.

  • @Leonardodiego needs to be in JS?

  • @Andrecalil You don’t need!

  • @Leonardodiego A solution in C# interest you? :)

  • @Andrecalil not :\

Show 2 more comments

2 answers

21


The following code mounts an object containing the histogram and recovers the most common color using an element canvas invisible:

//carrega uma imagem
var img = new Image();
img.src = ...

//cria um canvas invisível
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
var context = canvas.getContext('2d');

//desenha a imagem no canvas
context.drawImage(img, 0, 0);

//recupera vetor de cores
var map = context.getImageData(0, 0, img.width, img.height).data;

//monta histograma
var hex, r,g,b; //,alpha;
var histograma = {};
for (var i = 0, len = map.length; i < len; i += 4) {

    //recupera componentes de um ponto
    r = arredonda(map[i]);
    g = arredonda(map[i+1]);
    b = arredonda(map[i+2]);
    //alpha = map[i+2]; //ignora canal alpha

    //valor em hexadecimal
    hex = rgbToHex(r, g, b);

    //adiciona no histograma ou incrementa se já existir
    if (histograma[hex] === undefined) {
        histograma[hex] = 1;
    } else {
        histograma[hex]++;
    }
}

//recupera cor mais comum
var corMaisComum = null;
var frequenciaCorMaisComum = 0;
for (var cor in histograma) {
    if (frequenciaCorMaisComum < histograma[cor]) {
        corMaisComum = cor;
        frequenciaCorMaisComum = histograma[cor];
    }
}

console.log(corMaisComum);

The histogram is nothing more than a type of map where the key is the color in hexadecimal notation and the value is the frequency with which it occurs in the image.

In this algorithm, I used the function arredonda by recovering the color to arredondar it to the nearest multiple of 5. This way, small variations in the color will not disturb the final result.

Note that with p histogram we can not only get the most common color, but also the first N most common colors. For this we would only have to create a vector with the colors ordered by the frequency.

The previous code can be seen performance on the website jsdo., but I will post the same complete if it becomes inaccessible one day:

//"arredonda" o número para o múltiplo de 5 mais próximo
//isso adiciona uma certa tolerância para os tons próximos
function arredonda(v) {
    return 5 * (Math.round(v / 5));
}

function componentToHex(c) {
    var hex = c.toString(16);
    return hex.length == 1 ? "0" + hex : hex;
}

function rgbToHex(r, g, b) {
    return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
}

//carrega uma imagem
var img = new Image();
img.src = 'http://jsrun.it/assets/8/O/3/U/8O3Ux.jpg';
img.onload = function() {

    $(document.body).append(img);

    //cria um canvas invisível
    var canvas = document.createElement('canvas');
    canvas.width = img.width;
    canvas.height = img.height;
    var context = canvas.getContext('2d');

    //desenha a imagem no canvas
    context.drawImage(img, 0, 0);

    //recupera vetor de cores
    var map = context.getImageData(0, 0, img.width, img.height).data;

    var hex, r,g,b; //,alpha;
    var histograma = {};
    for (var i = 0, len = map.length; i < len; i += 4) {

        //recupera componentes de um ponto
        r = arredonda(map[i]);
        g = arredonda(map[i+1]);
        b = arredonda(map[i+2]);
        //alpha = map[i+2]; //ignora canal alpha

        //valor em hexadecimal
        hex = rgbToHex(r, g, b);

        //adiciona no histograma ou incrementa se já existir
        if (histograma[hex] === undefined) {
            histograma[hex] = 1;
        } else {
            histograma[hex]++;
        }
    }

    //recupera cor mais comum
    var corMaisComum = null;
    var frequenciaCorMaisComum = 0;
    for (var cor in histograma) {
        if (frequenciaCorMaisComum < histograma[cor]) {
            corMaisComum = cor;
            frequenciaCorMaisComum = histograma[cor];
        }
    }

    console.log(corMaisComum);

    //adiciona um div como exemplo
    $(document.body).append(
        $('<div>').css({
            'background-color': corMaisComum,
            'width': '200px',
            'height': '200px',
            'border': '1px solid #000'
        })
    );

};

The visual result is as in the image below:

resultado com a cor retornada

  • 3

    In my view, this is the answer I believe to be correct :)

  • :What did you do, man?

  • @Pauloroberto Yes, but it’s not much different from your answer, unless instead of averaging I count the number of times a color appears.

6

You can use the technology Canvas which is contained in the browsers that support HTML5(currently most), and with it you can make a Javascript function that takes as a parameter your image and checks 5 by 5 pixels which color, and checks the entire image, and then the predominant color is set via R,G, B(red,green,blue) at the bottom of your page.

HTML Exemplar would be:

<span> Background é setado para a cor predominante desta imagem: </span>
<img id="i" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYI
DAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkF
BQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU
FBQUFBT/wAARCABOAE4DASIAAhEBAxEB/8QAHQAAAQQDAQEAAAAAAAAAAAAAAAEHCAkC
BQYEA//EADkQAAEDAwIFAgQDBAsAAAAAAAECAwQABREGBwgSITFBUWETInGhCYKRFFKB
wRUWFyRCYmV1kqOx/8QAGwEAAgIDAQAAAAAAAAAAAAAABQYEBwACAwj/xAAxEQABAgQC
CAQGAwAAAAAAAAABAgMABAUREiEGEzFBUYGRwRQy8PEiQmFxseFSodH/2gAMAwEAAhED
EQA/AGhyKMiscUV6IjzDGWRRkVjS1kZC5FGRUr+HPgpibn6Kj6p1VdptvhTuYwodu5Eu
qQCU/EWtaVAZIOEhPbBz1xXfak/DnsDsdZsOrbnEeAykXFhuQk+3yfDI+9LrtekGXSyt
eYyORtDOzo5Un2UvoRkRcZgG0QSyKM06m7PDPrfaBLkq5QU3GzoPW524lxpI/wA4wFI+
pGPc01XejTD7UyjWMqCh9IAzEs9Kr1b6SlX1hcijIpMUlSIjRlismmlvOJbbQpxxZCUo
SMlRPYAeaSpHcDG2DWut2F3qcyHrfpxpMsJUMpVJUSGQfpha/qgVDm5lMmwt9exI9hzM
TpKUVPTCJZG1R9zyEPpsFwS6bsmlGLluBbU3i/y0BxUJ1xQZhJI6IwkjmX+8TkA9B2yW
B4uNk7Btjc4F20w2qHbZrqo7sFTilpacA5klBUScEBWQT0I6d8CwzV98TaLcs8wCiKrE
4ht417q6qMeIof0FbnViOod5Cz0U79OmE+2T5wK8o03Pz1Q1pWSn5huA3C34iza9JU2n
UzVBACtiTb4id5J/PtFhnDOMbBaGP+mN/wA67WZqeDBmsxXpDTbzxKWm1rAUsgZISPPT
0riuGnP9gGh/9rb/AJ1Gbjzlut23Tq23FtuNXJS0LQohSVBtWCCOxpfEt4yoqYvbEpWf
WGUzfgaWmZtfClOXIRNabBZusRaVIS4haSkpUMgg9wRVfvFlw0taDde1ZpiN8KzLX/fo
DY+WKonAcQPCCTgj/CSMdD8rrcGHE5M1lKGhdWSjJu6Wyu23B0/PJSkZU04fKwASFeQD
nqMmSWv9Pxr3ZJUaUwmRGfaU080sZStChgg/UGpLa5qgTuFXMblD1s4GIrrcppJIYk8j
vSr1t4iKesZoxXQbgaSc0Jre9afcKlCDIUhtau6mj8zaj7lBSa0FXE04l1CXEbCLxRzr
SmXFNrFiDY8oSp//AIdVsbZ2x1LcEgfGkXj4Cj55W2W1D7uq/Wq/81PD8ObUTb2j9XWL
nAejT25vKT1KXW+TI/iz9xS3pIFGnLtxF+sNOipSKojFwNun+Q4HFvf5Fj2w1JJYWUOC
IWkqT3SXCG8j3HNmqzkJCUADwKtT4itCu652/vtrjp5pEqIsM57fEA5kZ/MBVV621srU
26hTbqCUrQsYKSOhBHg0L0TUjUupHmv/AFbLvBfTNK/ENKPlset8+0Wm8MWo4Ezh30g8
xIQ4mPC/ZnAD1Q4hRSpJHg5H6EHzUYuOi+xpjFghpcSZKpbj4bz15AjlJ/VQ+/pUc9H7
maq0Al9Gnr7LtbUg5dZaUFNrPbJQoFOffGa098vty1Nc3bjdpz9xnOYCn5C+ZWPAHoB6
DpXeXoC2aj4srGG5IG/P3iPNaSNv0sSQQQuwBO7K2fHO0bLb7UT+kddafvUVakPwJ7Mh
JHnlWCR9CMg/Wrg7yjntzwPpVS+xmhZG4+7GmrGw2pxt2Yh2SoDohhB53FH8oOPcgeat
i1FKEa1PKUcZFCNLFILzSR5rG/23d4N6FpWGHlHyki33tn2is/jDgtw95PiIABlW1l5f
uoLcR/4gUyeKdzirviL1vJNQhQUIMRmKSPX5nCP+ymjzTpSAoSDIVwEIVbKTUnyn+R/c
Y07vC3u6jZ3diBcZjhbss5Jg3A+ENLIw5+RQSo+cBQ800mKMUQmGETLSmXNihaBstMLl
Xkvt+ZJuIukksM3SIlSVJdbWkKQtJyFA9iD5FQ64kuDeXqe6StT6LQ0m5vErl2xaghMl
Xlbaj0Ss+QcA98g5zyHC5xg/1EhxdI60eccsbeG4NzwVqiJ8NuDuWx4I6p7dRjlnNatT
22+wGJsKUxNiPp52pEdwLQtPqFDoRVQuNztAmsSeR3KHrdtEXa27IaSSmFXMfMk+t+wx
ULqDQOpdKSlRrzYLlbHknHLJirQD9CRgj3HSt7oTYzXe5E1tix6anvtrIBlvMlmOgeqn
VYT/AAzn0Bq25M2OB0WAK+Mi9RIySVODpRpWlrxRZLQxcbm3T9wBToWwF3U8SnhYX6/q
Gi4bOG23bC2V6RIebuWp5yAmZPSnCG0d/hNZ6hOepJ6qIBOMAD1b7boQNFaYnz5ToDEV
sq5QcFxXZKB7k4A+tfbdHfCy6Hs7su4z2oLABCeY5W4f3UJHVR9hVeG9O9Fx3fvYWpK4
dkjrKo0NR+ZR7fEcx0KseOwBwO5JFSMjM1uZ1z18N8z2HrKDNQqEpQJQMMWxW+FPc+s4
4S8XaTqC7zrpNVzy5r65DpHbmUc4HsOwrx1lijFW+lIQkJTsEUitRWoqUbkwUtJR0raN
IK6bRm5WqtvHi5py+zLUFHmUy0vmZWfVTaspJ9yK5kdqK5uNodTgcAI4HOOrbq2VBbai
DxGUP1B419x4jIbeTZpygMfEfirSo/8ABxI+1aq/8XO498aU2iZBtQV0KoMXr+rhXTNU
ULFIkArFqU9ILGt1Epwl9Vvv32x7LzebhqKeqddZ8m5TFd3pTpcVj0BPYewrx0UUWSlK
BhSLCA6lqWSpRuTC0Uho6Gto0j//2Q=="/>

Obs: I converted your image into :)

And the function that makes the magic would be this:

    var rgb = getAverageRGB(document.getElementById('i'));
    document.body.style.backgroundColor = 'rgb('+rgb.r+','+rgb.g+','+rgb.b+')';

function getAverageRGB(imgEl) {

    var blockSize = 5, //checa a cor à cada 5 pixels
        defaultRGB = {r:0,g:0,b:0}, // para browsers com incompatibilidade
        canvas = document.createElement('canvas'),
        context = canvas.getContext && canvas.getContext('2d'),
        data, width, height,
        i = -4,
        length,
        rgb = {r:0,g:0,b:0},
        count = 0; //zera o contador

    if (!context) {
        return defaultRGB;
    }

    height = canvas.height = imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height;
    width = canvas.width = imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width;

    context.drawImage(imgEl, 0, 0); //desenha a imagem cria o canvas

    try {
        data = context.getImageData(0, 0, width, height);
    } catch(e) {
        /* gera um erro de segurança, se a imagem for de dominio diferente */alert('x');
        return defaultRGB;//retorna  a cor padrão
    }

    length = data.data.length; //tamanho do array dos dados da imagem

    while ( (i += blockSize * 4) < length ) {
        ++count; //incrementa o contador previamente zerado
        rgb.r += data.data[i];
        rgb.g += data.data[i+1];
        rgb.b += data.data[i+2];
    }

    // ~~ usado para arrendondar valores para baixo
    rgb.r = ~~(rgb.r/count);
    rgb.g = ~~(rgb.g/count);
    rgb.b = ~~(rgb.b/count);

    return rgb;

}

Example running on Jsfiddle with your image.

Important:

The function is not my own, here is the Reference of the response in the SOEN.

  • From the result you posted, I think the function takes the average color, not the predominant, right?

  • Do you think why? explain.

  • To convert the image to Base64 in php would be using the function "base64_encode", right?

  • Yes, the base64_encode to convert and the base64_decode to disconnect :)

  • 1

    @Pauloroberto First you add up all the values of r, g and b then divide each of them by the pixel count. That’s the average. The user who posted the question wants the most prevalent color, which within a frequency table would be the color that has the highest count. The problem is if the image in question is, for example, a low-quality JPEG, where there may be several colors nearby but none very prevalent (say, greater than 20%). Now for GIF or PNG images, there would be no problem.

  • But wouldn’t the average be more likely to be the prevailing color?? test if interested, with other images, if you get results let me know we can improve this function together :)

  • 1

    So, in my understanding, the predominant color is the one that’s the most frequent. It may be that for the author, the concept is the one you explained. First it’s interesting to know what he wants so we propose a change in the algorithm ;)

  • My dear @Leonardodiego do you want the color that appears most frequently in the image? or the average of the colors present in the image? depending on this answer we will change the algorithm :)

Show 3 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.