SHooDK
SHooDK

Reputation: 67

(Logical Indexing) Executing formula for RGBA values in numpy array

I'm trying to unpremultiply my png image by accessing values via logical indexing. Made it work in python for loop before but I can't get it done right by using logical indexing. (for loop takes up to 1 minute)

Getting my image in numpy array

img = Image.open('test.png')
matrix = numpy.array(img)

Changing values using common for loops

for line in matrix:
   for v in line:
       if v[3]:
           v[0] = (255 * v[0] + (v[3] / 2)) / v[3]
           v[1] = (255 * v[1] + (v[3] / 2)) / v[3]
           v[2] = (255 * v[2] + (v[3] / 2)) / v[3]

It ended up looking like this using logical indexing

height, width, depth = matrix.shape
r = matrix[0:height, 0:width//4, 0:1]
g = matrix[0:height, 0:width//4, 1:2]
b = matrix[0:height, 0:width//4, 2:3]
a = matrix[0:height, 0:width//4, 3:4]

matrix[0:height, 0:width//4, 0:1] = (255 * r + (a / 2)) / a
matrix[0:height, 0:width//4, 1:2] = (255 * g + (a / 2)) / a
matrix[0:height, 0:width//4, 2:3] = (255 * b + (a / 2)) / a

How do I change the desired values correctly? If there is a better than doing it with logical indexing, please enlighten me.

EDIT: Added example images

test.png test.png

what it looks like with for loop (desired result) test_unpm.png

what it looks like using indexing enter image description here

Upvotes: 1

Views: 331

Answers (2)

Divakar
Divakar

Reputation: 221614

Here's one approach -

matrix_out = matrix.astype(float)
vals = (255 * matrix_out[...,:3] + matrix_out[...,[3]]/2)/matrix_out[...,[3]]
mask = matrix[...,3]!=0
matrix[mask,:3] = vals[mask]

Thus, the updated values would be in matrix.

Upvotes: 1

Thomas Kühn
Thomas Kühn

Reputation: 9820

If I understand your problem correctly, this should do the job:

r = matrix[:,:,0]
g = matrix[:,:,1]
b = matrix[:,:,2]
a = matrix[:,:,3]

r[a>0] = ((255*r + (a/2))/a)[a>0]
g[a>0] = ((255*g + (a/2))/a)[a>0]
b[a>0] = ((255*b + (a/2))/a)[a>0]

EDIT:

This must be because of the dtype of your matrix. If you first change your matrix to float values, it should work:

matrix2 = matrix.astype(np.float)

r = matrix2[:,:,0]
g = matrix2[:,:,1]
b = matrix2[:,:,2]
a = matrix2[:,:,3]

r[a>0] = ((255*r + (a/2))/a)[a>0]
g[a>0] = ((255*g + (a/2))/a)[a>0]
b[a>0] = ((255*b + (a/2))/a)[a>0]

matrix_out = matrix2.astype(np.uint8)

The final result can then be found in matrix_out.

Upvotes: 1

Related Questions