将ImageMagick FX操作符转换为纯Python代码与PIL
我正在尝试把一些图像处理功能从一个Image Magick命令(使用Fx特殊效果图像操作符)移植到Python中,使用PIL库。我的问题是,我不太明白这个fx操作符到底在做什么:
convert input.png gradient.png -fx "v.p{0,u*v.h}" output.png
从整体上看,这个命令是从一个渐变图像(gradient.png)中提取颜色,并把这些颜色作为输入图像(input.png)的调色板,最后写入到一个输出图像(output.png)中。
根据我了解到的,u是输入图像,v是渐变图像,它会从渐变图像的最左边的像素开始,从上到下逐个处理,以某种方式把这些颜色应用到输入图像上。
我一直想不明白如何用PIL以编程的方式做到这一点。我想到的最好办法是把图像转换成调色板图像(降采样到仅256种颜色),然后通过一个像素访问对象逐个从渐变中获取颜色。
import Image
# open the input image
input_img = Image.open('input.png')
# open gradient image and resize to 256px height
gradient_img = Image.open('gradient.png')
gradient_img = gradient_img.resize( (gradient_img.size[0], 256,) )
# get pixel access object (significantly quicker than getpixel method)
gradient_pix = gradient_img.load()
# build a sequence of 256 palette values (going from bottom to top)
sequence = []
for i in range(255, 0, -1):
# from rgb tuples for each pixel row
sequence.extend(gradient_pix[0, i])
# convert to "P" mode in order to use putpalette() with built sequence
output_img = input_img.convert("P")
output_img.putpalette(sequence)
# save output file
output_img = output_img.convert("RGBA")
output_img.save('output.png')
这样做是可行的,但正如我所说的,这样降采样到256种颜色。这不仅是一种笨拙的做法,而且输出的图像质量非常差。我该如何在不把结果限制在256种颜色的情况下,复制Magick的功能呢?
补充:忘了提到我找到原始Magick命令的博客
1 个回答
1
我知道已经过去一个月了,你可能已经搞明白了。不过这里有个答案。
通过查看ImageMagicK的文档,我明白了这个效果实际上是做什么的。
convert input.png gradient.png -fx "v.p{0,u*v.h}" output.png
v is the second image (gradient.png)
u is the first image (input.png)
v.p will get a pixel value
v.p{0, 0} -> first pixel in the image
v.h -> the hight of the second image
v.p{0, u * v.h} -> will read the Nth pixel where N = u * v.h
我把这个效果转换成了PIL,结果看起来正是你想要的样子:
import Image
# open the input image
input_img = Image.open('input.png')
# open gradient image and resize to 256px height
gradient_img = Image.open('gradient.png')
gradient_img = gradient_img.resize( (gradient_img.size[0], 256,) )
# get pixel access object (significantly quicker than getpixel method)
gradient_pix = gradient_img.load()
data = input_img.getdata()
input_img.putdata([gradient_pix[0, r] for (r, g, b, a) in data])
input_img.save('output.png')