如何检测图像是照片,剪贴画还是线条图?

识别图像类型的最佳方法是什么? rwong对这个问题 的 回答表明Google将图像分为以下几组:

  • 照片 – 连续色调
  • 剪贴画 – 光滑的阴影
  • 画线 – 双色调

将图像分类为其中一个组的最佳策略是什么? 我目前正在使用Java,但欢迎任何一般方法。

谢谢!


更新:

我尝试了tyjkenn在评论中提到的独特颜色计数方法,它似乎适用于我尝试过的大约90%的案例。 特别是使用独特的颜色计数难以正确地检测黑白照片。

获取图像直方图并单独计算窥视图似乎不是一个可行的选择。 例如,此图像只有两个峰值:

这是我检查过的另外两张图片:

这个问题可以通过图像分类来解决,这可能是谷歌解决问题的方法。 基本上,你要做的是(i)获得一组标记为3类的图像:照片,剪贴画和线条画; (ii)从这些图像中提取特征; (iii)使用图像的特征和标签来训练分类器。

特征提取:

在此步骤中,您必须提取可能对分类器有用的视觉信息,以区分3类图像:

  • 一个非常基本但有用的视觉特征是图像直方图及其变体。 例如,照片的灰度直方图可能比剪贴画的直方图更平滑,其中您的区域可能具有相同的颜色值。
  • 可以使用的另一个特征是将图像转换到频域(例如,使用FFT或DCT )并测量高频分量的能量。 由于线条图可能会有明显的颜色过渡,因此其高频成分往往会积累更多能量。

还可以使用许多其他特征提取算法 。

训练分类器:

在特征提取阶段之后,我们将为每个图像提供一个数值向量(让我们称之为图像特征向量)及其元组。 这是训练分类器的合适输入。 至于分类器,可以考虑神经网络 , SVM 等 。

分类:

现在我们有一个训练有素的分类器,对图像进行分类(即检测图像类别),我们只需要提取其特征并将其输入分类器,它将返回其预测的类别

直方图是第一种方法。
将彩色图像转换为灰度并计算直方图。 一个非常双模态的直方图,黑色(或深色)和白色(或右)有2个尖峰,可能有更多的白色,是画线的良好指示。
如果你只有几个峰值,那么它很可能是一个剪贴画类型的图像。
否则这是一张照片。

相当简单但有效的方法来区分图纸和照片。 将它们组合使用可获得最佳精度:

1)Mime类型或文件扩展名

PNG通常是剪贴画或绘画,而JPEG主要是照片。

2)透明度

如果图像具有Alpha通道,则很可能是绘图。 如果存在alpha通道,您还可以迭代所有像素以检查是否确实使用了透明度。 这是一个Python示例代码:

from PIL import Image img = Image.open('test.png') transparency = False if img.mode in ('RGBA', 'RGBa', 'LA') or (img.mode == 'P' and 'transparency' in img.info): if img.mode != 'RGBA': img = img.convert('RGBA') transparency = any(px for px in img.getdata() if px[3] < 220) print 'Transparency:', transparency 

3)颜色分布

剪贴画通常具有相同颜色的区域。 如果一些颜色构成图像的重要部分,则它相当于绘图而不是照片。 此代码输出由十种最常用颜色制成的图像区域的百分比(Python示例):

 from PIL import Image img = Image.open('test.jpg') img.thumbnail((200, 200), Image.ANTIALIAS) w, h = img.size print sum(x[0] for x in sorted(img.convert('RGB').getcolors(w*h), key=lambda x: x[0], reverse=True)[:10])/float((w*h)) 

您需要调整和优化这些值。 十种颜色足以满足您的数据需求吗? 什么百分比最适合你。 通过测试大量样本图像找出它。 30%或更多通常是剪贴画。 不过,不是为了天空照片或喜欢。 因此,我们需要另一种方法 - 下一种方法。

4)通过FFT进行锐边检测

锐边导致傅立叶频谱中的高频。 通常在图纸(另一个Python代码段)中可以找到这些function:

 from PIL import Image import numpy as np img = Image.open('test.jpg').convert('L') values = abs(numpy.fft.fft2(numpy.asarray(img.convert('L')))).flatten().tolist() high_values = [x for x in values if x > 10000] high_values_ratio = 100*(float(len(high_values))/len(values)) print high_values_ratio 

此代码为您提供每个区域超过一百万的频率数。 再次:根据您的样本图像优化这些数字。

为您的图像集组合并优化这些方法。 如果您能改进这一点,请告诉我 - 或者只是编辑此答案。 我想自己改进一下:-)

除了颜色直方图之外,还要考虑边缘信息和整个图像中线宽的一致性。

照片 – 自然边缘将具有各种边缘强度,并且不太可能存在许多平行边缘。

剪贴画 – 分水岭算法可以帮助识别一致亮度的大型连通区域。 在用于高可见度的剪贴画和合成图像中,更可能是完美的直线和平行线。 边缘强度的直方图可能具有一些非常强的峰值。

线条图 – 合成线可能具有非常一致的宽度。 笔画宽度变换可以帮助您识别笔画。 (其中一个基本原则是找到相互“指向”的边缘梯度。)边缘强度的直方图可能只有一个强峰。