如何通过直方图判断照片的曝光

作者: 蛙声一爿 | 来源:发表于2017-04-12 13:37 被阅读135次

原文链接


拿到一张照片,不管是黑白还是彩色,它的明暗分布总是最先刺激视觉系统的特征,无论是在拍摄还是后期处理过程中,我们都可以通过直方图直观地了解当前照片的明暗分布情况。

所谓的直方图其实就是一张照片中亮度值的统计分布结果。当下电子设备中常用的 RGB 色彩模式通常采用24比特模式(24 bits per pixel),即每个像素的 R、G、B 通道各由 8 bit 表示,因此 RGB 的取值范围是(0~255),通过统计一张照片中所有像素亮度值的分布,就可以获得其亮度直方图(对于黑白照片是亮度直方图,彩色照片则可以是三个通道各有一个直方图,不过彩色与黑白之间本来就是可以相互转换的)。

RGB_color_solid_cube.png

直方图只是粗暴地统计了所有像素的亮度水平,通过它很难直接推断出一张照片的曝光水平,一些大概的准则也只有在实践中结合经验才能有效运用。为了找到其中的关联,我去抓去了某摄影爱好者网站上的图片,其中每张图片会有不同的标签及点赞数,点赞数可以看做是对一张照片的评价,当然这一评价不只是针对曝光水平的,照片的主题、构图、色彩等等可能占有更大的比重,更有甚者,有些照片可能拥有非常诡异的曝光数据然而却具有更高的艺术价值。

考虑到这些原因,想要用点赞数量作为曝光水平好坏的指标本身就是一个大胆的假设,但是不试试怎么知道你错得有多离谱呢?(最后也证明这个假设是行不通的,本文权当是失败经验总结,不过还是有不少收获)

这次的尝试过程很简单,首先抓取数据和图片,然后提取直方图,最后找个机器学习算法进行分类。

数据

数据记录共 7.8w 条,粗略估算了一下,如果下载所有图片可能有近20G,考虑到这并不是一个非常严格的实验而且电脑容量有限,只过滤了点赞数超过50的照片,共约 1w 张,图片下载下来一共2G 左右。

预处理

NumPy 和 SciPy 来处理图片数据,Pandas 用作数据结构化存储与操作。

首先是提取图片的直方图信息,matplotlib 可以直接通过 hist 方法将直方图绘制出来,我们先看看评价排名靠前和靠后的照片有什么不同:

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

def display_images(images):
    fig = plt.figure(figsize=(10, 3*len(images)))
    grd = gridspec.GridSpec(len(images), 3)
    for i, img in enumerate(images):
        isGray = False
        if len(img.shape) == 2:
            isGray = True
        ax = fig.add_subplot(grd[i, 0])
        if isGray:
            ax.imshow(img, cmap=plt.cm.gray)
        else:
            ax.imshow(img)
        
        ax = fig.add_subplot(grd[i, 1])
        ax.hist(img.flatten(), bins=256, normed=1,fc='k', ec='k',range=(0.0,256))  
        ax.set_xlim(0, 255)
        
        if not isGray:
            ax = fig.add_subplot(grd[i, 2])
            ax.hist(img[:,:,0].flatten(), bins=256, normed=1, fc='r', ec='r')
            ax.hist(img[:,:,1].flatten(), bins=256, normed=1, fc='g', ec='g')
            ax.hist(img[:,:,2].flatten(), bins=256, normed=1, fc='b', ec='b')
            ax.set_xlim(0, 255)
    plt.tight_layout()
WX20170411-154931@2x.png WX20170411-155456@2x.png

前两张和后两张,评价数量2000和50好像还是有点差别的。

导入到 Pandas

计算直方图并更新到 DataFrame 中:

from sklearn.preprocessing import normalize
from scipy import misc
import numpy as np

def cal_lum_hist(imgid):
    try:
        p = "images/{}.jpg".format(imgid)
        img = misc.imread(p, flatten=True)
        hist, _ = np.histogram(img, bins=range(256))
        return normalize(hist.astype(np.float64).reshape(1, -1)).ravel()
    except BaseException as e:
        print(e)
        return None

ImageDF = ImageDF.imgid.apply(cal_lum_hist)

根据点赞数量计算分数,即给训练数据设定标签。这是比较重要的一步,直接决定了分类结果的好坏。最直接的方法是将样本平均分为两类(或多类),这样可以保持不同类别下样本数量的平衡。我第一次选择了分为三类(挺好、很好、非常好):

ImageDF.fav.quantile([0.3, 0.6])
"""
0.3     81
0.6    153
Name: fav, dtype: float64
"""

于是分别以此界线设定分数:

def cal_score(df, b, u):
    s = df.fav.quantile([b, u])
    def _inner(fav):
        if fav >= s[u]:
            return 2
        elif fav >= s[b]:
            return 1
        else:
            return 0
    return _inner
# 展示划分后样本数量
def score_size(df, n):
    for s in range(n):
        print("Score = {}, Size = {}".format(s, df[df['score'] == s].shape[0]))
ImageDF['score'] = ImageDF.fav.apply(cal_score(ImageDF, 0.3, 0.6))
score_size(imageDF, 3)
"""
Score = 0, Size = 3080
Score = 1, Size = 3102
Score = 2, Size = 4163
"""

然后分离训练样本和测试样本:

def data_split(df, n):
    return (
        (list(df[:n]['norm_hist']), list(df[:n]['score'])),
        (list(df[n:]['norm_hist']), list(df[n:]['score'])))

# 随机打乱顺序
ImageDF = ImageDF.reindex(np.random.permutation(ImageDF.index))

# 十折交叉验证
train, test = data_split(ImageDF, len(ImageDF) // 10 * 9)

# SVM
from sklearn import svm
clf = svm.SVC()
clf.fit(*train)
clf.score(*test)

以上就是一次训练、测试的流程,结果发现,准确率最高的情况也只是在50%附近徘徊。

Picture1.png

注:2:0:2和1:0:1 是二分类的结果。

总结

根据上面的结果来看,根据直方图推断图片曝光的假设是失败了。其中得到较高准确率的2:6:2(实际上如果是1:9:1准确率更是可以高达80%)明显是因为样本偏差。现在再来看一下点赞数量的分布情况:

download (1).png

很明显绝大部分点赞数量集中在我所截取的50左右,统计所有记录的评价结果:

AllRecordDF.fav.describe()
"""
count    78779.000000
mean        33.258470
std        101.544808
min          0.000000
25%          2.000000
50%          5.000000
75%         20.000000
max       2933.000000
Name: fav, dtype: float64
"""

75%的评价分数不过20,而平均分被拉到33,这本身就是一个非常不平衡的样本,而我又只截取了其中的一部分。

既然不能只考虑曝光水平,那就应该将整张图片的所有特征考虑在内,也许通过神经网络模型可以得到一个更好的预测结果,用来评价你新拍的照片水平如何,虽然这已经失去了直方图在拍摄过程中的实时指导意义。

相关文章

  • 用神经网络模型给你的照片打分(Part I)

    【原文链接】 在上一篇《如何通过直方图判断照片的曝光》中,我试图以用户对照片的评分作为评判标准,找出照片直方图与其...

  • 如何通过直方图判断照片的曝光

    【原文链接】 拿到一张照片,不管是黑白还是彩色,它的明暗分布总是最先刺激视觉系统的特征,无论是在拍摄还是后期处理过...

  • 了解直方图

    直方图是照片中曝光级别的图形表示,是判断曝光的好帮手。 这里的高低起伏,其实就是照片像素的明暗分布,左代表暗(Da...

  • 数码单反摄影轻松入门(2.5)

    巧用直方图判断曝光正确与否 前面讲到了曝光补偿是获得最佳曝光的重要手段,也讲到了在一些场合如何曝光补偿的一些技巧,...

  • PS笔记

    曲线:Ctrl+M 色阶:Ctrl+L 直方图:判断图片曝光,按住Alt进入阈值模式,进行更改 校正偏色的照片:取...

  • 单反摄影入门基础教程(12)——认识直方图

    相信你应该听说过或者看过直方图,可能感觉很难理解。简单说,直方图也是用来判断曝光的工具。 之所以要把直方图这个概念...

  • 直方图

    查看拍摄的照片的亮度,不要以液晶屏的现实来判断,因为液晶屏的亮度的是可调的鉴定照片的曝光和偏色的唯一依据就是直方图...

  • 理解直方图

    直方图是什么鬼 ◔ ‸◔?有什么用(⊙.⊙)? 一。直方图是什么? 是一种照片的分析方式,用来检查我们拍摄的曝光情...

  • 疯狂分享摄影技巧(二)

    我们继续 使用直方图 在数码摄影中,直方图是评估曝光准确度的最佳方法。液晶屏可能会误导。了解如何阅读直方图可能与思...

  • 零基础学习PhotoshopCS6︱第十六课 直方图

    1.直方图的作用:直方图是对照片的一种分析方式,通过直方图,可以对一张图片的明暗程度有一个准确的了解。 2.直方图...

网友评论

本文标题:如何通过直方图判断照片的曝光

本文链接:https://www.haomeiwen.com/subject/uwjuattx.html