Home > OS >  Why isn't Python writing elements from one 3-D list to another?
Why isn't Python writing elements from one 3-D list to another?

Time:09-24

I'm trying to create a program that creates an average out of an image by looping through each RGBA value in two images to average them out and create one composite image, but the right value isn't being written to my list comp_img, which contains all the new image data.

I'm using these 256x256 images for debugging.
Text Text

But it just creates this as output:

Text

While this is the composite color, the 64 gets wiped out entirely. Help is very much appreciated, thank you.

from PIL import Image
import numpy as np
from math import ceil
from time import sleep

red = Image.open("64red.png")
grn = Image.open("64green.png")
comp_img = []

temp = [0,0,0,0] #temp list used for appending
#temp is a blank pixel template
for i in range(red.width):
    comp_img.append(temp)
    
temp = comp_img
#temp should now be a row template composed of pixel templates
#2d to 3d array code go here
comp_img = []
for i in range(red.height):
    comp_img.append(temp)

reddata = np.asarray(red)
grndata = np.asarray(grn)

reddata = reddata.tolist() #its uncanny how easy it is
grndata = grndata.tolist()

for row, elm in enumerate(reddata):
    for pxl, subelm in enumerate(elm):
        for vlu_index, vlu in enumerate(subelm):
            comp_img[row][pxl][vlu_index] = ceil((reddata[row][pxl][vlu_index]   grndata[row][pxl][vlu_index])/2)
            #These print statements dramatically slowdown the otherwise remarkably quick program, and are solely for debugging/demonstration.
            


output = np.array(comp_img, dtype=np.uint8) #the ostensible troublemaker
outputImg = Image.fromarray(output)
outputImg.save("output.png")

CodePudding user response:

You really should work with just NumPy arrays and functions, but I'll explain the bug here. It's rooted in how you make the nested list. Let's look at the first level:

temp = [0,0,0,0] #temp list used for appending
#temp is a blank pixel template
for i in range(red.width):
    comp_img.append(temp)

At this stage, comp_img is a list with size red.width whose every element/pixel references the same RGBA-list [0,0,0,0]. I don't just mean the values are the same, it's one RGBA-list object. When you edit the values of that one RGBA-list, you edit all the pixels' colors at once.

Just fixing that step isn't enough. You also make the same error in the next step of expanding comp_img to a 2D matrix of RGBA-lists; every row is the same list.

If you really want to make a blank comp_img first, you should just make a NumPy array of a numerical scalar dtype; there you can guarantee every element is independent:

comp_img = np.zeros((red.height, red.width, 4), dtype = np.uint8)

If you really want a nested list, you have to properly instantiate (make new) lists at every level for them to be independent. A list comprehension is easy to write:

comp_img = [[[0,0,0,0] for i in range(red.width)] for j in range(red.height)]

CodePudding user response:

You could simply do

comp_img = np.ceil((reddata   grndata) / 2)

This gives me

enter image description here

To get correct values it needs to work with 16bit values - because for uint8 it works only with values 0..255 and 255 255 gives 254 instead of 510 (it calculates it modulo 256 and (255 255) % 256 gives 254)

reddata = np.asarray(red, dtype=np.uint16)
grndata = np.asarray(grn, dtype=np.uint16)

and then it gives

enter image description here

from PIL import Image
import numpy as np

red = Image.open("64red.png")
grn = Image.open("64green.png")

reddata = np.asarray(red, dtype=np.uint16)
grndata = np.asarray(grn, dtype=np.uint16)

#print(reddata[128,128])
#print(grndata[128,128])

#comp_img = (reddata   grndata) // 2
comp_img = np.ceil((reddata   grndata) / 2)

#print(comp_img[128,128])

output = np.array(comp_img, dtype=np.uint8)
outputImg = Image.fromarray(output)
outputImg.save("output.png")
  • Related