旧款Android相机的简单图像校正

时间:2017-11-21 16:33:06

标签: java android android-camera2

我有一个Android应用程序,我试图让用户使用本机相机捕获文档的图像,然后将其发送到服务器以使其成为黑白。

在Android应用程序中,我正在关注this example从相机拍摄完整尺寸的照片。

我遇到的问题是旧的Nexus 4相机会产生较暗的图像,因此部分文档会变成黑色而不是白色(大部分位于文档的边缘)。但是使用更新的Nexus 6相机没有问题。

使用this code更改对比度/亮度非常有助于提高Nexus 4图像的质量,但可以清除较新的Nexus 6图像。

是否有办法从较旧的Android设备自动检测较暗,质量较差的图像,以便仅对这些图像应用图像校正?

简单地用this code计算图像的平均亮度会因文档周围背景暗的可能性而被抛弃。

2 个答案:

答案 0 :(得分:0)

可能,标准不是亮度,而是对比度。无论如何,挑战是艰难的,你不能指望完美的流程,但要准备好通过反复试验来处理它。

尝试拍摄具有正常对比度的照片;如果失败,请设置一个标志,以便下次使用额外的亮度。请注意,野外设备可能会有非常不同的相机行为,即使使用同一部手机,照片条件也会有所不同。

您可以将Nexus 4的标志初始化为高亮度。实际上,我不确定这是否适用于所有Nexus 4设备,或仅适用于某些设备。

如果您的应用程序将被大量使用,您可以收集每个模型的统计信息,并在安装应用程序时将其应用为初始猜测。

答案 1 :(得分:0)

我最终在C ++ OpenCV中找到了这个algorithm,我在后端服务器上用Java编写了一个实现。它似乎很好地处理来自旧相机的较暗图像。虽然它似乎只适用于JPG图像,但不适用于PNG。

private BufferedImage autoCorrectBrightnessAndContrast(final BufferedImage image) {
    final int[] histogram = makeHistogram(image);

    if (LOG.isDebugEnabled()) {
        LOG.debug("Histogram: {}", Arrays.toString(histogram));
    }

    final int[] cumulativeHistogram = getCumulativeHistogram(histogram);
    /*
     * Finding the minimum and maximum indices in the histogram where the value at the index is greater than a given
     * threshold, computed from CLIP_PERCENT.
     */
    final int min = getMinIndex(cumulativeHistogram);
    final int max = getMaxIndex(cumulativeHistogram);
    LOG.debug("Min: {} Max: {}", min, max);

    /*
     * alpha is the scaling factor, or the amount that we need to expand the histogram graph horizontally so that it
     * fills the entire width. Essentially increasing contrast.
     */
    double alpha = 1;
    if (max != min) {
        alpha = MAX_COLOR / (double) (max - min);
    }
    /*
     * beta is the translating factor, or the amount that we need to slide the histogram graph left or right so that
     * it lines up with the origin. Essentially adjusting brightness.
     */
    final double beta = -min * alpha;

    return adjustBrightnessAndContrast(image, alpha, beta);
}

/**
 * Creates an int array of length MAX_COLOR representing a histogram from the input image. Each index represents the
 * number of pixels of that greyscale shade in the image.
 * 
 * @param image
 *            the bufferedImage to create a histogram from.
 * @return an int array represenation of the histogram.
 * 
 * @see <a href="https://stackoverflow.com/a/10109389/1088659">Plot a histogram for a buffered image</a>
 */
private static int[] makeHistogram(final BufferedImage image) {
    final int[] histogram = new int[MAX_COLOR];

    final ColorSpace colorSpace = image.getColorModel().getColorSpace();
    LOG.debug("Color space type: {}, is RGB = {}", colorSpace.getType(), colorSpace.isCS_sRGB());

    for (int x = 0; x < image.getWidth(); x++) {
        for (int y = 0; y < image.getHeight(); y++) {
            final int color = image.getRGB(x, y);
            final int red =   (color & 0x00ff0000) >> 16;
            final int green = (color & 0x0000ff00) >> 8;
            final int blue =   color & 0x000000ff;
            // Constructing a weighted average of the three color bands
            // based on how much they contribute to the overall brightness
            // of a pixel. (Relative luminance - https://en.wikipedia.org/wiki/Relative_luminance)
            final double greyscaleBrightness = .2126 * red + .7152 * green + .0722 * blue;
            histogram[(int) greyscaleBrightness]++;
        }
    }
    return histogram;
}

/**
 * @param histogram
 * @return an int array representing the cumulative histogram of the given histogram.
 * @see <a href="https://en.wikipedia.org/wiki/Histogram#Cumulative_histogram">Cumulative Histogram</a>
 */
private static int[] getCumulativeHistogram(final int[] histogram) {
    final int[] cumulativeHistogram = new int[histogram.length];

    cumulativeHistogram[0] = histogram[0];
    for (int i = 1; i < histogram.length; i++) {
        cumulativeHistogram[i] = cumulativeHistogram[i - 1] + histogram[i];
    }
    return cumulativeHistogram;
}

/**
 * @param cumulativeHistogram
 * @return the minimum index where the cumulative histogram goes above the threshold set by CLIP_PERCENT.
 */
private static int getMinIndex(final int[] cumulativeHistogram) {
    final int maxValue = cumulativeHistogram[cumulativeHistogram.length - 1];
    final double clipThreshold = CLIP_PERCENT * (maxValue / 100.0) * .5;
    int minIndex = 0;

    while (cumulativeHistogram[minIndex] < clipThreshold) {
        minIndex++;
    }
    return minIndex;
}

/**
 * @param cumulativeHistogram
 * @return the maximum index where the cumulative histogram goes below the threshold set by CLIP_PERCENT.
 */
private static int getMaxIndex(final int[] cumulativeHistogram) {
    final int maxValue = cumulativeHistogram[cumulativeHistogram.length - 1];
    final double clipThreshold = CLIP_PERCENT * (maxValue / 100.0) * .5;
    int maxIndex = cumulativeHistogram.length - 1;

    while (cumulativeHistogram[maxIndex] >= maxValue - clipThreshold) {
        maxIndex--;
    }
    return maxIndex;
}

/**
 * @param image
 * @param alpha
 *            the scaling factor to adjust the contrast.
 * @param beta
 *            the offset factor to adjust the brightness.
 * @return the adjusted image.
 */
private static BufferedImage adjustBrightnessAndContrast(final BufferedImage image, final double alpha, final double beta) {
    BufferedImage processedImage = new BufferedImage(image.getWidth(), image.getHeight(), image.getType());
    processedImage = new RescaleOp((float) alpha, (float) beta, null).filter(image, processedImage);
    LOG.debug("alpha: {} beta: {}", (float) alpha, (float) beta);
    return processedImage;
}
相关问题