看看这两个示例图片:
我希望能够在大量照片和类似图像中识别这些类型的图像。 photograph
我的意思是人物,风景,动物等的照片。
我不介意有些照片被错误地识别为uniform images
,但我真的不想通过将它们识别为照片来“遗漏”其中一些。
我想到的最简单的事情是逐个像素地分析图像以找到最高和最低的R,G,B值(每个通道分别)。如果最低值和最高值之间的差异很大,那么颜色变化很大,这样的图像可能是一张照片。
其他想法是以类似的方式分析每个像素的Hue值。问题是在HSL模型中,橙色红色和粉红色在顺时针方向看时差异大约为350度,逆时针方向看时差异为10度。所以我不能只比较每个像素的Hue组件,因为我会得到一些奇怪的结果。
此外,存在噪音问题 - 一个白色或黑色像素会破坏这样的测试。因此,如果只有极少数像素具有这样的极值,我将需要以某种方式排除极值。但是在这一点上它变得越来越复杂,我觉得这不是最好的方法。
我还在考虑将对比度与最大值进行对比,然后像我上面描述的RGB一样运行测试。它可能会使事情变得更容易,但仍然有一两个异常像素会破坏测试。如何处理此类案件?
我不介意运行几种不同的算法来覆盖不同的图像类型。但请注意,我正在处理来自数码相机的图像,所以6MP,12MP甚至16MP都很常见。因为运行计算密集型算法是不可取的。我处理数百甚至数千个图像,并且只有有限的CPU资源用于图像处理。让我们说每张大图片只有一两张是我能接受的最大值。
我知道,例如蓝天的照片可能会引发误报,但这没关系。误报比错过更好。
答案 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的结果:
正如您在查看完代码后所看到的那样,图像变为空白(全黑)。图像相当大,因此很难在一个窗口中显示所有内容。
示例2的结果你告诉我:
可以看到轮廓,但是解决此问题的一种方法是从图像的尺寸引入大约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)
这就是我要解决的问题:
答案 4 :(得分:0)
以下apprach可能有用。
在以每个像素为中心的5x5窗口中导出局部二进制模式。因此,对于一个像素,您有15个布尔值。在某个方向(顺时针或逆时针)计算数字1-0和0-1的变化。这是中心像素的特征值。
对于所有20x20窗口,导出像素特征值的方差。
如果您采用方差的方差,对于均匀图像,它应接近零。而对于其他图像,它会非常高。通过这种方式,可能没有必要修复阈值,局部二进制模式可以处理潜在的不均匀照明。
答案 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 - 训练分类器:既然您有照片和非照片图像的图像示例,您可以使用此信息来训练分类器。给定直方图的这个分类器可用于预测图像是否摄影。
如果您不想在分类器上花时间,可以尝试更简单的方法:
答案 7 :(得分:0)
以下是我的回答。我写了一个简单的演示来解释我的想法C.你可以在gist找到它。
就绪
制定一些定义:
#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]);
此功能可以:
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_count
。 min_count
应大于0。min_count
。