2012-05-13 3 views
7

Я работаю над проектом, который требует от меня выделить каждый цвет изображения CYMK и генерировать полутоновое изображение, которое будет напечатано на специальном полутоновом принтере. Используемый метод является аналогом шелкографии, поскольку процесс почти идентичен. Сделайте снимок и вырвите каждый цветной канал. Затем создайте экран для полутона. Каждый цветной экран должен иметь экран, сдвинутый на 15-45 (регулируемый) градус. Размер точек и LPI должен рассчитываться из пользовательских настраиваемых значений для достижения различных эффектов. Этот процесс, который, как мне сказали, используется при шелковом скрининге, но я не смог найти какую-либо информацию, которая объясняет полутонов CYMK. Я нахожу много для уменьшения до одного цвета и создания нового черно-белого изображения черно-белой печати.Halftone Images in Python

Я бы предположил, что мне нужно: 1. Разделить файл на его цветные каналы. 2. Создайте монохромное полутоновое изображение для этого канала. 3. Наклоните полученное полутоновое изображение на количество градусов * номер канала. Кто-нибудь знает, правильно ли это?

Кто-нибудь знает о существующем коде Python для этого? Или каких-либо хороших объяснений для этого процесса или алгоритмов?

+0

обновил мой код, надеюсь его полезно;) – fraxel

+0

Теперь связано: [Как полутонировать черно-белое изображение?] (Https://stackoverflow.com/questions/47828014/how-to-halftone-a-black- и-white-picture) – martineau

ответ

20

Раньше я запускал студию для трафаретной печати (она была довольно маленькой), и хотя я никогда не делал цветной разделительной печати, я достаточно хорошо знаком с принципами. Это, как я бы подойти к нему:

  1. разбить изображение на C, M, Y, K.
  2. Поворот отделенных друг от изображения 0, 15, 30 и 45 градусов соответственно.
  3. Возьмите половину тона каждого изображения (размер точки будет пропорционален интенсивности).
  4. Поверните назад каждое полутоновое изображение.

Теперь у вас есть цветные изображения. Как вы упомянули, шаг поворота уменьшает проблемы выравнивания точек (что бы все испортить), и такие вещи, как Moiré pattern effects, будут сведены к минимуму.

Это должно быть довольно легко кодировать, используя PIL.

Update 2:

Я написал несколько быстрый код, который будет делать это для вас, он также включает в себя GCA функцию (как описано ниже):

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

Это превратит это:

enter image description here

в это (размыть глаза и отойти от монитора тор):

enter image description here

Обратите внимание, что выборка изображения может быть пиксель за пикселем (таким образом, сохраняя разрешение исходного изображения, в окончательном изображении). Сделайте это, установив sample=1, и в этом случае вам нужно установить scale на большее число, чтобы было возможно количество точек. Это также приведет к большему размеру выходного изображения (размер оригинального изображения * шкала ** 2, так что следите!).

По умолчанию при обращении от RGB к CMYK канал K (черный канал) пуст. Нужен ли вам канал K или нет, зависит от вашего процесса печати. Существуют различные возможные причины, по которым вы можете это сделать: получить более черный цвет, чем перекрытие CMY, экономя чернила, улучшая время сушки, уменьшая количество чернил и т. Д. Во всяком случае, я также написал небольшую Grey component replacement функцию GCA, поэтому вы можете установить процент от K канал, который вы хотите заменить CMY, перекрывается с (я объясняю это немного дальше в комментариях к коду).

Вот несколько примеров для иллюстрации. Обработка letter F с изображения, с sample=1 и scale=8, поэтому довольно высокое разрешение.

В 4 CMYK каналов, с percentage=0, так пусто K канала:

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

сочетает в себе производить:

enter image description here

CMYK каналов, с percentage=100, такКанал. Вы можете увидеть канал циана полностью подавлен, и пурпурные и желтые каналы используют много меньше чернила, в черных полосах в нижней части изображения:

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

+1

аккуратное решение! –

+0

+1 Отлично. –

+0

@ user69333 - Круто, удачи в этом! Кстати, я fraxel (отличается от Андрея, который тоже ответил ..). Я был бы признателен, если бы вы могли «принять мой ответ», нажав на галочку, на том, как работает stackoverflow (мы оба получаем очки ... whoop), приветствуем. – fraxel

2

Мое решение также использует PIL, но полагается на внутренний метод сглаживания (Floyd-Steinberg), который поддерживается внутри страны. Тем не менее, создает артефакты, поэтому я рассматриваю возможность перезаписи его кода на 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 

неявный ОГП PIL применяется также может быть расширен с более общими один, но я попытался описать простое решение, в котором также разрешение и выборки игнорируются.