new recruit 21
new recruit 21

Reputation: 111

Python - Changing An Image's Contrast With For-Loop

I'm trying to create a for-loop function that will run through every pixel to add contrast to the image. I think I'm close, but right now the image only brightens. If possible, try your best to stick closely to what I have formulated already (FYI, I'm trying to avoid libraries like OpenCV). Thanks for any contributions.

def contrast(img):
   for x in range(img.size[0]):
       for y in range(img.size[1]):
           if (x, y) > 128:
              (r, g, b) = img.getpixel((x, y))  
              img.putpixel((x, y), (r+80, g+80, b+80))  
           else:
              if(x, y) < 128:
                 (r, g, b) = img.getpixel((x, y))  
                 img.putpixel((x, y), (r-80, g-80, b-80))

Upvotes: 2

Views: 2688

Answers (2)

martineau
martineau

Reputation: 123463

The problem you're having is that the (x, y) > 128 is comparing a tuple to a single value which is probably not what you want to. The other problem is img.getpixel((x, y)) returns a tuple of three separate color components for RGB images, not the brightness of pixel.

What you need is an image processing technique that will change the contrast of color images. I found an article titled Image Processing Algorithms Part 5: Contrast Adjustment that describes a simple way to do it.

Here's an implementation of it using the pillow version of PIL (the Python Imaging Library) module:

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):
        return 0 if v < 0 else 255 if v > 255 else v

    if Image.isStringType(img):  # file path?
        img = Image.open(img)
    if img.mode not in ['RGB', 'RGBA']:
        raise TypeError('Unsupported source image mode: {}'.format(img.mode))
    img.load()

    factor = (259 * (level+255)) / (255 * (259-level))
    for x in range(img.size[0]):
        for y in range(img.size[1]):
            color = img.getpixel((x, y))
            new_color = tuple(truncate(factor * (c-128) + 128) for c in color)
            img.putpixel((x, y), new_color)

    return img

result = change_contrast('test_image1.jpg', 128)
result.save('test_image1_output.jpg')
print('done')

Here's the results of a test run I did showing the before image on the left and the resulting image on the right — and it looks like it works:

screenshot of before and after images side-by-side

Upvotes: 1

orlp
orlp

Reputation: 117681

These lines:

if (x, y) > 128:

Should be comparing the brightness of a pixel to 128, and not pixel coordinates.

Upvotes: 2

Related Questions