我试图判断某张照片是否模糊。我知道这基本上是一项不可能完成的任务,并且任何指标有时会返回不良结果。
我想知道是否有一个简单的指标,至少试图估计我可以使用的模糊。具体而言,该任务对误报具有很高的容忍度。例如如果我得到的东西可以消除90%的模糊照片和50%的非模糊照片,我会非常高兴。
我正在尝试用Java实现它。我有一个像素数组(作为整数)。请记住,我对图像处理技术(傅里叶变换等)的理解有限,我希望能够对如何编写解决方案进行非常具体的演练。
正如您所说,您不会找到通用指标。
还有不同类型的模糊:均匀,各向异性,运动模糊......
通常,模糊图像倾向于表现出低频。可能的描述符是k个最高频率的幅度之和。具有低总和的图像可能总体上模糊。
可以使用傅立叶频谱(高频远离原点)或Laplace pyramid(高频对应于第一标度)在N * log(N)时间内获得幅度。
Wavelet变换是另一种可能的描述符
一个非常简单的措施是应用Sobel滤波器并研究滤波图像的整体能量。图像越模糊,边缘消失越多,滤波图像的能量越小。当你试图确定模糊和不模糊的阈值时,你会遇到这种方法的问题,但也许这个简单的方法会给你一个想法。
查看维基百科的Sobel过滤器,这是一个代码片段,用于获取图像的边缘比率。您可以使用这些边缘比率来配对比较图像是否具有更多或更少的边缘。不过,请记住,这是一个简单的方法,a.lasram的答案肯定是正确的。
float[] sobelX = {
-1, 0, 1,
-2, 0, 2,
-1, 0, 1,
};
BufferedImage image = ImageIO.read(new File("test.jpg"));
ColorConvertOp grayScaleOp = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
BufferedImage grayImage = grayScaleOp.filter(image, null);
BufferedImageOp op = new ConvolveOp( new Kernel(3, 3, sobelX) );
BufferedImage result = op.filter(grayImage, null);
WritableRaster r = result.getRaster();
int[] pixel = new int[r.getWidth()];
double countEdgePixels = 0;
for (int y = 0; y<r.getHeight();y++) {
// System.out.println("y = " + y);
r.getPixels(0, y, r.getWidth(),1, pixel);
for (int i = 0; i < pixel.length; i++) {
// create some stat out of the energy ...
if (pixel[i] > 128) {
countEdgePixels++;
}
}
}
System.out.printf("Edge pixel ratio = %4.4f\n", countEdgePixels/(double) (r.getWidth()*r.getHeight()));
ImageIO.write(result, "png", new File("out.png"));