添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

使用Python分析图像亮度的方法有哪些?

36 人关注

我想请教一下用Python进行简单的图像分析的问题。我需要计算一个图像的 "亮度 "值。我知道 PIL 是做这样的事情的首选库。它有一个内置的直方图函数。

我需要的是一个 "perceived brightness" 价值,我可以决定是否有必要对图像作进一步调整。那么,在这种情况下,有哪些基本的技术可以发挥作用?我是否应该只使用RGB值,或者直方图会给我足够接近的东西?

一个可能的解决方案是将两者结合起来,用直方图生成平均的R、G和B值,然后应用 "感知亮度 "公式。

4 个评论
是什么阻碍了你用PIL在Python中实现你所链接的算法?你是在问另一种算法,还是问如何使用PIL,还是问什么?
我只是想确定我没有错过一些明显的功能/模块,这些功能/模块已经在做这件事。看起来这种类型的东西应该已经存在了。
计算出一个人的感知亮度。 形象 与找到一个简单的颜色有根本的不同。 观看者可能更关心主体的亮度,但背景像素通常比主体像素多。
另一件事是,你可能想测量图像中的亮度范围。更鲜明的差异和更高的范围将导致更高的感知光线
python
image-processing
cmcginty
cmcginty
发布于 2010-08-16
6 个回答
cmcginty
cmcginty
发布于 2022-01-12
已采纳
0 人赞同

利用问题中提到的技术,我想出了几个不同的版本。

每个方法都返回一个接近的值,但与其他方法不完全相同。另外,所有方法的运行速度都差不多,除了最后一个方法,它的速度要慢得多,这取决于图像的大小。

  • 将图像转换为灰度,返回平均像素亮度。

    def brightness( im_file ):
       im = Image.open(im_file).convert('L')
       stat = ImageStat.Stat(im)
       return stat.mean[0]
    
  • 将图像转换为灰度,返回像素亮度的有效值。

    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(有几个例外)。

  • 只想评论一下速度:在我的测试中,就拿它们来说,方法2号、3号和4号的速度基本持平(处理20张不同大小的图片需要~140ms),方法1号只是稍微慢一些(~180ms),而方法5号真的很慢(~3505ms)。这是意料之中的事,但如果你在1号、3号和5号之间选择,可能应该宁可坚持使用3号。
    For me method #3 worked super fast and accurate (didn't experiment with the others though). For return values > 120.0 I consider the image to be bright, otherwise - not. And ~ 200.0 would be super-bright, ~ 20.0 - super dark.
    我需要额外做的是分别获得图像的波段,因为有些.png图像有r,g,b通道,有些则有-r,g,b,a通道。 band = stat.mean r = band[0] g = band[1] b = band[2] 。还有,不要忘记依赖性。 import math , from PIL import Image, ImageStat
    提出这些神奇数字的作者实际上指出,应该使用 (0.299, 0.587, 0.114) 而不是 (0.241, 0.691, 0.068) ,因为第一个数字更准确。请看这里的参考资料。 alienryderflex.com/hsp.html
    关于方法2,在计算RMS之前,将其转换为灰度作为一个归一化过程是否足够?wiki说 "假设输入图像的像素强度在[0, 1]范围内被标准化"。
    Andrew
    Andrew
    发布于 2022-01-12
    0 人赞同

    鉴于你只是在寻找整个图像的平均值,而不是每个像素的亮度值,对PIL的直方图进行平均,并将亮度函数应用于输出,似乎是该库的最佳方法。

    If using 形象化的Magick (with the 淘宝网 bindings), I would suggest using the identify 命令,并设置 "verbose "选项。这将为你提供每个通道的平均值,使你不必对直方图进行求和和平均--你可以直接将每个通道相乘。

    作为一个试图维护PythonMagick并提供0.9.1版本的人,我不建议在当前状态下使用它。最近ImageMagick的变化破坏了很多PythonMagick的代码。包的原作者想出了另一个ImageMagick的python绑定。 public.procoders.net/PythonMagickWand/docs/html/index.html 意思是说,它比目前的PythonMagick要好。
    Mark Ransom
    Mark Ransom
    发布于 2022-01-12
    0 人赞同

    我想你最好的结果是用你最喜欢的公式将RGB转换为灰度,然后取该结果的直方图。我不确定直方图的平均值或中位数是否更合适,但在大多数图像上它们可能是相似的。

    我不确定如何在PIL中使用任意公式进行灰度转换,但我猜测这是可能的。

    Ankit Gupta
    Ankit Gupta
    发布于 2022-01-12
    0 人赞同

    下面的代码将给你一个图像的亮度水平,从0-10。

    1- 使用opencv将图像转换为HSV格式后,计算图像的平均亮度。

    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())))
        
    hsh
    hsh
    发布于 2022-01-12
    0 人赞同

    这可以通过将BGR图像从cv2转换为灰度来完成,然后找到强度 - x和y是像素坐标。这里已经很好地解释了这一点 https://docs.opencv.org/3.4/d5/d98/tutorial_mat_operations.html document.

    Scalar intensity = img.at<uchar>(y, x);
        
    Ajay Beniwal
    Ajay Beniwal
    发布于 2022-01-12
    0 人赞同
    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):