Сохранение цветов при преобразовании CMYK в RGB в PIL - PullRequest
2 голосов
/ 15 февраля 2011

Я использую PIL для обработки загруженных изображений. К сожалению, у меня возникают проблемы с преобразованием цветов из CMYK в RGB, так как результирующие изображения меняют тон и контраст.

Я подозреваю, что он выполняет только прямые преобразования чисел. Имеет ли PIL, или что-либо построенное поверх него, Adobian dummy-proof , использует встроенный профиль, конвертирует в пункт назначения, сохраняет номера инструмент, который я могу использовать для конвертации?

Из-за моего здорового невежества и неопытности этот вид прыгнул на меня, и я в ужасе. Я действительно хотел бы сделать это без использования каких-либо тонкостей цветовых пространств, преобразований и необходимой математики для обоих на данный момент.

Хотя я никогда не использовал его ранее, я также склонен использовать ImageMagick для этого шага обработки, если у кого-то есть опыт, что он может выполнить его любезно.

Ответы [ 2 ]

8 голосов
/ 15 февраля 2011

Так что мне не пришлось долго сталкиваться с другими людьми, которые упоминали, что Little CMS - самое популярное решение с открытым исходным кодом для управления цветом. Я закончил слежку за привязками Python, нашел старые pyCMS и некоторые якобы представления о поддержке PIL Little CMS.

В самом деле, есть поддержка Little CMS, она упоминается в целом одной строке:

Поддержка CMS: littleCMS (рекомендуется 1.1.5 или более поздняя версия).

Документация не содержит ссылок, тематических руководств, Google ничего не сканировал, их список рассылки закрыт ... но при копании в источнике есть модуль PIL.ImageCms, который хорошо документирован и получить работу сделано. Надеюсь, это спасет кого-то от грязных раскопок в Интернете.

Уходит, получая себе печенье ...

1 голос
/ 16 июня 2019

это 2019, и все изменилось.Ваша проблема значительно сложнее, чем может показаться на первый взгляд.Проблема в том, что CMYK в RGB и RGB в CMYK не просто туда и обратно.Если, например, вы открываете изображение в Photoshop и конвертируете его там, это преобразование имеет 2 дополнительных параметра: исходный цветовой профиль и целевой цветовой профиль.Это сильно меняет дело!Для типичного случая использования вы бы приняли Adobe RGB 1998 на стороне RGB и сказали бы Coated FOGRA 39 на стороне CMYK.Эти две дополнительные части информации разъясняют преобразователю, как обращаться с цветами на входе и выходе.Далее вам нужен механизм трансформации, Little CMS действительно является отличным инструментом для этого.Это лицензия MIT и (после долгих поисков решений) я бы порекомендовал следующую настройку, если вам действительно нужен способ преобразования цветов на языке python:

  1. Python 3.X (необходимо)из-за littlecms)
  2. pip install littlecms
  3. pip install Pillow

В папке littlecms /tests вы найдете множество примеров.Я бы позволил себе особую адаптацию одного теста.Прежде чем получить код, позвольте мне рассказать вам кое-что об этих цветовых профилях.В Windows, как и в моем случае, вы найдете набор файлов с расширением .icc в папке C:\Windows\System32\spool\drivers\color, где Windows хранит свои цветовые профили.Вы можете скачать другие профили с сайтов, таких как https://www.adobe.com/support/downloads/iccprofiles/iccprofiles_win.html и установить их в Windows, просто дважды щелкнув соответствующий файл .icc.Приведенный мною пример зависит от таких файлов профиля, которые Little CMS использует для преобразования этих волшебных цветов.Я работаю полупрофессиональным графическим дизайнером, и мне нужно было иметь возможность конвертировать цвета из CMYK в RGB и наоборот для определенных скриптов, которые манипулируют объектами в InDesign.Моя установка - RGB: Adobe RGB 1998 и CMYK: Coated FOGRA 39 (эти настройки рекомендованы большинством книжных принтеров, на которых печатаются мои книги).Вышеупомянутые цветовые профили дали мне результаты, очень похожие на те же преобразования, которые были сделаны в Photoshop и InDesign.Тем не менее, имейте в виду, что цвета немного (примерно на 1%) отключены по сравнению с тем, что PS и Id предоставят вам для тех же самых входов.Я пытаюсь понять, почему ...

Маленькая программа:

import littlecms as lc
from PIL import Image

def rgb2cmykColor(rgb, psrc='C:\\Windows\\System32\\spool\\drivers\\color\\AdobeRGB1998.icc', pdst='C:\\Windows\\System32\\spool\\drivers\\color\\CoatedFOGRA39.icc') :
    ctxt = lc.cmsCreateContext(None, None)

    white = lc.cmsD50_xyY()    # Set white point for D50
    dst_profile = lc.cmsOpenProfileFromFile(pdst, 'r')
    src_profile = lc.cmsOpenProfileFromFile(psrc, 'r') # cmsCreate_sRGBProfile()
    transform = lc.cmsCreateTransform(src_profile, lc.TYPE_RGB_8, dst_profile, lc.TYPE_CMYK_8,
                                  lc.INTENT_RELATIVE_COLORIMETRIC, lc.cmsFLAGS_NOCACHE)

    n_pixels = 1
    in_comps = 3
    out_comps = 4
    rgb_in = lc.uint8Array(in_comps * n_pixels)
    cmyk_out = lc.uint8Array(out_comps * n_pixels)
    for i in range(in_comps):
        rgb_in[i] = rgb[i]

    lc.cmsDoTransform(transform, rgb_in, cmyk_out, n_pixels)

    cmyk = tuple(cmyk_out[i] for i in range(out_comps * n_pixels))
    return cmyk

def cmyk2rgbColor(cmyk, psrc='C:\\Windows\\System32\\spool\\drivers\\color\\CoatedFOGRA39.icc', pdst='C:\\Windows\\System32\\spool\\drivers\\color\\AdobeRGB1998.icc') :
    ctxt = lc.cmsCreateContext(None, None)

    white = lc.cmsD50_xyY()    # Set white point for D50
    dst_profile = lc.cmsOpenProfileFromFile(pdst, 'r')
    src_profile = lc.cmsOpenProfileFromFile(psrc, 'r') # cmsCreate_sRGBProfile()
    transform = lc.cmsCreateTransform(src_profile, lc.TYPE_CMYK_8, dst_profile, lc.TYPE_RGB_8,
                                  lc.INTENT_RELATIVE_COLORIMETRIC, lc.cmsFLAGS_NOCACHE)

    n_pixels = 1
    in_comps = 4
    out_comps = 3
    cmyk_in = lc.uint8Array(in_comps * n_pixels)
    rgb_out = lc.uint8Array(out_comps * n_pixels)
    for i in range(in_comps):
        cmyk_in[i] = cmyk[i]

    lc.cmsDoTransform(transform, cmyk_in, rgb_out, n_pixels)

    rgb = tuple(rgb_out[i] for i in range(out_comps * n_pixels))
    return rgb

def rgb2cmykImage(PILImage, psrc='C:\\Windows\\System32\\spool\\drivers\\color\\AdobeRGB1998.icc', pdst='C:\\Windows\\System32\\spool\\drivers\\color\\CoatedFOGRA39.icc') :
    ctxt = lc.cmsCreateContext(None, None)
    white = lc.cmsD50_xyY()    # Set white point for D50
    dst_profile = lc.cmsOpenProfileFromFile(pdst, 'r')
    src_profile = lc.cmsOpenProfileFromFile(psrc, 'r')
    transform = lc.cmsCreateTransform(src_profile, lc.TYPE_RGB_8, dst_profile, lc.TYPE_CMYK_8,
                                  lc.INTENT_RELATIVE_COLORIMETRIC, lc.cmsFLAGS_NOCACHE)

    n_pixels = PILImage.size[0]

    in_comps = 3
    out_comps = 4
    n_rows = 16

    rgb_in = lc.uint8Array(in_comps * n_pixels * n_rows)
    cmyk_out = lc.uint8Array(out_comps * n_pixels * n_rows)

    outImage = Image.new('CMYK', PILImage.size, 'white')
    in_row = Image.new('RGB', (PILImage.size[0], n_rows), 'white')
    out_row = Image.new('CMYK', (PILImage.size[0], n_rows), 'white')
    out_b = bytearray(n_pixels * n_rows * out_comps)
    row = 0

    while row < PILImage.size[1] :

        in_row.paste(PILImage, (0, -row))
        data_in = in_row.tobytes('raw')

        j = in_comps * n_pixels * n_rows

        for i in range(j):
            rgb_in[i] = data_in[i]

        lc.cmsDoTransform(transform, rgb_in, cmyk_out, n_pixels * n_rows)

        for j in cmyk_out :
            out_b[j] = cmyk_out[j]

        out_row = Image.frombytes('CMYK', in_row.size, bytes(out_b))
        outImage.paste(out_row, (0, row))
        row += n_rows

    return outImage

def cmyk2rgbImage(PILImage, psrc='C:\\Windows\\System32\\spool\\drivers\\color\\CoatedFOGRA39.icc', pdst='C:\\Windows\\System32\\spool\\drivers\\color\\AdobeRGB1998.icc') :
    ctxt = lc.cmsCreateContext(None, None)
    white = lc.cmsD50_xyY()    # Set white point for D50
    dst_profile = lc.cmsOpenProfileFromFile(pdst, 'r')
    src_profile = lc.cmsOpenProfileFromFile(psrc, 'r')
    transform = lc.cmsCreateTransform(src_profile, lc.TYPE_CMYK_8, dst_profile, lc.TYPE_RGB_8,
                                  lc.INTENT_RELATIVE_COLORIMETRIC, lc.cmsFLAGS_NOCACHE)

    n_pixels = PILImage.size[0]

    in_comps = 4
    out_comps = 3
    n_rows = 16

    cmyk_in = lc.uint8Array(in_comps * n_pixels * n_rows)
    rgb_out = lc.uint8Array(out_comps * n_pixels * n_rows)

    outImage = Image.new('RGB', PILImage.size, 'white')
    in_row = Image.new('CMYK', (PILImage.size[0], n_rows), 'white')
    out_row = Image.new('RGB', (PILImage.size[0], n_rows), 'white')
    out_b = bytearray(n_pixels * n_rows * out_comps)
    row = 0

    while row < PILImage.size[1] :

        in_row.paste(PILImage, (0, -row))
        data_in = in_row.tobytes('raw')

        j = in_comps * n_pixels * n_rows

        for i in range(j):
            cmyk_in[i] = data_in[i]

        lc.cmsDoTransform(transform, cmyk_in, rgb_out, n_pixels * n_rows)

        for j in rgb_out :
            out_b[j] = rgb_out[j]

        out_row = Image.frombytes('RGB', in_row.size, bytes(out_b))
        outImage.paste(out_row, (0, row))
        row += n_rows

    return outImage
...