Полутоновые изображения в Python

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

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

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

Ответы на вопрос(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

Неявное применение GCR PIL также может быть расширено более общим, но я попытался описать простое решение, в котором также игнорируются разрешение и выборка.

Решение Вопроса

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

  1. Split the image into C, M, Y, K.
  2. Rotate each separated image by 0, 15, 30, and 45 degrees respectively.
  3. Take the half-tone of each image (dot size will be proportional to the intensity).
  4. Rotate back each half-toned image.

Теперь у вас есть разделенные изображения цвета. Как вы упомянули, шаг поворота уменьшает проблемы с выравниванием точек (которые могут все испортить), и такие вещи, какМойр & # xE9; шаблонные эффекты будет разумно сведено к минимуму.

Это должно быть довольно легко с помощью кода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экономия чернил, сокращение времени сушки, уменьшение вытекания чернил и т. д. Во всяком случае, я также написал немногоЗамена серого компонента функцияGCA, так что вы можете установить процентK канал, который вы хотите заменитьCMY перекрываются с (я объясняю это немного дальше в комментариях к коду).

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

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

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

объединяет в производство:

enter image description here

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

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

Ваш ответ на вопрос