0
0
mirror of https://github.com/markusfisch/BinaryEye.git synced 2024-09-20 03:52:16 +02:00

Route raw YUV data to ZXing

And don't convert it into a Bitmap just to read the
pixels back from it.
This commit is contained in:
Markus Fisch 2018-05-20 15:31:40 +02:00
parent 05a206384c
commit 64e1d722d5
5 changed files with 76 additions and 103 deletions

View File

@ -362,15 +362,18 @@ class CameraActivity : AppCompatActivity() {
}
private fun decodeFrame(): Result? {
val dat = frameData
dat ?: return null
return zxing.decodeBitmap(
preprocessor.convert(
dat,
frameWidth,
frameHeight,
frameOrientation
)
val yuvData = frameData
yuvData ?: return null
preprocessor.convert(
yuvData,
frameWidth,
frameHeight,
frameOrientation
)
return zxing.decode(
yuvData,
frameWidth,
frameHeight
)
}

View File

@ -1,10 +1,8 @@
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
@ -13,31 +11,23 @@ import android.support.v8.renderscript.Type
class Preprocessor(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 destType: Type? = null
private var destAlloc: Allocation? = null
private var dest: Bitmap? = null
private var odd = true
fun destroy() {
yuvType?.destroy()
yuvType = null
rgbaType?.destroy()
rgbaType = null
yuvAlloc?.destroy()
yuvAlloc = null
rgbaAlloc?.destroy()
rgbaAlloc = null
destType?.destroy()
destType = null
yuvAlloc?.destroy()
destAlloc?.destroy()
destAlloc = null
dest?.recycle()
dest = null
rotatorScript.destroy()
yuv2grayScript.destroy()
rs.destroy()
}
@ -46,67 +36,56 @@ class Preprocessor(context: Context) {
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
) {
if (orientation == 0) {
return
}
if (yuvAlloc == null) {
yuvType = Type.createXY(
rs,
Element.U8(rs),
width,
height * 3 / 2
)
rgbaType = Type.createXY(rs, Element.RGBA_8888(rs), width, height)
rgbaAlloc = Allocation.createTyped(
rs, rgbaType,
yuvAlloc = Allocation.createTyped(
rs,
yuvType,
Allocation.USAGE_SCRIPT
)
var w = width
var h = height
when (orientation) {
90, 270 -> {
val tmp = w
w = h
h = tmp
}
if (orientation == 90 || orientation == 270) {
val tmp = w
w = h
h = tmp
}
dest = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
destAlloc = Allocation.createFromBitmap(
destType = Type.createXY(
rs,
dest,
Allocation.MipmapControl.MIPMAP_NONE,
Element.U8(rs),
w,
h
)
destAlloc = Allocation.createTyped(
rs,
destType,
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()
// invert every second frame to also read inverted barcodes
if (odd) {
yuv2grayScript.forEach_yuv2gray(rgbaAlloc)
} else {
yuv2grayScript.forEach_yuv2inverted(rgbaAlloc)
}
odd = odd xor true
rotatorScript._inImage = rgbaAlloc
rotatorScript._inImage = yuvAlloc
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)
// since Bitmap.createBitmap() can't return null,
// dest cannot be null here either
return dest!!
destAlloc?.copyTo(data)
}
}

View File

@ -6,9 +6,9 @@ import com.google.zxing.DecodeHintType
import com.google.zxing.LuminanceSource
import com.google.zxing.MultiFormatReader
import com.google.zxing.MultiFormatWriter
import com.google.zxing.PlanarYUVLuminanceSource
import com.google.zxing.ReaderException
import com.google.zxing.Result
import com.google.zxing.RGBLuminanceSource
import com.google.zxing.common.HybridBinarizer
import android.graphics.Bitmap
@ -20,6 +20,8 @@ import java.util.EnumSet
class Zxing {
private val multiFormatReader: MultiFormatReader = MultiFormatReader()
private var odd = false
init {
val decodeFormats = EnumSet.noneOf<BarcodeFormat>(
BarcodeFormat::class.java
@ -54,16 +56,32 @@ class Zxing {
multiFormatReader.setHints(hints)
}
fun decodeBitmap(bitmap: Bitmap): Result? {
val width = bitmap.width
val height = bitmap.height
val data = IntArray(width * height)
bitmap.getPixels(data, 0, width, 0, 0, width, height)
return decodeLuminanceSource(RGBLuminanceSource(width, height, data))
fun decode(yuvData: ByteArray, width: Int, height: Int): Result? {
return decodeLuminanceSource(
PlanarYUVLuminanceSource(
yuvData,
width,
height,
0,
0,
width,
height,
false
)
)
}
private fun decodeLuminanceSource(source: LuminanceSource): Result? {
val bitmap = BinaryBitmap(HybridBinarizer(source))
val bitmap = BinaryBitmap(
HybridBinarizer(
if (odd) {
source
} else {
source.invert()
}
)
)
odd = odd xor true
return try {
multiFormatReader.decodeWithState(bitmap)
} catch (e: ReaderException) {

View File

@ -5,20 +5,20 @@ rs_allocation inImage;
int inWidth;
int inHeight;
uchar4 RS_KERNEL rotate90(uchar4 in, uint32_t x, uint32_t y) {
const uchar4 *out = rsGetElementAt(inImage, y, inHeight - 1 - x);
uchar RS_KERNEL rotate90(uchar in, uint32_t x, uint32_t y) {
const uchar *out = rsGetElementAt(inImage, y, inHeight - 1 - x);
return *out;
}
uchar4 RS_KERNEL rotate180(uchar4 in, uint32_t x, uint32_t y) {
const uchar4 *out = rsGetElementAt(
uchar RS_KERNEL rotate180(uchar in, uint32_t x, uint32_t y) {
const uchar *out = rsGetElementAt(
inImage,
inWidth - 1 - x,
inHeight - 1 - y);
return *out;
}
uchar4 RS_KERNEL rotate270(uchar4 in, uint32_t x, uint32_t y) {
const uchar4 *out = rsGetElementAt(inImage, inWidth - 1 - y, x);
uchar RS_KERNEL rotate270(uchar in, uint32_t x, uint32_t y) {
const uchar *out = rsGetElementAt(inImage, inWidth - 1 - y, x);
return *out;
}

View File

@ -1,27 +0,0 @@
#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;
}
uchar4 RS_KERNEL yuv2inverted(uint32_t x, uint32_t y) {
uchar Y = 255 - rsGetElementAt_uchar(inYUV, x, y);
uchar4 out;
out.r = Y;
out.g = Y;
out.b = Y;
out.a = 255;
return out;
}