繁体   English   中英

在Android中从相机捕获后,有什么方法可以检测图像是否模糊(OpenCV除外)

[英]Is there any way to detect image is Blurry after capturing from Camera in Android (Except OpenCV )

我正在使用 Camera2 API 并想检测捕获的图像是否模糊或清晰,为此我使用了 OpenCV,但结果并不令人满意,并且将 APK 大小增加了 3 倍,那么有什么方法可以检测模糊吗?

测量图像焦点/模糊涉及迭代位图的像素或其至少一部分。

虽然您不需要 OpenCV 在 Android 上迭代位图的像素,但它不适合胆小的人。 以一种高性能的方式执行此操作将需要您使用 JNI 本机代码,或者可能使用 RenderScript 之类的技术,因为在 Java 或 Kotlin 中迭代像素可能会太慢。

有许多算法和技术可用于测量焦距、锐度或对比度,这是我使用的一种并取得了相当成功的方法。

Luma 是像素的亮度,即灰度像素值。 您需要将每个像素转换为此焦点度量的灰度值。 例如使用 NTSC 公式:

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]

{Gray_Level_Dynamic_Range} = 位图中 N 个最亮像素和 N 个最暗像素的平均值之间的差异。 N 的典型值为 64,在我的情况下,处理大约 1200w x 500h 的图像。 较小的图像应该使用较小的 N。

{Pixel_Pitch} = 1 / DPI = 1/200 = 0.005

这将导致得分,更高的值更受关注。 您可以确定一个合理的阈值。

这是用 C 编写的代码片段:

  • 宽度 = 位图的宽度
  • 高度 = 位图的高度
  • 像素 = 大小为(宽 * 高)的字节数组,用于保存像素亮度值
  • VFOCUS_N = 64
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。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM