2012-05-13 30 views
7

Estoy trabajando en un proyecto que me obliga a separar cada color en una imagen CYMK y generar una imagen de medios tonos que se imprimirá en una impresora de medios tonos especial. El método utilizado es análogo al cribado de seda porque el proceso es casi idéntico. Toma una foto y divide cada canal de color. Luego, genere una pantalla para el medio tono. Cada pantalla de color debe tener su pantalla sesgada por 15-45 (grados ajustables). El tamaño del punto y el LPI se deben calcular a partir de valores configurables por el usuario para lograr diferentes efectos. Este proceso, según me han dicho, se usa en la detección de seda, pero no he podido encontrar ninguna información que explique el semitono de CYMK. Encuentro mucho para reducir a un solo color y generar una nueva imagen de medios tonos en blanco y negro.Imágenes de medios tonos en Python

Supongo que necesito: 1. dividir el archivo en sus canales de color. 2. genera una imagen monocromática de semitonos para ese canal. 3. Incline la imagen de semitonos resultante por el número de grados * número de canal. ¿Alguien sabe si este es el enfoque correcto?

¿Alguien sabe de algún código python existente para esto? ¿O de alguna buena explicación para este proceso o algoritmos?

+0

actualicé mi código, espero que sea útil;) – fraxel

+0

Ahora vinculado: [¿Cómo semitono una imagen en blanco y negro?] (Https://stackoverflow.com/questions/47828014/how-to-halftone-a-black- and-white-picture) – martineau

Respuesta

20

Solía ​​dirigir un estudio de serigrafía (era bastante pequeño), y aunque nunca he hecho la impresión de separación de colores, estoy razonablemente familiarizado con los principios. Así es como yo lo enfoque:

  1. dividir la imagen en C, M, Y, K.
  2. Girar cada imagen separados por 0, 15, 30, y 45 grados, respectivamente.
  3. Tome el medio tono de cada imagen (el tamaño del punto será proporcional a la intensidad).
  4. Gire hacia atrás cada imagen de medio tono.

Ahora tiene sus imágenes separadas por color. Como mencionas, el paso de rotación reduce los problemas de alineación de puntos (lo que ensuciaría todo) y cosas como Moiré pattern effects se minimizarán razonablemente.

Esto debería ser bastante fácil de codificar usando PIL.

Actualización 2:

escribí algo de código rápida que va a hacer esto para usted, sino que también incluye una función GCA (descrito a continuación):

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() 

Esto a su vez esto:

enter image description here

en esto (desdibuja los ojos y aléjate de la moni tor):

enter image description here

Nota que el muestreo de imagen puede ser píxel por píxel (preservando así la resolución de la imagen original, en la imagen final). Para ello, establezca sample=1, en cuyo caso debe establecer scale en un número mayor para que haya varios tamaños de puntos posibles. Esto también dará como resultado un tamaño de imagen de salida más grande (tamaño de imagen original * escala ** 2, ¡así que tenga cuidado!).

De forma predeterminada, al convertir de RGB a CMYK, el canal K (el canal negro) está vacío. Si necesita el canal K o no, depende de su proceso de impresión. Hay varias razones posibles por las que podría desearlo: obtener un negro mejor que la superposición de CMY, ahorrar tinta, mejorar el tiempo de secado, reducir el sangrado de tinta, etc. De todos modos, también escribí una pequeña función Grey component replacement , para que pueda configurar el porcentaje del canal K con el que desea reemplazar CMY se superponen (lo explico un poco más en los comentarios del código).

Aquí hay un par de ejemplos para ilustrar. Procesando el letter F de la imagen, con sample=1 y scale=8, con una resolución bastante alta.

Los 4 CMYK canales, con percentage=0, tan vacío K de canal:

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

se combina para producir:

enter image description here

CMYK canales, con percentage=100, por lo K canal es usado. Se puede ver el canal cian está totalmente suprimida, y los canales de magenta y amarillo usar mucha menos tinta, en la banda de negro en la parte inferior de la imagen:

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

+1

solución limpia! –

+0

+1 Sobresaliente. –

+0

@ user69333 - ¡Qué buena suerte con eso! Por cierto, soy fraxel (diferente de Andrew, quien también respondió ...). Le agradecería si pudiera 'aceptar mi respuesta', haciendo clic en el tic, es la forma en que funciona stackoverflow (ambos obtenemos puntos ... whoop), aplausos. – fraxel

2

Mi solución utiliza también PIL, pero se basa internamente en el método de difuminado interno (Floyd-Steinberg). Crea artefactos, por lo que estoy considerando volver a escribir su código 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 

El PIL GCR implícita se aplica también puede ser ampliado con una más genérica, pero he tratado de describir una solución simple, donde se tienen en cuenta también la resolución y muestreo.

Cuestiones relacionadas