1

I try to manually adjust the contrast of the image. The 2nd code works fine with me but it uses loop -> it's slow so I change to 1st code but get a different output.

I don't know what gone wrong because I assumed that these 2 are alike. Can somebody tell me what did I miss? Thanks a lot.

Code with no-loop

from PIL import Image

# level should be in range of -255 to +255 to decrease or increase contrast
def change_contrast(img, level):
    def truncate(v):
        v[v<0] = 0
        v[v>255] = 255
        return v

    img_c = np.reshape(img,(1,img.shape[0] *img.shape[1],3))[0].copy()
   
    

    factor = (259 * (level+255)) / (255 * (259-level))
    img_c = factor * (img_c-128) + 128
    img_c = truncate(img_c)

    return np.reshape(img_c,(img.shape[0] ,img.shape[1],3)).astype(np.uint8)

Code with loop

from PIL import Image

# level should be in range of -255 to +255 to decrease or increase contrast
def change_contrast(img, level):
    def truncate(v):
        v[v<0] = 0
        v[v>255] = 255
        return v

    img_c = np.reshape(img,(1,img.shape[0] *img.shape[1],3))[0].copy()
   
    factor = (259 * (level+255)) / (255 * (259-level))
    for x in range(img_c.shape[0]):
        color = img_c[x]
        new_color = truncate(np.asarray([int(factor * (c-128) + 128) for c in color]))
        img_c[x]=     new_color
    return np.reshape(img_c,(img.shape[0] ,img.shape[1],3))

Test code

a = PIL.Image.open('Test.jpg')
b = np.asarray(a)
Image.fromarray(change_contrast(b , 128))

Result:

Original

non_loop:

non_loop

loop:

loop

Solution: my original array has uint8 type which won't let you have negative numbers (ex: img_c - 128). Change to int should help!

Gotta check type more carefully.

0

1 Answer 1

1

The problem is that img is an unsigned integer uint8, so when you subtract 128, it would get clipped at 0 instead of going negative.

If you convert the image to int, it would work as expected:

a = PIL.Image.open('test.jpeg')
b = np.asarray(a).astype(int)
Image.fromarray(change_contrast(b, 128))

Here's also a shorter version of your function (you can use np.clip instead of a custom truncate function):

def change_contrast(img, level):
    img_c = img.astype(int).copy()
    factor = (259 * (level+255)) / (255 * (259-level))
    img_c = factor * (img_c - 128) + 128
    img_c = np.clip(img_c, 0, 255)
    return img_c.astype(np.uint8)

P.S. I've included astype(int) inside this function to ensure that it's signed integer, so you don't have to convert before passing the image to the function.

Sign up to request clarification or add additional context in comments.

1 Comment

Aghh! I forgot about "uint8". What a dumb question I asked!. Thanks for clearing my problem out.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.