Search code examples
pythonlistfileappendppm

Color Reduction - Only Reds are generated


I am trying to reduce the color of a ppm image file from 255 colors to 5 colors(red, blue, green, black and white). When I initiate my test file, the pixel_list generated is only reds, which is not correct. I'm using the Euclidean distance formula to find which of the 5 colors the pixel is closest too and changing the values to that color. (Color Reduction)

Here is an example of my data: (The first three rows are file type, dimensions and total colors. The following rows are pixel data ordered in r, g, b.)

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

My code:

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)

Second 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)

Solution

  • What you seem to be trying to say here

    a < b and c and d and e
    

    is

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

    But it's pretty inefficient to compute and compare those values over and over anyway, when all you are really interested in is the minimum.

    so consider:

    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)
    

    and

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

    Now idx is the index of the smallest item in L, so you can use that index to select the colour

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

    Aside: It's a good optimisation not to bother with the sqrt as it doesn't affect the ordering.

    Here is an example run using the first pixel of you question (r=0, g=48, b=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