Python中的半色调图像

时间:2012-05-13 13:47:38

标签: python image cmyk

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

我猜我需要:1。将文件分成彩色通道。 2.为该频道生成单色半色调图像。 3.将得到的半色调图像偏移*度数*。有谁知道这是否是正确的方法?

有没有人知道任何现有的python代码?或者对这个过程或算法有什么好的解释?

2 个答案:

答案 0 :(得分:24)

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

  1. 将图像分割为C,M,Y,K。
  2. 将每个分离的图像分别旋转0度,15度,30度和45度。
  3. 拍摄每张图像的半色调(点大小与强度成正比)。
  4. 向后旋转每张半色调的图像。
  5. 现在你有了分色图像。正如您所提到的,旋转步骤减少了点对齐问题(这会使所有事情变得混乱),Moiré pattern effects之类的事情将被合理地最小化。

    使用PIL进行编码应该非常简单。

    更新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 Fsample=1处理图片中的scale=8,以便获得相当高的分辨率。

    包含CMYK的4个percentage=0频道,空K频道:

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

    组合产生:

    enter image description here

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

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

答案 1 :(得分:4)

我的解决方案也使用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应用也可以用更通用的扩展,但我试图描述一个简单的解决方案,其中也忽略了分辨率和采样。