Blane Townsend
Blane Townsend

Reputation: 3048

How to read pixel values for Raw Image on Android

I have managed to capture a RAW image on Android and save it to disk as a DNG. What I want to do is read the raw sensor data of each "pixel" for the image. Specifically, I just want to read the green sensor values before any processing. What is the best way to do this?

Upvotes: 1

Views: 311

Answers (1)

Samuel Solomon
Samuel Solomon

Reputation: 1

Here is a method I use. I average the green pixels, but this may not be the best strategy. Either way, here is how you get them.

fun getBayerFilter(cameraId: Int) {
    val cameraCharacteristics: CameraCharacteristics = CameraInterface.cameraManager.getCameraCharacteristics(cameraId)
    val bayerFilter = cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT)

    return bayerFilter
}

fun extractGreenPixels(image: Image, blackLevel: Float, cameraId: Int): FloatArray {
    if (image.format != ImageFormat.RAW_SENSOR) {
        throw IllegalArgumentException("Unsupported image format (Need to change this method to continue): ${image.format}")
    }

    // Get the Bayer filter.
    val bayerFilter = getBayerFilter(cameraId)
    val supportedFilters = listOf(
        CameraMetadata.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB,
        CameraMetadata.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG,
        CameraMetadata.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG,
        CameraMetadata.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR
    )

    if (bayerFilter !in supportedFilters) {
        throw IllegalArgumentException("Unsupported Bayer filter (Need to change this method to continue): $bayerFilter")
    }

    // TODO: Why does "image.planes" have a warning? Format(0x20) is RAW_SENSOR
    val planes = image.planes  // This line has the warning: Could not find component description for Format(0x20) FourCC value(0x20363152)???
    val buffer: ByteBuffer = planes[0].buffer
    val rowStride: Int = planes[0].rowStride
    val pixelStride: Int = planes[0].pixelStride
    val width = image.width
    val height = image.height

    // Correct array size: width * height / 2
    val greenPixels = FloatArray(width * height / 4)

    var index = 0
    for (y in 0 until height step 2) {
        for (x in 0 until width step 2) {
            val green1: Float
            val green2: Float

            when (bayerFilter) {
                CameraMetadata.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB -> {
                    green1 = get16BitPixel(buffer, rowStride, pixelStride, x + 1, y)
                    green2 = get16BitPixel(buffer, rowStride, pixelStride, x, y + 1)
                }
                CameraMetadata.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG -> {
                    green1 = get16BitPixel(buffer, rowStride, pixelStride, x, y)
                    green2 = get16BitPixel(buffer, rowStride, pixelStride, x + 1, y + 1)
                }
                CameraMetadata.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG -> {
                    green1 = get16BitPixel(buffer, rowStride, pixelStride, x, y)
                    green2 = get16BitPixel(buffer, rowStride, pixelStride, x + 1, y + 1)
                }
                CameraMetadata.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR -> {
                    green1 = get16BitPixel(buffer, rowStride, pixelStride, x + 1, y)
                    green2 = get16BitPixel(buffer, rowStride, pixelStride, x, y + 1)
                }
                else -> throw IllegalArgumentException("Unsupported Bayer filter (Need to change this method to continue): $bayerFilter")
            }

            // Calculate the average green value
            greenPixels[index++] = (green1 + green2) / 2.0f - blackLevel
        }
    }

    return greenPixels
}

Upvotes: 0

Related Questions