Каковы некоторые методы для анализа яркости изображения с помощью Python?
Я хотел бы дать несколько советов по выполнению простого анализа изображений в Python. Мне нужно рассчитать значение для "яркости" изображения. Я знаю, что PIL - это библиотека goto, которая делает что-то подобное. Есть встроенная функция гистограммы.
Что мне нужно, так это значения "воспринимаемой яркости", которые я могу решить, если необходимы дальнейшие корректировки изображения. Итак, каковы основные методы, которые будут работать в этой ситуации? Должен ли я просто работать со значениями RGB, или гистограмма даст мне что-то достаточно близкое?
Одним из возможных решений может быть объединение этих двух значений и генерирование средних значений R,G и B с использованием гистограммы, а затем применение формулы "воспринимаемой яркости".
6 ответов
Используя методы, упомянутые в вопросе, я придумал несколько разных версий.
Каждый метод возвращает значение close, но не точно так же, как другие. Кроме того, все методы работают с одинаковой скоростью, кроме последней, которая значительно медленнее в зависимости от размера изображения.
Преобразовать изображение в оттенки серого, вернуть среднюю яркость пикселей.
def brightness( im_file ): im = Image.open(im_file).convert('L') stat = ImageStat.Stat(im) return stat.mean[0]
Преобразовать изображение в оттенки серого, вернуть RMS яркость пикселей.
def brightness( im_file ): im = Image.open(im_file).convert('L') stat = ImageStat.Stat(im) return stat.rms[0]
Среднее количество пикселей, а затем преобразовать в "воспринимаемую яркость".
def brightness( im_file ): im = Image.open(im_file) stat = ImageStat.Stat(im) r,g,b = stat.mean return math.sqrt(0.241*(r**2) + 0.691*(g**2) + 0.068*(b**2))
Среднеквадратичное значение пикселей, а затем преобразование в "воспринимаемую яркость".
def brightness( im_file ): im = Image.open(im_file) stat = ImageStat.Stat(im) r,g,b = stat.rms return math.sqrt(0.241*(r**2) + 0.691*(g**2) + 0.068*(b**2))
Рассчитайте "воспринимаемую яркость" пикселей, затем верните среднее значение.
def brightness( im_file ): im = Image.open(im_file) stat = ImageStat.Stat(im) gs = (math.sqrt(0.241*(r**2) + 0.691*(g**2) + 0.068*(b**2)) for r,g,b in im.getdata()) return sum(gs)/stat.count[0]
Обновить результаты теста Я запустил симуляцию на 200 изображениях. Я обнаружил, что методы № 2, № 4 дали почти идентичные результаты. Также методы № 3, № 5 были также почти идентичны. Метод № 1 внимательно следовал № 3, № 5 (за некоторыми исключениями).
Учитывая, что вы просто ищете среднее значение по всему изображению, а не значения яркости на пиксель, усреднение гистограммы PIL и применение функции яркости к выводу кажется лучшим подходом для этой библиотеки.
При использовании ImageMagick (с привязками PythonMagick) я бы предложил использовать команду identifier с установленным параметром "verbose". Это даст вам среднее значение для каждого канала, избавляя вас от необходимости суммировать и усреднять гистограмму - вы можете просто умножить каждый канал напрямую.
Приведенный ниже код даст вам уровень яркости изображения от 0 до 10.
1 вычислить среднюю яркость изображения после преобразования изображения в формат HSV с помощью opencv.
2 найдите, где находится это значение в списке диапазонов яркости.
import numpy as np
import cv2
import sys
from collections import namedtuple
#brange brightness range
#bval brightness value
BLevel = namedtuple("BLevel", ['brange', 'bval'])
#all possible levels
_blevels = [
BLevel(brange=range(0, 24), bval=0),
BLevel(brange=range(23, 47), bval=1),
BLevel(brange=range(46, 70), bval=2),
BLevel(brange=range(69, 93), bval=3),
BLevel(brange=range(92, 116), bval=4),
BLevel(brange=range(115, 140), bval=5),
BLevel(brange=range(139, 163), bval=6),
BLevel(brange=range(162, 186), bval=7),
BLevel(brange=range(185, 209), bval=8),
BLevel(brange=range(208, 232), bval=9),
BLevel(brange=range(231, 256), bval=10),
]
def detect_level(h_val):
h_val = int(h_val)
for blevel in _blevels:
if h_val in blevel.brange:
return blevel.bval
raise ValueError("Brightness Level Out of Range")
def get_img_avg_brightness():
if len(sys.argv) < 2:
print("USAGE: python3.7 brightness.py <image_path>")
sys.exit(1)
img = cv2.imread(sys.argv[1])
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
_, _, v = cv2.split(hsv)
return int(np.average(v.flatten()))
if __name__ == '__main__':
print("the image brightness level is:
{0}".format(detect_level(get_img_avg_brightness())))
Я думаю, что ваш лучший результат будет от преобразования RGB в оттенки серого, используя вашу любимую формулу, а затем взяв гистограмму этого результата. Я не уверен, будет ли более подходящим среднее значение или медиана гистограммы, но на большинстве изображений они, вероятно, похожи.
Я не уверен, как сделать преобразование в градациях серого в PIL, используя произвольную формулу, но я предполагаю, что это возможно.
Это можно сделать, преобразовав изображение BGR из cv2 в оттенки серого, а затем определив интенсивность - x и y - координаты пикселей. Это хорошо объяснено в этом https://docs.opencv.org/3.4/d5/d98/tutorial_mat_operations.html документе.
Scalar intensity = img.at<uchar>(y, x);
def calculate_brightness(image):
greyscale_image = image.convert('L')
histogram = greyscale_image.histogram()
pixels = sum(histogram)
brightness = scale = len(histogram)
for index in range(0, scale):
ratio = histogram[index] / pixels
brightness += ratio * (-scale + index)
return 1 if brightness == 255 else brightness / scale