Ari Lotter
Ari Lotter

Reputation: 615

How do I remove pixels based on luminescence in RGB with PIL?

I'm trying to write a glitch art program that lets me make pictures kinda fall like sand, and I have it working for greyscale (L). I'm trying to convert it into color, but I can't get this code to work. Here's what I have for color

#! /usr/bin/python
from PIL import Image
from random import randint

# Sorts img kinda randomly
source = Image.open("test.jpg")
threshold = 150

img = source.load()

blackandwhite = source.convert("L").load()

canvas = Image.new("RGB", source.size)

newimg = canvas.load()
count = source.size[0]

print (source.format)
print (source.size)
print (source.mode)
print ("Threshold: ", threshold)
print ("============================================")

counter = 0 #counter
# do the loop twice because we want to make em fall!
counter = 0
for i in range(0, source.size[0]-1): # loop through every x value
    vert_list = [] #list of this column
    for pix in range(0, source.size[1]-1): #make a list of the column from the b&w img
        color = blackandwhite[i, pix] #for being in color ^^
        vert_list.append( color )

    counter += 1
    if counter % 10 == 0:
        print(counter, "/", count)
    #now remove all pixels brighter than the threshold

    color_vert_list = []
    for x in range(0, len(vert_list)-1):
        if vert_list[x] < threshold:
            color_vert_list.append(img[i, pix]) #add colors darker than something to the color list

    top_spacing = source.size[1] - len(color_vert_list) #height
    for pixel in range(0, len(color_vert_list)):
        newimg[i,pixel + top_spacing] = color_vert_list[pixel] #add em


canvas.save("fall.png") #save

and here's the same code working in black and white

#! /usr/bin/python
from PIL import Image
from random import randint

# Sorts img kinda randomly
source = Image.open("test.jpg")
threshold = 150

img = source.load()

blackandwhite = source.convert("L").load()

canvas = Image.new("L", source.size)

newimg = canvas.load()
count = source.size[0]

print (source.format)
print (source.size)
print (source.mode)
print ("Threshold: ", threshold)
print ("============================================")

counter = 0 #counter
# do the loop twice because we want to make em fall!
counter = 0
for i in range(0, source.size[0]-1): # loop through every x value
    vert_list = [] #list of this column
    for pix in range(0, source.size[1]-1): #make a list of the column from the b&w img
        color = blackandwhite[i, pix] #for being in color ^^
        vert_list.append( color )

    counter += 1
    if counter % 10 == 0:
        print(counter, "/", count)
    #now remove all pixels brighter than the threshold
    vert_list[:] = (x for x in vert_list if threshold > x)

    top_spacing = source.size[1] - len(vert_list) #height
    for pixel in range(0, len(vert_list)):
        newimg[i,pixel + top_spacing] = vert_list[pixel]


canvas.save("fall.png")

Upvotes: 0

Views: 1023

Answers (1)

abarnert
abarnert

Reputation: 365637

It looks like your problem is that you're trying to get back the color value (which you've discarded) from the greyscale value's index, but that isn't going to work when you've already discarded previous greyscale values and the indices no longer match up.

So let's start over. Instead of keeping a list of greyscale vertices and a list of color vertices and trying to match them up, let's just keep a list of (greyscale, color) pairs. Like this:

for pix in range(0, source.size[1]-1): #make a list of the column from the b&w img
    grey = blackandwhite[i, pix]
    color = img[i, pix]
    vert_list.append((grey, color))

Now, you just need to change the filter to use the grey value in the pair:

vert_list[:] = (x for x in vert_list if threshold > x[0])

… and change the newimg assignment to use the color value in the pair:

newimg[i,pixel + top_spacing] = vert_list[pixel][1]

And (other than changing the mode of the canvas, which you already got right), that's all you need to do.

I've posted a complete implementation here (with comments on the three changed lines).

Upvotes: 1

Related Questions