Ableton Certified Trainer, Music Technologist, Creative Coder, Educator

Una palette di colori da un’immagine

Nelle ultime settimane mi è capitato di fare diversi lavori di grafica – che non è propriamente il campo in cui sono più ferrato – e mi sono sempre trovato in crisi nella scelta della palette di colori più adatta a quello che stavo facendo.

Mentre ero alla ricerca della giusta combinazioni di colori su siti come Coolors e Adobe Color mi è tornata in mente una frase di Joshua Davis detta in uno dei suoi video (non cito testualmente, vado a memoria): le palette di colori che funzionano meglio sono quelle legate a immagini a cui siamo abituati, come un tramonto sul mare oppure le gradazioni di verde in un bosco in montagna. Ecco perché estrarre i colori da una foto è uno dei modi migliori per trovare delle combinazioni che funzionano.

Da qui l’illuminazione: perché non creare uno sketch in Processing per aiutarmi?

Leggere i colori da un’immagine

Partiamo riciclando il codice visto nell’ultimo post: Modificare la dimensione della finestra in base all’immagine caricata. Creiamo un oggetto di tipo PImage e facciamo in mondo che la finestra si ridimensioni automaticamente al caricamento del file. Nel codice sotto riportato noterete un +50 pixel nell’altezza che servirà come spazio per rappresentare i colori della palette in tempo reale.

Per questo sketch ho deciso di utilizzare l’immagine di un prato fiorito:
Leggere i colori da un'immagine con Processing

Ricordatevi di inserire l’immagine nella cartella /data come spiegato qui.

/*
 * Una palette di colori da un'immagine
 * Federico Pepe, 28.08.2017
 * http://blog.federicopepe.com/processing
*/

PImage img;

void setup() {
  size(1, 1);
  surface.setResizable(true);
  img = loadImage("flowers.jpg");
  surface.setSize(img.width, img.height+50); 
}

void draw() {
}

Creiamo due variabili di tipo integer: la prima, numPoints indica il numero di colori di cui sarà composta la nostra palette. Ho deciso di chiamarla points perché prenderemo i dati colori da dei punti nell’immagine. La seconda pointX la utilizzeremo come riferimento per calcolare il valore di x dei punti scelti che, ai fini di questo esempio, saranno equidistanti.

Aggiungiamo un po’ di codice nel ciclo draw(): mostriamo l’immagine come sfondo e carichiamo l’array di pixel. Come anticipato, assegniamo a pointX il valore della larghezza della foto caricata diviso il numero di punti.

Utilizziamo il classico ciclo for per trovare i colori dei punti. Creo un minimo di interfaccia per aiutarmi nel lavoro: intorno ai punti di riferimento disegno un cerchio.

/*
 * Una palette di colori da un'immagine
 * Federico Pepe, 28.08.2017
 * http://blog.federicopepe.com/processing
*/

PImage img;
// Numero di "punti" della nostra palette
int numPoints = 5;
// Valore x di riferimento
int pointX;

void setup() {
  size(1, 1);
  surface.setResizable(true);
  img = loadImage("flowers.jpg");
  surface.setSize(img.width, img.height+50); 
}

void draw() {
  image(img, 0, 0);
  img.loadPixels();
  pointX = img.width / numPoints;
  
  for(int i = 0; i <= numPoints-1; i++) {
    int x = pointX*i;
    int y = mouseY;
    
    if(mouseY <= 0 || mouseY >= img.height) {
      y = img.height/2;
    }
    stroke(255);
    noFill();
    ellipse(x, y, 25, 25);
    color c = img.pixels[x + y * img.width];
    println(c);
  }
  
}

Avendo deciso di lasciare il valore di y variabile e dipendente dalla posizione y del mouse, ho deciso di inserire un controllo condizionale per verificare di non uscire dall’immagine stessa causando un errore Array out of bounds sull’array di pixel.

Nella console vengono mostrati i valori di c ma non sono utilizzabili in alcun programma di grafica perché non sono i classici valori HEX, RGB o HSB.

Mostriamo la palette di colori

Sfrutto i 50 pixel di margine di abbondanza rispetto alla foto per mostrare in tempo reale i colori dei pixel di riferimento. Farlo è molto semplice: creo dei rettangoli con, come fill, il colore estratto in precedenza. Sfrutto questo passaggio per centrare i punti di analisi rispetto alla larghezza della finestra e ai rettangoli in basso.

Palette di colori da immagine

/*
 * Una palette di colori da un'immagine
 * Federico Pepe, 28.08.2017
 * http://blog.federicopepe.com/processing
 */

PImage img;
// Numero di "punti" della nostra palette
int numPoints = 5;
// Valore x di riferimento
int pointX;

void setup() {
  size(1, 1);
  surface.setResizable(true);
  img = loadImage("flowers.jpg");
  surface.setSize(img.width, img.height+50);
}

void draw() {
  image(img, 0, 0);
  img.loadPixels();
  pointX = img.width / numPoints;

  for (int i = 0; i <= numPoints-1; i++) {
    int x = pointX/2+pointX*i;
    int y = mouseY;

    if (mouseY <= 0 || mouseY >= img.height) {
      y = img.height/2;
    }

    stroke(255);
    noFill();
    ellipse(x, y, 25, 25);

    color c = img.pixels[x + y * img.width];

    fill(c);
    rect(pointX*i, img.height, pointX, 50);
  }
}

Otteniamo i valori HEX dei colori

A questo punto il programma funziona nel modo corretto, non ci resta che fare dei piccoli miglioramenti all’interfaccia: grazie alla funzione hex(value, digits) possiamo ottenere il valore esadecimale del colore. Come indicato nel reference, il numero viene rappresentato con un massimo di 8 caratteri ma possiamo ottenerne 6, come siamo abituati, aggiungendo indicando il secondo parametro alla funzione.

Palette colori GIF

Ecco qui il codice:

/*
 * Una palette di colori da un'immagine
 * Federico Pepe, 28.08.2017
 * http://blog.federicopepe.com/processing
 */

PImage img;
// Numero di "punti" della nostra palette
int numPoints = 5;
// Valore x di riferimento
int pointX;

void setup() {
  size(1, 1);
  surface.setResizable(true);
  img = loadImage("flowers.jpg");
  surface.setSize(img.width, img.height+50);
}

void draw() {
  image(img, 0, 0);
  img.loadPixels();
  pointX = img.width / numPoints;

  for (int i = 0; i <= numPoints-1; i++) {
    int x = pointX/2+pointX*i;
    int y = mouseY;

    if (mouseY <= 0 || mouseY >= img.height) {
      y = img.height/2;
    }

    stroke(255);
    noFill();
    ellipse(x, y, 25, 25);

    color c = img.pixels[x + y * img.width];

    fill(c);
    rect(pointX*i, img.height, pointX, 50);
    
    fill(255);
    textAlign(CENTER);
    text("#"+hex(c,6), x, img.height+30);
    
  }
}

Salvare la palette di colori in un file di testo

Siamo quasi alla fine del nostro lavoro: l’unico passaggio che ci manca è salvare la palette di colori in un file .txt in modo da poterli usare a nostro piacimento anche in programmi esterni.

Aggiungiamo qualche riga di codice: creiamo una nuova variabile di tipo StringList il cui contenuto verrà inizializzato a ogni ciclo di draw con la funzione .clear();

Alla pressione del tasto del mouse, verrà salvato il file chiamato palette.txt. La conversione della StringList in array è necessaria perché la funzione saveStrings si aspetta come secondo parametro un array e non una lista.

/*
 * Una palette di colori da un'immagine
 * Federico Pepe, 28.08.2017
 * http://blog.federicopepe.com/processing
 */

PImage img;
// Numero di "punti" della nostra palette
int numPoints = 5;
// Valore x di riferimento
int pointX;
// Salviamo i valori HEX in una lista di stringhe
StringList palette = new StringList();

void setup() {
  size(1, 1);
  surface.setResizable(true);
  img = loadImage("flowers.jpg");
  surface.setSize(img.width, img.height+50);
}

void draw() {
  image(img, 0, 0);
  
  img.loadPixels();
  pointX = img.width / numPoints;
  
  palette.clear();
  
  for (int i = 0; i <= numPoints-1; i++) {
    int x = pointX/2+pointX*i;
    int y = mouseY;

    if (mouseY <= 0 || mouseY >= img.height) {
      y = img.height/2;
    }

    stroke(255);
    noFill();
    ellipse(x, y, 25, 25);

    color c = img.pixels[x + y * img.width];

    fill(c);
    rect(pointX*i, img.height, pointX, 50);
    
    fill(255);
    textAlign(CENTER);
    text("#"+hex(c,6), x, img.height+30);
    // Aggiungiamo il colore come stringa all'array
    palette.append("#"+hex(c,6));
    
  }
}

void mousePressed() {
  saveStrings("palette.txt", palette.array());
}

5 responses to “Una palette di colori da un’immagine”

  1. Nick avatar
    Nick

    Ciao Federico ti ringrazio per l’utile articolo. Come potrei fare invece per leggere il colore esadecimale del singolo pixel su cui si trova il mouse e facendo colorare un singolo rettangolo con quel colore anziché averne 5 come invece accade nell’esempio di questo articolo? Grazie in anticipo!

    1. Federico avatar

      Ciao Nick, è sufficiente modificare il codice utilizzando anche la variabile mouseX quando si dichiara la posizione x e y

  2. Nick avatar
    Nick

    Innanzitutto grazie per la disponibilità. Potresti essere più specifico Federico? Sono ancora alle prime armi purtroppo…

    PImage img;
    int numPoints = 5;
    int pointX;

    void setup() {
    size(1, 1);
    surface.setResizable(true);
    img = loadImage(“flowers.jpg”);
    surface.setSize(img.width, img.height+50);
    }

    void draw() {
    image(img, 0, 0);
    img.loadPixels();
    pointX = img.width / numPoints;

    for (int i = 0; i <= numPoints-1; i++) {
    int x = pointX/2+pointX*i;
    int y = mouseY;

    if (mouseY = img.height) {
    y = img.height/2;
    }

    stroke(255);
    noFill();
    ellipse(x, y, 25, 25);

    color c = img.pixels[x + y * img.width];

    fill(c);
    rect(pointX*i, img.height, pointX, 50);

    fill(255);
    textAlign(CENTER);
    text(“#”+hex(c,6), x, img.height+30);

    }
    }

    1. Federico avatar

      In questo momento sono in vacanza senza computer quindi non ho modo di provare il codice. Comunque dovrebbe essere sufficiente mettere int x = mouseX

  3. Nick avatar
    Nick

    Grazie mille Federico sei stato gentilissimo.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.