【问题标题】:How to create CMYK halftone Images from a color image?如何从彩色图像创建 CMYK 半色调图像?
【发布时间】:2012-05-21 06:50:05
【问题描述】:

我正在从事一个项目,该项目需要我分离出 CYMK 图像中的每种颜色并生成将在特殊的半色调打印机上打印的半色调图像。使用的方法类似于丝网印刷,其过程几乎相同。拍一张照片并打破每个颜色通道。然后为半色调制作一个网屏。每个彩色屏幕的屏幕必须倾斜 15-45(可调)度。点大小和 LPI 必须根据用户可配置的值计算,以实现不同的效果。我被告知这个过程用于丝网印刷,但我无法找到任何解释 CYMK 半色调的信息。我发现有很多方法可以减少为单一颜色并生成新的打印风格黑白半色调图像。

我猜我需要:

  1. 将文件拆分为其颜色通道。
  2. 为该通道生成单色半色调图像。
  3. 将生成的半色调图像倾斜度数 * 通道数。

有谁知道这是否是正确的方法以及任何现有的 Python 代码?或者对这个过程或算法有什么好的解释?

【问题讨论】:

标签: python image image-processing python-imaging-library cmyk


【解决方案1】:

我曾经经营过一家丝网印刷工作室(那是一间很小的),虽然我从未真正做过分色印刷,但我对这些原理相当熟悉。这就是我的处理方式:

  1. 将图像拆分为 C、M、Y、K。
  2. 将每个分离的图像分别旋转 0、15、30 和 45 度。
  3. 对每张图像进行半色调处理(点大小与强度成正比)。
  4. 将每个半色调图像向后旋转。

现在您有了分色图像。正如您所提到的,旋转步骤减少了点对齐问题(这会使一切变得混乱),并且像Moiré pattern effects 这样的事情将被合理地最小化。

这应该很容易使用PIL 编写代码。

更新 2:

我为您编写了一些快速代码,它还包括一个GCR 函数(如下所述):

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

这会变成这样:

进入这个(模糊你的眼睛并远离显示器):

请注意,图像采样可以逐像素进行(从而在最终图像中保留原始图像的分辨率)。通过设置sample=1 来执行此操作,在这种情况下,您需要将scale 设置为更大的数字,以便有多个可能的点大小。这也会导致更大的输出图像尺寸(原始图像尺寸 * 比例 ** 2,所以要小心!)。

默认情况下,当您从RGB 转换为CMYK 时,K 通道(黑色通道)为空。您是否需要K 频道取决于您的打印过程。您可能想要它的原因可能有多种:获得比CMY 的重叠更好的黑色、节省墨水、缩短干燥时间、减少墨水渗色等。无论如何我还写了一点Grey component replacement 函数GCR ,因此您可以设置要替换 CMY 重叠的 K 频道的百分比(我在代码 cmets 中对此进行了进一步解释)。

这里有几个例子来说明。处理图像中的letter F,使用sample=1scale=8,分辨率相当高。

4 个CMYK 频道,有percentage=0,所以空K 频道:

组合产生:

CMYK 频道,与percentage=100,因此使用K 频道。您可以看到青色通道被完全抑制,而品红色和黄色通道使用的墨水要少得多,在图像底部的黑色带中:

【讨论】:

  • @user69333 - 很酷,祝你好运!顺便说一句,我是 fraxel(与 Andrew 不同,他也回答了..)。如果您能通过单击勾号“接受我的回答”,我将不胜感激,这就是 stackoverflow 的工作方式(我们都得到了分数……哎呀),干杯。
  • 再次感谢安德鲁。您的灰度组件可能会派上用场。我在这里学到的大部分内容都来自 T-Shirt 网站。现在它让我考虑为 T 恤印刷做一些 OSS。但是,我注意到商业软件似乎使用 RGB 以及 CMYK 通道和其他屏幕。我读了一篇关于使用 Photoshop 进行丝网印刷 T 恤的短文,看来它们对它很重要。至于我的打印机项目,你让我有了一个很好的开始。我将添加您的灰度代码并制作更多模组。
  • 我在网上找到了一些角度,每个通道从 10 度到 60 度不等,发现某些组合会产生非常糟糕的波纹图案效果,而其他组合会减少这些效果。我的代码允许我为每个通道设置特定的角度,这样我就可以使用非增量的角度。这似乎有助于减少影响,但也可以改变感知的颜色。混在一起很酷;-)
  • 对不起,名字混淆了。仍然不确定这个网站是如何运作的。
  • @user69333 - 如果你能接受我的回答,那就太好了! (您目前已接受安德鲁斯的回答......)。一开始我也觉得这个网站很混乱!
【解决方案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 应用也可以扩展为更通用的,但我试图描述一个简单的解决方案,其中分辨率和采样也被忽略。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-09
    • 1970-01-01
    • 2015-12-16
    • 2018-03-05
    • 2011-05-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多