我想在python中执行简单的图像分析。我需要计算图像“亮度”的值。我知道PIL是用于执行此类操作的goto库。有一个内置的直方图功能。
我需要的是"perceived brightness"值我可以决定是否需要进一步调整图像。那么在这种情况下哪些基本技术会起作用呢?我应该只使用RGB值,还是直方图能给我一些足够接近的东西?
一种可能的解决方案可能是将两者结合起来,并使用直方图生成平均R,G和B值,然后应用“感知亮度”公式。
答案 0 :(得分:43)
使用问题中提到的技术,我提出了几个不同的版本。
每个方法返回一个值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))
像素的RMS,然后转换为“感知亮度”。
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(除了少数例外)。
答案 1 :(得分:2)
鉴于您只是在寻找整个图像的平均值,而不是每像素亮度值,平均PIL的直方图并将亮度函数应用于输出似乎是该库的最佳方法。
如果使用ImageMagick(带PythonMagick绑定),我建议使用identify命令并设置“verbose”选项。这将为您提供每个通道的平均值,从而节省您对直方图求和和平均值的需要 - 您可以直接乘以每个通道。
答案 2 :(得分:1)
我认为您最好的结果将来自使用您喜欢的公式将RGB转换为灰度,然后获取该结果的直方图。我不确定直方图的均值或中位数是否更合适,但在大多数图像上它们可能相似。
我不确定如何使用任意公式在PIL中转换为灰度,但我猜它是可能的。
答案 3 :(得分:1)
下面的代码将为您提供0-10之间的图像亮度级别
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())))
答案 4 :(得分:0)
这可以通过将 BGR 图像从 cv2 转换为灰度,然后找到强度来完成 - x 和 y 是像素坐标。此 https://docs.opencv.org/3.4/d5/d98/tutorial_mat_operations.html 文档对此进行了很好的解释。
Scalar intensity = img.at<uchar>(y, x);