我正在使用Camera2 API,并希望检测捕获的图像是模糊或清晰,我使用OpenCV为此,但结果并不令人满意,它增加了APK大小3倍,所以有什么方法来检测模糊?
myzjeezk1#
测量图像聚焦/模糊涉及位图的像素或其至少一部分的迭代。虽然你不需要OpenCV来覆盖Android上位图的像素,但它不适合胆小的人。以高性能的方式这样做需要您使用JNI本地代码,或者像RenderScript这样的技术,因为在Java或Kotlin中迭代像素可能会太慢。有很多算法和技术可以用来测量焦点、清晰度或对比度,这是我用过的一种,效果相当不错。亮度是像素的发光度,即灰度像素值。您需要将每个像素转换为该焦点度量的灰度值。例如,使用以下公式:
pixelLuma = (red * 0.299) + (green * 0.587) + (blue * 0.114)
下面是一个建议的公式来衡量焦点分数:
FocusScore = Max({Video_Gradient}) / {Gray_Level_Dynamic_Range} * {Pixel_Pitch}
Max{Video_Gradient}=位图中相邻像素(x,y)之间 * 最大 * 亮度差异的度量。
例如:水平测量pixel[x] - pixel[x+1]垂直测量pixel[y] - pixel[y+1]
pixel[x] - pixel[x+1]
pixel[y] - pixel[y+1]
{Gray_Level_Dynamic_Range}=位图中N个最亮像素和N个最暗像素的平均值之差。N的典型值是64,在我的情况下,图像的工作功率约为1200 w x 500 h。较小的图像应使用较小的N。{像素间距}= 1 / DPI = 1/200 = 0.005
这将导致一个分数,更高的值更集中。你可以设定一个合理的门槛。下面是一段用C语言编写的代码:
int gradientHorizontal[256]; int *pGradientHorizontal = gradientHorizontal; int gradientVertical[256]; int *pGradientVertical = gradientVertical; int luminanceHistogram[256]; int *pLuminance = luminanceHistogram; int maxGradient = 0; for (int i = 0;i < 256;i++) { gradientHorizontal[i] = 0; gradientVertical[i] = 0; luminanceHistogram[i] = 0; } // pixel by pixel math... for (nRow = 0; nRow < height-1; nRow++) { nRowOffset = nRow * width; nNextRowOffset = (nRow+1) * width; for (nCol = 0; nCol < width-1; nCol++) { int gC = pixels[nRowOffset + nCol]; int gH = abs(gC - pixels[nRowOffset + nCol + 1]); int gV = abs(gC - pixels[nNextRowOffset + nCol]); pLuminance[gC]++; pGradientHorizontal[gH]++; pGradientVertical[gV]++; } } // find max gradient for (int i = 255;i >= 0;i--) { // first one with a value if ((gradientHorizontal[i] > 0) || (gradientVertical[i] > 0)) { maxGradient = i; break; } } // calculate dynamic range int rangeLow = 0; int rangeHi = 0; int p; p = 0; for (int i = 0;i < 256;i++) { if (luminanceHistogram[i] > 0) { if (p + luminanceHistogram[i] > VFOCUS_N) { rangeLow += (i * (VFOCUS_N - p)); p = VFOCUS_N; break; } p += luminanceHistogram[i]; rangeLow += (i * luminanceHistogram[i]); } } if (p) rangeLow /= p; p = 0; for (int i = 255;i >= 0;i--) { if (luminanceHistogram[i] > 0) { if (p + luminanceHistogram[i] > VFOCUS_N) { rangeHi += (i * (VFOCUS_N - p)); p = VFOCUS_N; break; } p += luminanceHistogram[i]; rangeHi += (i * luminanceHistogram[i]); } } if (p) rangeHi /= p; float mFocusScore = (float)fmin((float)maxGradient / (fabs((float)rangeHi - (float)rangeLow) * 0.005), 100.00);
低对焦分数意味着图像模糊。接近或超过100的值表示清晰的图像,上面的代码将分数限制在100。
1条答案
按热度按时间myzjeezk1#
测量图像聚焦/模糊涉及位图的像素或其至少一部分的迭代。
虽然你不需要OpenCV来覆盖Android上位图的像素,但它不适合胆小的人。以高性能的方式这样做需要您使用JNI本地代码,或者像RenderScript这样的技术,因为在Java或Kotlin中迭代像素可能会太慢。
有很多算法和技术可以用来测量焦点、清晰度或对比度,这是我用过的一种,效果相当不错。
亮度是像素的发光度,即灰度像素值。您需要将每个像素转换为该焦点度量的灰度值。例如,使用以下公式:
下面是一个建议的公式来衡量焦点分数:
Max{Video_Gradient}=位图中相邻像素(x,y)之间 * 最大 * 亮度差异的度量。
例如:
水平测量
pixel[x] - pixel[x+1]
垂直测量
pixel[y] - pixel[y+1]
{Gray_Level_Dynamic_Range}=位图中N个最亮像素和N个最暗像素的平均值之差。N的典型值是64,在我的情况下,图像的工作功率约为1200 w x 500 h。较小的图像应使用较小的N。
{像素间距}= 1 / DPI = 1/200 = 0.005
这将导致一个分数,更高的值更集中。你可以设定一个合理的门槛。
下面是一段用C语言编写的代码:
低对焦分数意味着图像模糊。接近或超过100的值表示清晰的图像,上面的代码将分数限制在100。