检测(很可能)不是照片的均匀图像

时间:2014-02-13 15:31:01

标签: algorithm image-processing computer-vision

看看这两个示例图片:Some background image Sticky tape

我希望能够在大量照片和类似图像中识别这些类型的图像。 photograph我的意思是人物,风景,动物等的照片。

我不介意有些照片被错误地识别为uniform images,但我真的不想通过将它们识别为照片来“遗漏”其中一些。

我想到的最简单的事情是逐个像素地分析图像以找到最高和最低的R,G,B值(每个通道分别)。如果最低值和最高值之间的差异很大,那么颜色变化很大,这样的图像可能是一张照片。

其他想法是以类似的方式分析每个像素的Hue值。问题是在HSL模型中,橙色红色和粉红色在顺时针方向看时差异大约为350度,逆时针方向看时差异为10度。所以我不能只比较每个像素的Hue组件,因为我会得到一些奇怪的结果。

此外,存在噪音问题 - 一个白色或黑色像素会破坏这样的测试。因此,如果只有极少数像素具有这样的极值,我将需要以某种方式排除极值。但是在这一点上它变得越来越复杂,我觉得这不是最好的方法。

我还在考虑将对比度与最大值进行对比,然后像我上面描述的RGB一样运行测试。它可能会使事情变得更容易,但仍然有一两个异常像素会破坏测试。如何处理此类案件?

我不介意运行几种不同的算法来覆盖不同的图像类型。但请注意,我正在处理来自数码相机的图像,所以6MP,12MP甚至16MP都很常见。因为运行计算密集型算法是不可取的。我处理数百甚至数千个图像,并且只有有限的CPU资源用于图像处理。让我们说每张大图片只有一两张是我能接受的最大值。

我知道,例如蓝天的照片可能会引发误报,但这没关系。误报比错过更好。

8 个答案:

答案 0 :(得分:3)

这是我怎么做的(下面的整个方法,在帖子的底部,但只是从上到下阅读):

你的引言:

  

“照片是指人物,风景,动物的照片   等“。

我对你的报价的回应:

  

这意味着此类图像具有边缘,轮廓。你是的形象   试图分开,没有边缘或小轮廓(对于第二个   至少示例图片)

你的引言:

  

一个白色或黑色像素会破坏这样的测试。所以我需要   如果只有少数像素,则以某种方式排除极值   极端

我的回答:

  

通过诸如DoG(高斯差分)等方法来最小化噪声将减少噪声   嘈杂的单个像素

所以我拍摄了你的照片并通过以下代码运行:

cv::cvtColor(image, imagec, CV_BGR2GRAY); // where image is the example image you shown
cv::GaussianBlur(imagec,imagec, cv::Size(3,3), 0, 0, cv::BORDER_DEFAULT ); //blur image
cv::Canny(imagec, imagec, 20, 60, 3);

您给出的示例图片1的结果: enter image description here

正如您在查看完代码后所看到的那样,图像变为空白(全黑)。图像相当大,因此很难在一个窗口中显示所有内容。

示例2的结果你告诉我: enter image description here

可以看到轮廓,但是解决此问题的一种方法是从图像的尺寸引入大约20到30个像素的ROI,因此,例如,如果图像尺寸是640x320,则ROI可以是610x 290 ,它放在图像的中心。

现在,让我向您介绍我的真实方法:

  

1)通过上面的代码运行所有图像以找到边

     

2)检查哪些图像没有任何边缘(没有边缘的图像)   将具有0像素,其值大于0或小像素,其值大于0,因此设置稍高的阈值以使其安全吗?您可以相应地调整,识别图像的像素数量)

     

3)保存/命名所有没有边缘的图像,这将是图像   你试图将其与其他人分开。

     

4)结束。

编辑(回答评论,会回复,但我的答复太长了):

关于模糊部分的真实情况。为了最大限度地减少模糊的使用,您可以先进行“类似消除过程”,这样图像1中那些平滑的图像就已经分离并分类为您要查找的图像。

从那里开始对剩余图像进行第二次测试,这将是“模糊”。

如果您真的希望避免模糊,我注意到您的示例图像1可以归类为“光滑表面”,而您的示例图像2可以归类为“粗糙表面”,这意味着它是嘈杂的,这让我首先介绍了模糊。

根据我的经验,如果我没记错的话,这种粗糙的表面在“分水岭”或“通过颜色聚类”方法中表现非常好,它们很好地融合在一起,与光滑的图像不同。

由于剩余的图像很难有粗糙的图像,你可以尝试使用分水岭方法,如果我没有错,你会发现它是一个黑色的图像。尝试一下这样的一行:

pyrMeanShiftFiltering( image, images, 10, 20, 3)

我不太确定这种方法是否比高斯模糊更昂贵。但你可以尝试两者并比较两者的计算速度。

关于您对灰度图像的评论:

  

转换为灰度声音有风险 - 丢失颜色信息可能会   触发很多误报

我的回答:

  

我真的不这么认为。如果您想要分割图像   是一种颜色,改变灰度无关紧要。当然,如果   你拍了一张蓝天的照片,这可能会导致误报,   但正如你所说,那些都没关系。

     

如果你想一想,里面有人等图像的强度   变化差异很大。 (当然除非你的照片有   极端的情况,就像在草地上的绿球一样)

     

我承认转换为灰度会丢失信息。但在你的   例如,我怀疑它会影响很多,事实上,使用灰度   图像更快,更便宜。

答案 1 :(得分:2)

我会使用基于熵的方法。我没有任何自定义代码可供分享,但以下博客条目应该会让您朝着正确的方向前进。

http://envalo.com/image-cropping-php-using-entropy-explained/

事实是,与那些有趣的东西相比,均匀图像的熵会非常低。

所以问题是找到正确的阈值并处理整个集合。

答案 2 :(得分:1)

我会为每张图片生成颜色直方图,并比较它们与给定图案的差异程度。

也许您想先将亮度标准化以简化匹配。

答案 3 :(得分:1)

这就是我要解决的问题:

  • 查找图像中的平均R,G和B值
  • 计算每个像素的值,该值是每个通道与平均值之差的总和
  • 删除前0.1%的值以忽略异常值
  • 检查最大剩余差异与阈值(您可能需要通过反复试验来确定此阈值)

答案 4 :(得分:0)

以下apprach可能有用。

  1. 在以每个像素为中心的5x5窗口中导出局部二进制模式。因此,对于一个像素,您有15个布尔值。在某个方向(顺时针或逆时针)计算数字1-0和0-1的变化。这是中心像素的特征值。

  2. 对于所有20x20窗口,导出像素特征值的方差。

  3. 如果您采用方差的方差,对于均匀图像,它应接近零。而对于其他图像,它会非常高。通过这种方式,可能没有必要修复阈值,局部二进制模式可以处理潜在的不均匀照明。

答案 5 :(得分:0)

对于每个R,G,B通道,计算强度的标准偏差。如果它足够低,你就会有一个统一的图像。

如果您担心具有不同的均匀区域,请分别计算每个20x20平方的标准偏差,然后计算标准偏差的平均值。

答案 6 :(得分:0)

您可以使用机器学习(分类)解决您的问题。它听起来比听起来容易。我举一个例子:

1 - 特征提取:从所有图像计算颜色直方图(RGB值的直方图)。可能你会想要减少R,G和B的可能值的数量,所以你的直方图不会增长这么大(这被称为重新量化)。例如,你可以制作一个直方图,它接受4个不同的R,G和B值,产生一个带有4 * 4 * 4箱的直方图:[(R = 1,G = 1,B = 1),(R = 1 ,G = 1,B = 2),......(R = 4,G = 4,B = 4)]。

2 - 手动标记一些不知道照片的图像。

3 - 训练分类器:既然您有照片和非照片图像的图像示例,您可以使用此信息来训练分类器。给定直方图的这个分类器可用于预测图像是否摄影。

如果您不想在分类器上花时间,可以尝试更简单的方法:

  • 计算图像中的直方图您想知道它是否是摄影;
  • 将It的直方图与所有标记图像的直方图进行比较,找到最相似的直方图(例如,您可以对二元箱之间的差异求和);
  • 如果具有最相似直方图的图像是摄影,则将图像分类为摄影。否则,将其归类为不是摄影

答案 7 :(得分:0)

以下是我的回答。我写了一个简单的演示来解释我的想法C.你可以在gist找到它。

就绪

  • 一种颜色/像素包含三个通道(如果您有alpha数据,则为四个通道)
  • 每个频道共有8位(256)

制定一些定义:

#define IMAGEWIDTH      20 // Assumed
#define IMAGEHEIGHT     20 // Assumed
#define CHANNELBIT      8
#define COLORLEVEL      256

typedef struct tagPixel
{
    unsigned int R : CHANNELBIT;
    unsigned int G : CHANNELBIT;
    unsigned int B : CHANNELBIT;
} Pixel;

为每个频道中的每个COLORLEVEL收集每个颜色计数:

void TraverseAndCount(Pixel image_data[IMAGEWIDTH][IMAGEHEIGHT]
    , unsigned int red_counts[COLORLEVEL]
    , unsigned int green_counts[COLORLEVEL]
    , unsigned int blue_counts[COLORLEVEL]);

下一步非常重要。 分析颜色数

// just a very simple way to smooth the curve of the counts of colors
// and you can replace it with another way you want
unsigned int CalculateRange(unsigned int min_count
    , unsigned int blur_size
    , unsigned int color_counts[COLORLEVEL]);

此功能可以:

  • i平滑每个通道计数的曲线 - COLORLEVEL blur_size(你可以用另一种方式来平滑它)
  • 计算超过min_count
  • 的计数范围

最后,计算每个频道的平均范围:

// calculate the average of the range for each channel of color
// the value is bigger if the image is more probably photographs
float AverageRange(unsigned int min_count, unsigned int blur_size
    , unsigned int red_counts[COLORLEVEL]
    , unsigned int green_counts[COLORLEVEL]
    , unsigned int blue_counts[COLORLEVEL]);

注意:

  • 结果取决于min_countmin_count应大于0。
  • 更大的结果更可能是图片是照片。
  • 对于照片,更大的结果更可能是较小的min_count