2012-05-13 12 views
7

Sto lavorando a un progetto che richiede di separare ciascun colore in un'immagine CYMK e generare un'immagine a mezzitoni che verrà stampata su una stampante a mezzitoni speciale. Il metodo utilizzato è analogo alla serigrafia in quanto il processo è quasi identico. Scatta una foto e scoppia ogni canale di colore. Quindi produrre uno schermo per il mezzo tono. Ogni schermo a colori deve avere lo schermo inclinato di 15-45 gradi (regolabili). Le dimensioni dei punti e LPI devono essere calcolate dai valori configurabili dall'utente per ottenere effetti diversi. Questo processo mi è stato detto che è utilizzato per la serigrafia ma non sono stato in grado di individuare alcuna informazione che spieghi i mezzi toni del CYMK. Trovo molto per ridurlo a un singolo colore e generare un nuovo stile di stampa in bianco e nero.Immagini mezzitoni in Python

Direi che ho bisogno di: 1. dividere il file nei suoi canali di colore. 2. generare un'immagine mezzitoni monocromatica per quel canale. 3. Inclinare l'immagine a mezzitoni risultante in base al numero di gradi * numero di canale. Qualcuno sa se questo è l'approccio corretto?

Qualcuno conosce qualche codice Python esistente per questo? O di qualche buona spiegazione per questo processo o algoritmi?

+0

aggiornato il mio codice, spero che sia utile;) – fraxel

+0

Ora collegato: [Come retinatura a mezzitoni di un'immagine in bianco e nero?] (Https://stackoverflow.com/questions/47828014/how-to-halftone-a-black- e-white-picture) – martineau

risposta

20

Avevo uno studio di serigrafia (era piuttosto piccolo) e, anche se non ho mai realizzato la stampa a colori, ho una certa familiarità con i principi. Questo è come mi avvicinarlo:

  1. dividere l'immagine in C, M, Y, K.
  2. Ruota ciascuna immagine separato da 0, 15, 30, e 45 gradi rispettivamente.
  3. Prendere il semitono di ogni immagine (la dimensione del punto sarà proporzionale all'intensità).
  4. Ruota indietro di ciascuna immagine mezzatinta.

Ora hai le tue immagini a colori separati. Come si menziona, la fase di rotazione riduce i problemi di allineamento dei punti (che potrebbero rovinare tutto) e cose come Moiré pattern effects saranno ragionevolmente ridotte al minimo.

Questo dovrebbe essere piuttosto facile da codificare utilizzando PIL.

Aggiornamento 2:

ho scritto un codice rapido che lo farà per voi, ma include anche una funzione GCA (descritto di seguito):

import Image, ImageDraw, ImageStat 

def gcr(im, percentage): 
    '''basic "Gray Component Replacement" function. Returns a CMYK image with 
     percentage gray component removed from the CMY channels and put in the 
     K channel, ie. for percentage=100, (41, 100, 255, 0) >> (0, 59, 214, 41)''' 
    cmyk_im = im.convert('CMYK') 
    if not percentage: 
     return cmyk_im 
    cmyk_im = cmyk_im.split() 
    cmyk = [] 
    for i in xrange(4): 
     cmyk.append(cmyk_im[i].load()) 
    for x in xrange(im.size[0]): 
     for y in xrange(im.size[1]): 
      gray = min(cmyk[0][x,y], cmyk[1][x,y], cmyk[2][x,y]) * percentage/100 
      for i in xrange(3): 
       cmyk[i][x,y] = cmyk[i][x,y] - gray 
      cmyk[3][x,y] = gray 
    return Image.merge('CMYK', cmyk_im) 

def halftone(im, cmyk, sample, scale): 
    '''Returns list of half-tone images for cmyk image. sample (pixels), 
     determines the sample box size from the original image. The maximum 
     output dot diameter is given by sample * scale (which is also the number 
     of possible dot sizes). So sample=1 will presevere the original image 
     resolution, but scale must be >1 to allow variation in dot size.''' 
    cmyk = cmyk.split() 
    dots = [] 
    angle = 0 
    for channel in cmyk: 
     channel = channel.rotate(angle, expand=1) 
     size = channel.size[0]*scale, channel.size[1]*scale 
     half_tone = Image.new('L', size) 
     draw = ImageDraw.Draw(half_tone) 
     for x in xrange(0, channel.size[0], sample): 
      for y in xrange(0, channel.size[1], sample): 
       box = channel.crop((x, y, x + sample, y + sample)) 
       stat = ImageStat.Stat(box) 
       diameter = (stat.mean[0]/255)**0.5 
       edge = 0.5*(1-diameter) 
       x_pos, y_pos = (x+edge)*scale, (y+edge)*scale 
       box_edge = sample*diameter*scale 
       draw.ellipse((x_pos, y_pos, x_pos + box_edge, y_pos + box_edge), fill=255) 
     half_tone = half_tone.rotate(-angle, expand=1) 
     width_half, height_half = half_tone.size 
     xx=(width_half-im.size[0]*scale)/2 
     yy=(height_half-im.size[1]*scale)/2 
     half_tone = half_tone.crop((xx, yy, xx + im.size[0]*scale, yy + im.size[1]*scale)) 
     dots.append(half_tone) 
     angle += 15 
    return dots 

im = Image.open("1_tree.jpg") 

cmyk = gcr(im, 0) 
dots = halftone(im, cmyk, 10, 1) 
im.show() 
new = Image.merge('CMYK', dots) 
new.show() 

Questo si trasformerà questo:

enter image description here

in questo (offuscare gli occhi e allontanarsi dal moni tor):

enter image description here

noti che il campionamento dell'immagine può essere pixel per pixel (preservando così la risoluzione dell'immagine originale, nell'immagine finale). A tale scopo, impostare sample=1, nel qual caso è necessario impostare scale su un numero maggiore in modo che vi siano un numero di dimensioni di punti possibili. Ciò determinerà anche una dimensione dell'immagine in uscita più grande (dimensione dell'immagine originale * scala ** 2, quindi attenzione!).

Per impostazione predefinita quando si converte da RGB a CMYK il canale K (canale nero) è vuoto. Se hai bisogno del canale K o meno dipende dal tuo processo di stampa. Ci sono varie possibili ragioni per cui potresti volerlo: ottenere un nero migliore rispetto alla sovrapposizione di CMY, risparmiando inchiostro, migliorando il tempo di asciugatura, riducendo il margine di inchiostro, ecc. Comunque ho anche scritto un po 'la funzione Grey component replacementGCA, così puoi impostare percentuale del canale K che si desidera sostituire con lo CMY (si spiego un po 'oltre nei commenti del codice).

Ecco un paio di esempi da illustrare. Elaborazione di letter F dall'immagine, con sample=1 e scale=8, quindi con una risoluzione piuttosto elevata.

I 4 CMYK canali, con percentage=0, così vuoto K channel:

enter image description hereenter image description hereenter image description hereenter image description here

combina per produrre:

enter image description here

CMYK canali, con percentage=100, così K canale utilizzato. È possibile vedere il canale ciano è completamente soppressa, ei canali magenta e giallo usare un inchiostro molto meno, nella banda nera nella parte inferiore dell'immagine:

enter image description hereenter image description hereenter image description hereenter image description hereenter image description here

+1

soluzione pulita! –

+0

+1 Eccezionale. –

+0

@ user69333 - Fantastico, buona fortuna! A proposito, sono fraxel (diverso da Andrew, che ha anche risposto ..). Sarei grato se tu potessi "accettare la mia risposta", facendo clic sul segno di spunta, come funziona lo stackoverflow (entrambi otteniamo punti ... whoop), evviva. – fraxel

2

La mia soluzione usa i PIL, ma si basa sul metodo di dithering interno (Floyd-Steinberg) supportato internamente. Crea artefatti, comunque, quindi sto pensando di riscrivere il suo codice C.

from PIL import Image 

    im = Image.open('tree.jpg')    # open RGB image 
    cmyk= im.convert('CMYK').split()   # RGB contone RGB to CMYK contone 
    c = cmyk[0].convert('1').convert('L') # and then halftone ('1') each plane 
    m = cmyk[1].convert('1').convert('L') # ...and back to ('L') mode 
    y = cmyk[2].convert('1').convert('L') 
    k = cmyk[3].convert('1').convert('L') 

    new_cmyk = Image.merge('CMYK',[c,m,y,k]) # put together all 4 planes 
    new_cmyk.save('tree-cmyk.jpg')   # and save to file 

Il GCR PIL implicito permangono possono anche essere espansa con una più generica, ma ho cercato di descrivere una soluzione semplice, dove anche la risoluzione e campionamento vengono ignorati.