Android Studio 是否有任何方法来检测图像是模糊后,从Android相机捕获(除了OpenCV)

zu0ti5jz  于 2023-10-23  发布在  Android
关注(0)|答案(1)|浏览(118)

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

myzjeezk

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]

{Gray_Level_Dynamic_Range}=位图中N个最亮像素和N个最暗像素的平均值之差。N的典型值是64,在我的情况下,图像的工作功率约为1200 w x 500 h。较小的图像应使用较小的N。
{像素间距}= 1 / DPI = 1/200 = 0.005

这将导致一个分数,更高的值更集中。你可以设定一个合理的门槛。
下面是一段用C语言编写的代码:

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

相关问题