0
0
mirror of https://github.com/markusfisch/BinaryEye.git synced 2024-09-19 19:42:18 +02:00

Use only Y (lumo) channel from YUV input

Barcode recognition works on contrast so we don't need
color information and can therefore simplify processing
of input images.
This commit is contained in:
Markus Fisch 2017-09-02 14:22:26 +02:00
parent 7578d9b217
commit cbcc9591ff
7 changed files with 119 additions and 211 deletions

View File

@ -7,9 +7,7 @@ import de.markusfisch.android.cameraview.widget.CameraView
import de.markusfisch.android.binaryeye.activity.MainActivity
import de.markusfisch.android.binaryeye.app.addFragment
import de.markusfisch.android.binaryeye.rs.Inverter
import de.markusfisch.android.binaryeye.rs.Rotator
import de.markusfisch.android.binaryeye.rs.YuvToBitmap
import de.markusfisch.android.binaryeye.rs.YuvToGray
import de.markusfisch.android.binaryeye.widget.LockOnView
import de.markusfisch.android.binaryeye.zxing.Zxing
import de.markusfisch.android.binaryeye.R
@ -46,9 +44,7 @@ class CameraFragment : Fragment() {
private lateinit var vibrator: Vibrator
private lateinit var cameraView: CameraView
private lateinit var lockOnView: LockOnView
private lateinit var yuvToBitmap: YuvToBitmap
private lateinit var rotator: Rotator
private lateinit var inverter: Inverter
private lateinit var yuvToGray: YuvToGray
private var decoding = false
private var decodingThread: Thread? = null
@ -72,9 +68,7 @@ class CameraFragment : Fragment() {
vibrator = activity.getSystemService(
Context.VIBRATOR_SERVICE) as Vibrator
yuvToBitmap = YuvToBitmap(context)
rotator = Rotator(context)
inverter = Inverter(context)
yuvToGray = YuvToGray(context)
cameraView = (activity as MainActivity).cameraView
cameraView.setOnCameraListener(object : CameraView.OnCameraListener {
@ -109,9 +103,7 @@ class CameraFragment : Fragment() {
override fun onDestroyView() {
super.onDestroyView()
yuvToBitmap.destroy()
rotator.destroy()
inverter.destroy()
yuvToGray.destroy()
}
override fun onResume() {
@ -196,14 +188,8 @@ class CameraFragment : Fragment() {
private fun decodeFrame(): Result? {
frameData ?: return null
var bitmap = yuvToBitmap.convert(frameData!!, frameWidth, frameHeight)
bitmap = rotator.convert(bitmap, frameOrientation)
odd = odd xor true
if (odd) {
// invert every other frame to also read inverted barcodes
bitmap = inverter.convert(bitmap)
}
return zxing.decodeBitmap(bitmap)
return zxing.decodeBitmap(yuvToGray.convert(
frameData!!, frameWidth, frameHeight, frameOrientation))
}
private fun found(result: Result) {

View File

@ -1,41 +0,0 @@
package de.markusfisch.android.binaryeye.rs
import de.markusfisch.android.binaryeye.renderscript.ScriptC_invert
import android.content.Context
import android.graphics.Bitmap
import android.support.v8.renderscript.Allocation
import android.support.v8.renderscript.RenderScript
class Inverter(context: Context) {
private val rs: RenderScript = RenderScript.create(context)
private val inverterScript: ScriptC_invert = ScriptC_invert(rs)
private var alloc: Allocation? = null
private var dest: Bitmap? = null
fun destroy() {
alloc?.destroy()
alloc = null
dest?.recycle()
dest = null
inverterScript.destroy()
rs.destroy()
}
fun convert(bitmap: Bitmap): Bitmap {
if (dest == null) {
dest = bitmap.copy(bitmap.getConfig(), true)
alloc = Allocation.createFromBitmap(
rs,
dest,
Allocation.MipmapControl.MIPMAP_NONE,
Allocation.USAGE_SCRIPT)
}
inverterScript.forEach_invert(alloc, alloc)
alloc?.copyTo(dest)
return dest!!
}
}

View File

@ -1,77 +0,0 @@
package de.markusfisch.android.binaryeye.rs
import de.markusfisch.android.binaryeye.renderscript.ScriptC_rotator
import android.content.Context
import android.graphics.Bitmap
import android.support.v8.renderscript.Allocation
import android.support.v8.renderscript.RenderScript
class Rotator(context: Context) {
private val rs: RenderScript = RenderScript.create(context)
private val rotatorScript: ScriptC_rotator = ScriptC_rotator(rs)
private var sourceAlloc: Allocation? = null
private var destAlloc: Allocation? = null
private var dest: Bitmap? = null
fun destroy() {
sourceAlloc?.destroy()
sourceAlloc = null
destAlloc?.destroy()
destAlloc = null
dest?.recycle()
dest = null
rotatorScript.destroy()
rs.destroy()
}
fun convert(bitmap: Bitmap, frameOrientation: Int): Bitmap {
var orientation = frameOrientation
orientation = orientation % 360 / 90
if (orientation == 0) {
return bitmap
}
if (dest == null) {
var width = bitmap.width
var height = bitmap.height
sourceAlloc = Allocation.createFromBitmap(
rs,
bitmap,
Allocation.MipmapControl.MIPMAP_NONE,
Allocation.USAGE_SCRIPT)
rotatorScript._inImage = sourceAlloc
rotatorScript._inWidth = width
rotatorScript._inHeight = height
when (orientation) {
1, 3 -> {
val tmp = width
width = height
height = tmp
}
}
dest = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
destAlloc = Allocation.createFromBitmap(
rs,
dest,
Allocation.MipmapControl.MIPMAP_NONE,
Allocation.USAGE_SCRIPT)
} else {
sourceAlloc?.copyFrom(bitmap)
}
when (orientation) {
1 -> rotatorScript.forEach_rotate90(destAlloc, destAlloc)
2 -> rotatorScript.forEach_rotate180(destAlloc, destAlloc)
3 -> rotatorScript.forEach_rotate270(destAlloc, destAlloc)
}
destAlloc?.copyTo(dest)
return dest!!
}
}

View File

@ -1,63 +0,0 @@
package de.markusfisch.android.binaryeye.rs
import android.content.Context
import android.graphics.Bitmap
import android.support.v8.renderscript.Allocation
import android.support.v8.renderscript.Element
import android.support.v8.renderscript.RenderScript
import android.support.v8.renderscript.ScriptIntrinsicYuvToRGB
import android.support.v8.renderscript.Type
class YuvToBitmap(context: Context) {
private val rs: RenderScript = RenderScript.create(context)
private var yuvType: Type? = null
private var rgbaType: Type? = null
private var yuvAllocation: Allocation? = null
private var rgbaAllocation: Allocation? = null
private var yuvToRgbaScript: ScriptIntrinsicYuvToRGB? = null
private var dest: Bitmap? = null
fun destroy() {
yuvToRgbaScript?.destroy()
yuvToRgbaScript = null
yuvType?.destroy()
yuvType = null
rgbaType?.destroy()
rgbaType = null
yuvAllocation?.destroy()
yuvAllocation = null
rgbaAllocation?.destroy()
rgbaAllocation = null
dest?.recycle()
dest = null
rs.destroy()
}
fun convert(data: ByteArray, width: Int, height: Int): Bitmap {
if (dest == null) {
yuvType = Type.createX(rs, Element.U8(rs), data.size)
yuvType?.let {
yuvAllocation = Allocation.createTyped(rs, yuvType,
Allocation.USAGE_SCRIPT)
}
rgbaType = Type.createXY(rs, Element.RGBA_8888(rs), width, height)
rgbaType?.let {
rgbaAllocation = Allocation.createTyped(rs, rgbaType)
}
yuvToRgbaScript = ScriptIntrinsicYuvToRGB.create(rs,
Element.U8_4(rs))
yuvToRgbaScript?.setInput(yuvAllocation)
dest = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
}
yuvAllocation?.copyFrom(data)
yuvToRgbaScript?.forEach(rgbaAllocation)
rgbaAllocation?.copyTo(dest)
return dest!!
}
}

View File

@ -0,0 +1,96 @@
package de.markusfisch.android.binaryeye.rs
import de.markusfisch.android.binaryeye.renderscript.ScriptC_rotator
import de.markusfisch.android.binaryeye.renderscript.ScriptC_yuv2gray
import android.content.Context
import android.graphics.Bitmap
import android.support.v8.renderscript.Allocation
import android.support.v8.renderscript.Element
import android.support.v8.renderscript.RenderScript
import android.support.v8.renderscript.Type
class YuvToGray(context: Context) {
private val rs: RenderScript = RenderScript.create(context)
private val rotatorScript: ScriptC_rotator = ScriptC_rotator(rs)
private val yuv2grayScript: ScriptC_yuv2gray = ScriptC_yuv2gray(rs)
private var yuvType: Type? = null
private var rgbaType: Type? = null
private var yuvAlloc: Allocation? = null
private var rgbaAlloc: Allocation? = null
private var destAlloc: Allocation? = null
private var dest: Bitmap? = null
fun destroy() {
yuvType?.destroy()
yuvType = null
rgbaType?.destroy()
rgbaType = null
yuvAlloc?.destroy()
yuvAlloc = null
rgbaAlloc?.destroy()
rgbaAlloc = null
destAlloc?.destroy()
destAlloc = null
dest?.recycle()
dest = null
rotatorScript.destroy()
yuv2grayScript.destroy()
rs.destroy()
}
fun convert(
data: ByteArray,
width: Int,
height: Int,
orientation: Int): Bitmap {
if (dest == null) {
yuvType = Type.createXY(rs, Element.U8(rs), width, height * 3 / 2)
yuvAlloc = Allocation.createTyped(rs, yuvType,
Allocation.USAGE_SCRIPT)
rgbaType = Type.createXY(rs, Element.RGBA_8888(rs), width, height)
rgbaAlloc = Allocation.createTyped(rs, rgbaType,
Allocation.USAGE_SCRIPT)
var w = width
var h = height
when (orientation) {
90, 270 -> {
val tmp = w
w = h
h = tmp
}
}
dest = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
destAlloc = Allocation.createFromBitmap(
rs,
dest,
Allocation.MipmapControl.MIPMAP_NONE,
Allocation.USAGE_SCRIPT)
}
yuvAlloc?.copyFrom(data)
yuv2grayScript._inYUV = yuvAlloc
// width/height are uint_32 but Kotlin wants toLong()
yuv2grayScript._inWidth = width.toLong()
yuv2grayScript._inHeight = height.toLong()
yuv2grayScript.forEach_yuv2gray(rgbaAlloc)
rotatorScript._inImage = rgbaAlloc
rotatorScript._inWidth = width
rotatorScript._inHeight = height
when (orientation) {
0 -> destAlloc?.copyFrom(rgbaAlloc)
90 -> rotatorScript.forEach_rotate90(destAlloc, destAlloc)
180 -> rotatorScript.forEach_rotate180(destAlloc, destAlloc)
270 -> rotatorScript.forEach_rotate270(destAlloc, destAlloc)
}
destAlloc?.copyTo(dest)
return dest!!
}
}

View File

@ -1,10 +0,0 @@
#pragma version(1)
#pragma rs java_package_name(de.markusfisch.android.binaryeye.renderscript)
uchar4 RS_KERNEL invert(uchar4 in, uint32_t x, uint32_t y) {
uchar4 out = in;
out.r = 255 - in.r;
out.g = 255 - in.g;
out.b = 255 - in.b;
return out;
}

View File

@ -0,0 +1,17 @@
#pragma version(1)
#pragma rs java_package_name(de.markusfisch.android.binaryeye.renderscript)
#pragma rs_fp_relaxed
rs_allocation inYUV;
uint32_t inWidth;
uint32_t inHeight;
uchar4 RS_KERNEL yuv2gray(uint32_t x, uint32_t y) {
uchar Y = rsGetElementAt_uchar(inYUV, x, y);
uchar4 out;
out.r = Y;
out.g = Y;
out.b = Y;
out.a = 255;
return out;
}