2015-05-29 109 views
7

我正在研究一個項目,我想將彩色網格的圖片作爲輸入(在此示例中用樂高積木製作),並返回一個更小的修改後的圖片。Pixelate Image With Pillow

下面是一個例子輸入:

Input

下面是一個非常小的8×8的圖像,這將是結果:

Output

這裏是一個多較大版本的預期結果:

Big Output

這是到目前爲止我的代碼: 只用黑白影像作品。

from PIL import Image 
import re 

black = [(110,110,110),(0,0,0)] #The highest value and the lowest RGB value for the color black 

img = Image.open("input.jpg") #The input image 
size = (8,8) #The dimensions of the output image 

out = img.resize(size,resample=Image.LANCZOS) #Resize the image 

for y in range(size[0]): #loop through every pixel 
    for x in range(size[1]): 

     if out.getpixel((x,y)) <= black[0] and out.getpixel((x,y)) >= black[1]: #check to see if the pixel is within the accepted black values 

      out.putpixel((x,y), (0,0,0)) #Give the current pixel true color 
     else: 
      #otherwise make the pixel black 
      out.putpixel((x,y), (255,255,255)) #Give the current pixel true color 

"""Save the pixelated image""" 
out.save("output.jpg") 

並通過我的代碼返回的輸出:

Actual Output

我的程序工作正常的黑白圖像,但我需要幫助改變它與多種顏色(紅色工作,橙,黃,淺綠,深綠,淺藍,深藍,紫,黑和白)。

在此先感謝!

+0

不縮略圖做你想要的嗎? –

回答

7

你正在做一些錯誤的事情。

首先,你應該使用PNG,而不是JPG輸出。 JPG引入瞭如此多的文物,像輸出這樣的小圖像會完全退化。

然後,你應該減少你的調色板。處理不含噪音的輸入會更容易。

首先,無聊初始化:

from PIL import Image 
import operator 
from collections import defaultdict 
import re 

input_path = 'input.jpg' 
output_path = 'output.png' 
size = (4,4) 

然後我們聲明調色板 - 這應該包含所有可能的樂高積木的顏色。我下面的採樣值從你的形象,但像你在你的代碼呢,還是因爲他們是類似於源圖像中的顏色你想,只要任何顏色,你可以用黑白:

palette = [ 
    (45, 50, 50), #black 
    (240, 68, 64), #red 
    (211, 223, 223), #white 
    (160, 161, 67), #green 
    (233, 129, 76), #orange 
] 
while len(palette) < 256: 
    palette.append((0, 0, 0)) 

的下面的代碼將聲明調色板PIL,因爲需要PIL扁平陣列而不是陣列元組:

flat_palette = reduce(lambda a, b: a+b, palette) 
assert len(flat_palette) == 768 

現在我們可以聲明將保存的調色板的圖像。我們將使用它來減少原始圖像的顏色。

palette_img = Image.new('P', (1, 1), 0) 
palette_img.putpalette(flat_palette) 

這裏我們打開圖像並對其進行量化。我們將其規模擴大至比需要大8倍,因爲我們將在稍後對平均產出進行抽樣。

multiplier = 8 
img = Image.open(input_path) 
img = img.resize((size[0] * multiplier, size[1] * multiplier), Image.BICUBIC) 
img = img.quantize(palette=palette_img) #reduce the palette 

在此之後,我們的形象是這樣的:

quantized image

我們需要將其轉換回RGB,使我們現在可以品嚐像素:

img = img.convert('RGB') 

現在我們將要構建我們的最終形象。爲此,我們將在較大圖像中的每個方塊中對每個調色板顏色的像素數進行取樣。然後我們會選擇最常出現的顏色。

out = Image.new('RGB', size) 
for x in range(size[0]): 
    for y in range(size[1]): 
     #sample at get average color in the corresponding square 
     histogram = defaultdict(int) 
     for x2 in range(x * multiplier, (x + 1) * multiplier): 
      for y2 in range(y * multiplier, (y + 1) * multiplier): 
       histogram[img.getpixel((x2,y2))] += 1 
     color = max(histogram.iteritems(), key=operator.itemgetter(1))[0] 
     out.putpixel((x, y), color) 

最後,我們將輸出保存:

out.save(output_path) 

結果:

small image

1600%比例放大:

big image

+0

你好,我剛剛開始使用代碼,它給我帶來一些看起來像是與python版本有關的錯誤。我正在使用Python 3.4.2。這個代碼是用什麼版本編寫的? –

+0

Python 3.4.3,但我使用Pillow而不是PIL(它是一個更活躍的分叉)。可能有最小的API更改。 –

+1

感謝您的信息。我很高興地說,現在我已經完成了所有工作。 –

3

只是爲了好玩,我解決了這一與ImageMagick的 - 這也是從Python中調用...

首先,我創建了一個有點自定義調色板來匹配你的顏色 - 你的白是不是很白,你的綠是不同的從ImageMagick的綠色想法,所以我用十六進制代替顏色名稱。

convert xc:black xc:red xc:"rgb(200,200,200)" xc:"rgb(168,228,23)" xc:orange +append palette.png 

如果我擴大該面板時,它看起來是這樣的:

enter image description here

然後我調整圖像到4x4和映射結果到自定義面板和規模備份等等你可以看到它是這樣的:

convert lego.jpg -resize 4x4! +dither -remap palette.png -scale 1600 result.png 

這裏是結果

enter image description here

白色是關閉以匹配您的原來的「白色」