简体   繁体   中英

rgb values and pixels

def normalize_brightness(img: Image) -> Image: """

 Normalize the brightness of the given Image img by:
  1. computing the average brightness of the picture: - this can be done by calculating the average brightness of each pixel in img (the average brightness of each pixel is the sum of the values of red, blue and green of the pixel, divided by 3 as a float division) - the average brightness of the picture is then the sum of all the pixel averages, divided by the product of the width and height of img

  2. find the factor, let's call it x, which we can multiply the average brightness by to get the value of 128.

  3. multiply the colors in each pixel by this factor x """

     img_width, img_height = img.size pixels = img.load() # create the pixel map h = 0 for i in range(img_width): for j in range(img_height): r, g, b = pixels[i, j] avg = sum(pixels[i, j]) / 3 h += avg total_avg = int(h / (img_width * img_height)) x = 128 // total_avg r, g, b = pixels[i, j] pixels[i, j] = (r * x, g * x, b * x) return img

    I am a little lost as to what I am doing wrong can someone help?

You really should avoid for loops when image processing with Python whenever possible because it is seriously slow, verbose, harder to read and more likely to contain errors. Try to use vectorised Numpy functions, or OpenCV or PIL built-in functions.

#!/usr/bin/env python3

from PIL import Image
import numpy as np

def normalize(im):
   """Normalise brightness of image"""

   # Convert to Numpy array
   na = np.array(im, dtype=np.float32)

   # Calculate average brightness
   avg = na.mean()

   # Calculate factor x
   x = 128 / avg

   # Scale whole array as float since likely fractional
   na *= x

   # Convert back to PIL Image and return
   return Image.fromarray(na.astype(np.uint8))

# Load image and normalize
im = Image.open('start.png').convert('RGB')
result = normalize(im)
result.save('result.png')

This code runs in around 800 microseconds on my machine whereas any version with a for loop requires around 70x longer.

Input image:

在此处输入图片说明

Result:

在此处输入图片说明

Your calculation code to get the factor seems okay, processing every pixel to get the average of sum of averages.

However, your modification code to adjust the brightness is not done within a similar loop so it will operate on one pixel, and I'm not even sure that pixel is even within the image. You should do that within a loop as well:

for i in range(img_width):
    for j in range(img_height):
        (r, g, b) = pixels[i, j]
        pixels[i, j] = (r * x, g * x, b * x)

This should replace the third-last and second-last lines of what you have at the moment (between x = ... and return ... ). So what you would end up with is:

img_width, img_height = img.size
pixels = img.load()  # create the pixel map
h = 0
for i in range(img_width):
    for j in range(img_height):
        r, g, b = pixels[i, j]
        avg = sum(pixels[i, j]) / 3
        h += avg
total_avg = int(h / (img_width * img_height))
x = 128 // total_avg

# == New stuff below
for i in range(img_width):
    for j in range(img_height):
        (r, g, b) = pixels[i, j]
        pixels[i, j] = (r * x, g * x, b * x)
# == New stuff above

return img

A few other things to look in to:

First, I'm not sure if returning img is the right thing to do here, unless pixels is a reference to (not copy of) the pixels in the image. You may want to check up on that as well.

Further, it may be possible that the value for [rgb] * x gives you something more than 255 for certain input data sets. If that's the case, you probably want to clamp them into the range 0..255 to ensure this doesn't happen. Something like (replacing the "new stuff" in the code above):

for i in range(img_width):
    for j in range(img_height):
        # Get original pixel.

        (r, g, b) = pixels[i, j]

        # Scale with upper limit.

        r = min(255, r * x)
        g = min(255, g * x)
        b = min(255, b * x)

        # Replace pixel with scaled one.

        pixels[i, j] = (r, g, b)

At first, thanks to paxdiablo for sharing his answer.

I would just like to improve on the answer.

The calculation of the average can be optimized using list comprehension like:

x = 128 // (sum([sum(pixels[i, j]) / 3 for i in range(img_width) for j in range(img_height)]) / (img_width * img_height))

So my complete answer will be:

Normalize the brightness of the given Image

img_width, img_height = img.size
pixels = img.load()  # create the pixel map

x = 128 // (sum([sum(pixels[i, j]) / 3 for i in range(img_width) for j in range(img_height)]) / (img_width * img_height))

for i in range(img_width):
    for j in range(img_height):
        r, g, b = pixels[i, j]
        pixels[i, j] = [min(255, r * x), min(255, g * x), min(255, b * x)]

return img

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM