2015-11-16 4 views
2

Я пытаюсь уменьшить цвет файла изображения ppm от 255 цветов до 5 цветов (красный, синий, зеленый, черный и белый). Когда я запускаю свой тестовый файл, генерируемый pixel_list является только красным, что неверно. Я использую формулу евклидовой дистанции, чтобы найти, какой из 5 цветов пиксель ближе всего и меняет значения на этот цвет. (Цвет сокращения)Уменьшение цвета - генерируются только красные

Ниже приведен пример моих данных: (.. Первые три строки являются тип файла, размеры и общее количество цветов следующие строки пиксельные данные упорядочены в г, г, б)

P3 
200 200 
255 
0 
48 
255 
216 
52 
180 
252 
255 
176 
212 
96 
4 
0 
108 
20 
40 
64 
80 
140 
0 
80 

Мой код:

import math 

with open('test_pattern.ppm','r') as f: 
    output = f.read().split("\n") 

i = 0 
r_point = 3 + i 
g_point = 4 + i 
b_point = 5 + i 
pixel_list = [] 

resolution = [] 
resolution.append(output[1].split(" ")) 
file_size = resolution[0] 
file_size = int(file_size[0]) * int(file_size[1]) 
file_size = int(file_size*3) 
print(file_size) 

while file_size >= i: 
    r = int(output[r_point]) 
    g = int(output[g_point]) 
    b = int(output[b_point]) 
    if all(math.sqrt((r-255)**2 + (g - 0)**2 + (b-0)**2) < x for x in [math.sqrt((r-0)**2 + (g - 255)**2 + (b-0)**2) , math.sqrt((r-0)**2 + (g - 0)**2 + (b-255)**2) , math.sqrt((r-0)**2 + (g - 0)**2 + (b-0)**2) , math.sqrt((r-255)**2 + (g - 255)**2 + (b-255)**2)]): 
     r = 255 
     g = 0 
     b = 0 
     pixel_list.append(r) 
     pixel_list.append(g) 
     pixel_list.append(b) 
     i += 3 


    elif all(math.sqrt((r-0)**2 + (g - 255)**2 + (b-0)**2) < x for x in [math.sqrt((r-0)**2 + (g - 0)**2 + (b-255)**2) , math.sqrt((r-255)**2 + (g - 0)**2 + (b-0)**2) , math.sqrt((r-0)**2 + (g - 0)**2 + (b-0)**2) , math.sqrt((r-255)**2 + (g - 255)**2 + (b-255)**2)]): 
     r = 0 
     g = 255 
     b = 0 
     pixel_list.append(r) 
     pixel_list.append(g) 
     pixel_list.append(b) 
     i +=3 


    elif all(math.sqrt((r-0)**2 + (g - 0)**2 + (b-255)**2) < x for x in [math.sqrt((r-0)**2 + (g - 255)**2 + (b-0)**2) , math.sqrt((r-255)**2 + (g - 0)**2 + (b-0)**2) , math.sqrt((r-0)**2 + (g - 0)**2 + (b-0)**2) , math.sqrt((r-255)**2 + (g - 255)**2 + (b-255)**2)]): 
     r = 0 
     g = 0 
     b = 255 
     pixel_list.append(r) 
     pixel_list.append(g) 
     pixel_list.append(b) 
     i += 3 


    elif all(math.sqrt((r-0)**2 + (g - 0)**2 + (b-0)**2) < x for x in [math.sqrt((r-0)**2 + (g - 255)**2 + (b-0)**2) , math.sqrt((r-255)**2 + (g - 0)**2 + (b-0)**2) , math.sqrt((r-0)**2 + (g - 0)**2 + (b-255)**2) , math.sqrt((r-255)**2 + (g - 255)**2 + (b-255)**2)]): 
     r = 0 
     g = 0 
     b = 0 
     pixel_list.append(r) 
     pixel_list.append(g) 
     pixel_list.append(b) 
     i += 3 


    elif all(math.sqrt((r-255)**2 + (g - 255)**2 + (b-255)**2) < x for x in [math.sqrt((r-0)**2 + (g - 255)**2 + (b-0)**2) , math.sqrt((r-255)**2 + (g - 0)**2 + (b-0)**2) , math.sqrt((r-0)**2 + (g - 0)**2 + (b-0)**2) , math.sqrt((r-0)**2 + (g - 0)**2 + (b-255)**2)]): 
     r = 255 
     g = 255 
     b = 255 
     pixel_list.append(r) 
     pixel_list.append(g) 
     pixel_list.append(b) 
     i += 3 


print(pixel_list) 

Второй Try:

import math 

with open('test_pattern.ppm','r') as f: 
    output = f.read().split("\n") 
i = 0 
r_point = 3 + i 
g_point = 4 + i 
b_point = 5 + i 
pixel_list = [] 
resolution = [] 
resolution.append(output[1].split(" ")) 
file_size = resolution[0] 
file_size = int(file_size[0]) * int(file_size[1]) 
file_size = int(file_size*3) 
print(file_size) 


while file_size >= i: 
    r = int(output[r_point]) 
    g = int(output[g_point]) 
    b = int(output[b_point]) 
    a = math.sqrt((r-255)**2 + (g - 0)**2 + (b-0)**2) 
    b = math.sqrt((r-0)**2 + (g - 255)**2 + (b-0)**2) 
    c = math.sqrt((r-0)**2 + (g - 0)**2 + (b-255)**2) 
    d = math.sqrt((r-0)**2 + (g - 0)**2 + (b-0)**2) 
    e = math.sqrt((r-255)**2 + (g - 255)**2 + (b-255)**2) 

    L = [a, b, c, d, e] 
    idx = min(range(len(L)), key=L.__getitem__) 

    if idx == 0: 
     # red 
     r = 255 
     g = 0 
     b = 0 
     pixel_list.append(r) 
     pixel_list.append(g) 
     pixel_list.append(b) 
     i += 3 

    if idx == 1: 
     # green 
     r = 0 
     g = 255 
     b = 0 
     pixel_list.append(r) 
     pixel_list.append(g) 
     pixel_list.append(b) 
     i += 3 


    if idx == 2: 
     # blue 
     r = 0 
     g = 0 
     b = 255 
     pixel_list.append(r) 
     pixel_list.append(g) 
     pixel_list.append(b) 
     i += 3 


    if idx == 3: 
     # white 
     r = 0 
     g = 0 
     b = 0 
     pixel_list.append(r) 
     pixel_list.append(g) 
     pixel_list.append(b) 
     i += 3 


    if idx == 4: 
     # black 
     r = 255 
     g = 255 
     b = 255 
     pixel_list.append(r) 
     pixel_list.append(g) 
     pixel_list.append(b) 
     i += 3 


print(pixel_list) 
+0

При перемещении 'r_point = 3 + i' ' g_point = 4 + i' 'b_point = 5 + i' внутри время цикла, программа будет работать, но вы должны продолжать реорганизовать его, так как это все еще можно сделать намного проще для чтения –

+0

Спасибо, что это сработало – Wakedude

ответ

2

Что вы, кажется, пытается сказать здесь

a < b and c and d and e 

является

a < b and a < c and a < d and a < e 

Но это довольно неэффективный вычислить и сравнить эти значения снова и снова в любом случае, когда все, что вы на самом деле интересует минимум.

так считают:

a = math.sqrt((r-255)**2 + (g - 0)**2 + (b-0)**2) 
b = math.sqrt((r-0)**2 + (g - 255)**2 + (b-0)**2) 
c = math.sqrt((r-0)**2 + (g - 0)**2 + (b-255)**2) 
d = math.sqrt((r-0)**2 + (g - 0)**2 + (b-0)**2) 
e = math.sqrt((r-255)**2 + (g - 255)**2 + (b-255)**2) 

и

L = [a, b, c, d, e] 
idx = min(range(len(L)), key=L.__getitem__) 

Теперь idx является индекс наименьшего элемента в L, так что вы можете использовать этот индекс, чтобы выбрать цвет

if idx == 0: 
    # red 
if idx == 1: 
    # green 
if idx == 2: 
    # blue 
if idx == 3: 
    # white 
if idx == 4: 
    # black 

Помимо: Хорошая оптимизация не, чтобы беспокоиться о sqrt, так как это не влияет на порядок.

Вот пример запуска с использованием первого пиксела из вас вопрос (г = 0, г = 48, б = 255)

>>> import math 
>>> r = 0 
>>> g = 48 
>>> b = 255 
>>> a = math.sqrt((r-255)**2 + (g - 0)**2 + (b-0)**2) 
>>> b = math.sqrt((r-0)**2 + (g - 255)**2 + (b-0)**2) 
>>> c = math.sqrt((r-0)**2 + (g - 0)**2 + (b-255)**2) 
>>> d = math.sqrt((r-0)**2 + (g - 0)**2 + (b-0)**2) 
>>> e = math.sqrt((r-255)**2 + (g - 255)**2 + (b-255)**2) 
>>> L = [a, b, c, d, e] 
>>> idx = min(range(len(L)), key=L.__getitem__) 
>>> idx 
2 
+0

Хорошо, я тоже пробовал ваше предложение. Я разместил свой код, используя ваш метод, в нижней части вопроса, но я все еще получаю только красные числа, добавленные в список пикселей. – Wakedude

+0

@Wakedude, попробуйте напечатать 'r',' g' и 'b', а также' idx'. Достаточно просто запустить их вручную, чтобы увидеть, что выходные пиксели не все будут «красными» –

+0

@Wakedude, вы фактически не перемещаете 'r_point',' g_point', 'b_point' через файл. Они всегда одни и те же пиксель! –

3

ваш первый если заявление equiva одолжил:

math.sqrt((r-255)**2 + (g - 0)**2 + (b-0)**2) < math.sqrt((r-255)**2 + (g - 255)**2 + (b-255)**2): #your last boolean in your brackets 

Это происходит потому, что, как питон оценивает булевы:

>>> 4 and 5 
5 

Я предполагаю, что вы хотели бы заверить первое заявление меньше, чем все выражения в правой руке Оператор <. Вы должны сделать что-то вроде:

if all(firstexpression < x for x in [all your expressions in here]): 

это делает использование питонов all функции, которая принимает список и возвращает ли не каждый элемент в нем будет утверждать на True.

+0

Это все еще включает в себя и между выражениями или они должны быть разделены запятыми? – Wakedude

+0

измените их на запятые, потому что вы хотите, чтобы они были отдельными элементами в списке. ваше использование 'и' было, в принципе, не правильным –

+0

Я пошел вперед и внес изменения, которые вы рекомендовали, но я все еще получаю все красное. – Wakedude

1

Вы используете and неправильно. Он объединяет поплавки с and, который заканчивается либо 0.0, либо последним. Вы также вычисляете и пересчитываете те же значения больше, чем вам нужно. Вы также вычисляете квадратные корни , что дорого, когда вам это не нужно.

Вычислить квадраты из пяти расстояний, раз, тогда посмотрите, какая именно наименее.

0

Я просто поставить это там в качестве дополнительной информации только потому, что он использует NumPy:

Screen shot reduced colors

import numpy as np 
import matplotlib.pyplot as plt 

a = np.random.random((50, 50, 3)) 
do = np.ones_like(a, dtype=bool) 
do[0], do[-1], do[:,0], do[:,-1] = False, False, False, False 

a2 = 0.25*(np.roll(a, 1, axis=0) + np.roll(a, -1, axis=0) + 
      np.roll(a, 1, axis=1) + np.roll(a, -1, axis=1)) #smooth a little 
b = a.copy() 
b[do] = a2[do] 

a, b = a[1:-1,1:-1], b[1:-1,1:-1] # trim the edge 

c = (b - b.min())/(b.max() - b.min()) # rescale a bit 

colors = np.array([[1,0,0], [0,1,0], [0,0,1], [1,1,1], [0,0,0]], dtype=float) 

dsqa = ((a[...,None,:]-colors[None,None,...])**2).sum(axis=-1) 
dsqb = ((b[...,None,:]-colors[None,None,...])**2).sum(axis=-1) 
dsqc = ((c[...,None,:]-colors[None,None,...])**2).sum(axis=-1) 

i_closesta = np.argmin(dsqa, axis=-1) 
i_closestb = np.argmin(dsqb, axis=-1) 
i_closestc = np.argmin(dsqc, axis=-1) 

a_reduced = colors[i_closesta] 
b_reduced = colors[i_closestb] 
c_reduced = colors[i_closestc] 

fs = 18 
plt.figure() 
plt.subplot(2,3,1) 
plt.imshow(a, interpolation="nearest") 
plt.title("raw noise", fontsize=fs) 
plt.subplot(2,3,4) 
plt.imshow(a_reduced, interpolation="nearest") 
plt.title("raw noise reduced", fontsize=fs) 
plt.subplot(2,3,2) 
plt.imshow(b, interpolation="nearest") 
plt.title("smoothed noise", fontsize=fs) 
plt.subplot(2,3,5) 
plt.imshow(b_reduced, interpolation="nearest") 
plt.title("smooth noise reduced", fontsize=fs) 
plt.subplot(2,3,3) 
plt.imshow(c, interpolation="nearest") 
plt.title("smoothed, rescaled noise", fontsize=fs) 
plt.subplot(2,3,6) 
plt.imshow(c_reduced, interpolation="nearest") 
plt.title("smoothed, rescaled noise reduced", fontsize=fs) 
plt.show() 
0

Вы, кажется, есть несколько неправильных представлений о вещах. Первый заключается в том, что if expression0 < (expression1, expression2, etc) будет сравнивать первое значение с каждым из других. Необходимо явно сравнить первое с каждым: if expression0 < expression1 and expression0 < expression2 and ....

Другая в том, что если у вас есть:

i = 0 
r_point = 3 + i 
g_point = 4 + i 
b_point = 5 + i 

и изменить набор i += 3, что r_point и другие значения будут автоматически меняться. Опять же вам нужно сделать это явно.

Вот модифицированная версия вашего кода, которая делает то, что вы хотите. Он также использует несколько функций для упрощения кода.

from math import fsum, sqrt 

def dist(c1, c2): 
    " Euclidean distance between two colors. " 
    diffs = (b-a for a, b in zip(c1, c2)) 
# return sqrt(fsum(diff*diff for diff in diffs)) 
    return fsum(diff*diff for diff in diffs) # distance squared will work 

def clostest_color(color, base_colors): 
    " Return the color in 'base_colors' that is closest to 'color'. " 
    dists = [dist(color, base_color) for base_color in base_colors] 
    min_dist = min(dists) 
    return base_colors[dists.index(min_dist)] 

BASE_COLORS = (255,0,0), (0,255,0), (0,0,255), (0,0,0), (255,255,255) 

with open('test_pattern.ppm', 'r') as f: 
    output = f.read().splitlines() 

width, height = (int(v) for v in output[1].split(' ')) 
num_pixels = width * height 
print('num_pixels: {}'.format(num_pixels)) 

pixel_list = [] 
pixel_count = 0 
OFFSET = 3 
r_point = pixel_count*3 + OFFSET 
g_point = r_point + 1 
b_point = r_point + 2 
while pixel_count < num_pixels: 
    r, g, b = int(output[r_point]), int(output[g_point]), int(output[b_point]) 
    r, g, b = clostest_color((r, g, b), BASE_COLORS) 
    pixel_list.extend((r, g, b)) 
    pixel_count += 1 
    r_point, g_point, b_point = r_point+3, g_point+3, b_point+3