我正在尝试使用ML kit条形码检测器,camera2 API和Kotlin制作条形码扫描仪。 关于camera2,我从Google示例camera2basic开始 关于ML kit条形码检测器,我从doc开始:Scan Barcodes with ML Kit on Android
在Camera2BasicFragment / createCameraPreviewSession方法中,我添加了
previewRequestBuilder.addTarget(imageReader!!.surface)
因此,每次有图像可用时都会调用onImageAvailableListener。
在Camera2BasicFragment / setUpCameraOutputs方法中,我将ImageReader的ImageFormat.JPEG
更改为ImageFormat YUV420_888
,因此在onImageAvailableListener中,ImageReader给出了YUV图像
然后这是我的onImageAvailableListener:
private val onImageAvailableListener = ImageReader.OnImageAvailableListener {
val metadata = FirebaseVisionImageMetadata.Builder()
.setWidth(480) // 480x360 is typically sufficient for
.setHeight(360) // image recognition
.setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_YV12)
.setRotation(getRotationCompensation(cameraId, activity as Activity, context!!))
.build()
BarcodeReader(it.acquireNextImage(), detector, metadata, mListener).run()
}
在元数据中,“宽度”和“高度”如ML工具包文档中所建议,“格式”为YV12以处理YUV格式
条形码阅读器是:
class BarcodeReader (private val image: Image,
private val detector: FirebaseVisionBarcodeDetector,
private val metadata: FirebaseVisionImageMetadata,
private val mListener: IBarcodeScanner) : Runnable {
override fun run() {
val visionImage = FirebaseVisionImage.fromByteBuffer(image.planes[0].buffer, metadata)
detector.detectInImage(visionImage)
.addOnSuccessListener { barcodes ->
// Task completed successfully
// [START_EXCLUDE]
// [START get_barcodes]
for (barcode in barcodes) {
val bounds = barcode.boundingBox
val corners = barcode.cornerPoints
val rawValue = barcode.rawValue
if (rawValue!=null)
mListener.onBarcode(rawValue)
}
// [END get_barcodes]
// [END_EXCLUDE]
}
.addOnFailureListener {
// Task failed with an exception
// ...
Log.d("barcode", "null")
}
image.close()
}
detector.detectInImage进入onSuccessListener,但未检测到条形码:barcodes
数组始终为空。
有人可以帮我吗?
答案 0 :(得分:0)
您需要将所有三个平面的数据移交给FirebaseVisionImage.fromByteBuffer()函数。您的代码仅移交第一个(Y平面)。 YV12格式使用一个缓冲区(数组),其中包含Y数据,然后是U数据,然后是V数据。
图像包含3个单独的缓冲区,分别用于三个值(Y,U和V),但是实际帧需要在一个缓冲区(数组)中同时包含所有三个缓冲区。因此,您需要创建一个缓冲区,然后根据格式(YV12或NV21)以正确的顺序将三个平面的内容复制到其中,然后移交该缓冲区(数组)。
请参见this Wikipedia article和此SO问题/解答,其中包含有关YV12和NV21格式的转换和布局的更多信息。关于这些格式的另一个很好的资源是VideoLan Wiki。
一个函数可能看起来像这样:
0
宽度,高度和旋转程度取决于您的相机/预览和/或图像阅读器设置。
答案 1 :(得分:0)
有了ImageReader.OnImageAvailableListener
,您可以简单地将 FirebaseVisionImage#fromMediaImage(Image image, int rotation)用于ImageFormat YUV420_888
与文档中一样:
请注意,我们目前仅支持JPEG / YUV_420_888格式。如果使用的是云视觉检测器,建议使用JPEG格式;否则,建议使用JPEG格式。如果您使用的是设备上的检测器,则YUV_420_888将更加高效。
设置ImageReader
:
mImageReader = ImageReader.newInstance(mVideoSize!!.width,
mVideoSize!!.height,
ImageFormat.YUV_420_888, 3)
mImageReader!!.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler)
然后:
private val mOnImageAvailableListener = ImageReader.OnImageAvailableListener { imageReader ->
val image = imageReader.acquireLatestImage()
try {
mFaceDetector!!
.detectInImage(
FirebaseVisionImage
.fromMediaImage(image))
.addOnSuccessListener { firebaseVisionFaces ->
if (firebaseVisionFaces.size > 0) {
Log.d(TAG, "onSuccess: FACE DETECTED")
}
}
image.close()
} catch (e: NullPointerException) {
Log.e(TAG, "onImageAvailable: Invalid image provided for detection", e)
}
}
注意:我已经使用了面部检测,可以类似的方式使用条形码。