значения RGB и пикселей - PullRequest
1 голос
/ 30 марта 2020

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

 Normalize the brightness of the given Image img by:
  1. вычисление средней яркости изображения: - это можно сделать путем расчета средней яркости каждого пикселя в img (средняя яркость каждого пикселя представляет собой сумму значений красного, синего и зеленого пикселей, разделенных на 3 как деление с плавающей запятой) - средняя яркость изображения является суммой всех средние значения пикселей, разделенные на произведение ширины и высоты img

  2. , находим коэффициент, назовем его x, на который мы можем умножить среднюю яркость, чтобы получить значение 128.

  3. умножить цвета в каждом пикселе на этот коэффициент 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
    

    Я немного растерялся относительно того, что я делаю неправильно, может кто-то помочь?

Ответы [ 3 ]

2 голосов
/ 31 марта 2020

Вы действительно должны избегать циклов for при обработке изображений с Python, когда это возможно, потому что они очень медленные, подробные, труднее читать и с большей вероятностью содержат ошибки. Попробуйте использовать векторизованные Numpy функции или встроенные функции OpenCV или PIL.

#!/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')

Этот код работает на моей машине около 800 микросекунд, тогда как для любой версии с for l oop требуется примерно в 70 раз длиннее.

Исходное изображение:

enter image description here

Результат:

enter image description here

0 голосов
/ 30 марта 2020

Во-первых, спасибо paxdiablo за то, что он поделился своим ответом.

Я просто хотел бы улучшить ответ.

Расчет среднего можно оптимизировать используя понимание списка, например:

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

Итак, мой полный ответ будет таким:

Нормализация яркости данного изображения

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

0 голосов
/ 30 марта 2020

Ваш расчетный код для получения коэффициента кажется нормальным, обработка каждого пикселя для получения среднего значения суммы средних.

Однако ваш код модификации для регулировки яркости не выполняется в пределах аналогично l oop, поэтому он будет работать на один пиксель, и я даже не уверен, что пиксель даже в изображении. Вы должны сделать это также в пределах al oop:

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)

Это должно заменить третье-последнее и второе-последнее строки того, что у вас есть в данный момент (между x = ... и return ...) , В итоге вы получите:

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

Несколько других вещей, на которые стоит обратить внимание:

Во-первых, я не уверен, что возвращение img является здесь нужно делать правильно, если только pixels не является ссылкой (а не копией) пикселей на изображении. Вы также можете проверить это.

Кроме того, может возможно, что значение для [rgb] * x даст вам что-то на 1027 * больше , чем 255 наверняка наборы входных данных. Если это так, вы, вероятно, захотите зафиксировать их в диапазоне 0..255, чтобы этого не произошло. Что-то вроде (замена «нового материала» в коде выше):

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)
...