私は以前、スクリーン印刷スタジオ (かなり小さなスタジオでした) を経営していました。実際に色分解印刷を行ったことはありませんが、原則についてはかなり精通しています。これは私がそれにアプローチする方法です:
- イメージを C、M、Y、K に分割します。
- 分離された各イメージをそれぞれ 0、15、30、および 45 度回転します。
- 各画像のハーフトーンを取得します (ドット サイズは強度に比例します)。
- 各ハーフトーン イメージを元に戻します。
これで、色分けされた画像ができました。あなたが言及したように、回転ステップはドットの配置の問題(すべてを台無しにする)を減らし、モアレパターンの影響などは合理的に最小限に抑えられます.
これは、 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
GCR
K
CMY
例をいくつか示します。letter F
画像から と を処理するsample=1
とscale=8
、かなり高解像度になります。
の 4 つのCMYK
チャネル、percentage=0
空のK
チャネル:
組み合わせて生成します:
CMYK
channels, with percentage=100
, したがってK
channel が使用されます. シアン チャネルが完全に抑制され、マゼンタとイエロー チャネルが使用するインクがかなり少ないことが、画像の下部にある黒い帯でわかります。