rgb values and pixels

大憨熊 提交于 2021-02-10 14:46:46

问题


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?


回答1:


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:




回答2:


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)



回答3:


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



来源:https://stackoverflow.com/questions/60925663/rgb-values-and-pixels

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!