Camera2实现二维码扫描功能(qrcode scanner)
實現二維碼識別的流程
啟動camera
這里我已經把Camera2封裝成CameraHolder
,通過CameraHolder可以方便的操作Camera。首先生成一個CameraHolder的對象,然后在activity調用onCreate的時候開啟camera。
定義QRCodeDecoder用于解析二維碼數據
這個類還是比較簡單的,首先需要生成一個ImageReader對象用于接收camera的preview的數據,然后還需要一個QRCodeReader對象用于解析二維碼。我們創建ImageReader的時候需要指定圖像的寬高和編碼格式,我設置的編碼格式為ImageFormat.YUV_420_888。編碼格式的設置影響到ImageReader的輸出Buffer內容。我們需要根據設置的編碼格式從ImageReader輸出的Buffer中讀取圖像數據。然后將Buffer中讀取的數據傳遞給QRCodeReader進行解析。
class QRCodeDecoder(w: Int, h: Int, private val callback: (String) -> Unit) : ImageReader.OnImageAvailableListener {private val frameThread = HandlerThread("frame thread")private val frameHandler: Handlerprivate val imageReader: ImageReaderprivate val bufferByte: ByteArrayprivate var qrCodeResult: String? = nullprivate val qrCodeReader = QRCodeReader()private val hints: Hashtable<DecodeHintType, Any> = Hashtable<DecodeHintType, Any>()init {frameThread.start()frameHandler = Handler(frameThread.looper)imageReader = ImageReader.newInstance(w, h, ImageFormat.YUV_420_888, 2)imageReader.setOnImageAvailableListener(this, frameHandler)bufferByte = ByteArray(w * h * 2)hints[DecodeHintType.CHARACTER_SET] = "utf-8" // 設置二維碼內容的編碼hints[DecodeHintType.POSSIBLE_FORMATS] = BarcodeFormat.QR_CODELog.d("QRCodeDecoder", " w:$w h:$h")}//當有解析結果后如果還需要繼續解析時,我們需要調用這個方法進行重置。重置后decoder才可以繼續工作。fun reset() {qrCodeResult = null}//camera啟動preview的時候需要添加這個surface到camera用于接收數據fun getSurface(): Surface = imageReader.surfaceoverride fun onImageAvailable(reader: ImageReader?) {reader?.let {//獲取image隊列中最新的一條數據并釋放老的數據val image = it.acquireLatestImage()if (TextUtils.isEmpty(qrCodeResult)) {var offset = 0//讀取y數據image.planes[0].buffer.get(bufferByte, offset, image.planes[0].buffer.limit())offset += image.planes[0].buffer.limit()//讀取u數據image.planes[1].buffer.get(bufferByte, offset, image.planes[1].buffer.limit())offset += image.planes[1].buffer.limit()//讀取v數據image.planes[2].buffer.get(bufferByte, offset, image.planes[2].buffer.limit())//通過yuv數據buffer生成qrCodeReader的輸入對象val source = PlanarYUVLuminanceSource(bufferByte, image.width, image.height, 0, 0, image.width, image.height, false)//二值化后的位圖數據val tempBitmap = BinaryBitmap(HybridBinarizer(source))try {qrCodeResult = qrCodeReader.decode(tempBitmap, hints)?.textcallback.invoke(qrCodeResult ?: "")} catch (e: Exception) {e.printStackTrace()}}//讀完image數據后需要回收image。image.close()}}fun release() {imageReader.close()frameThread.quitSafely()} }啟動camera的preview
QRCodeDecoder創建了一個ImageReader,我們可以將ImageReader的surface設置給camera用于接收數據。這里設置了兩個surface,另一個surface用于將preview內容顯示在手機屏幕上。為了提高二維碼的識別速度,我將ImageReader的surface設置的更小一些。CameraHolder設置surface后自動進入preview模式。
nodesRender.runInRender {//屏幕顯示用的preview最大為1920var size = cameraHolder.previewSizes.first { size -> size.width <= 1920 && size.height <= 1920 }updatePreviewNode(size.width,size.height)//QRCodeDecoder解析的圖片尺寸最大為640size = cameraHolder.previewSizes.first { size -> size.width <= 640 && size.height <= 640 }qrCodeDecoder?.release()qrCodeDecoder = QRCodeDecoder(size.width, size.height) { ret ->//當二維碼識別成功后這個回調會被調用showQRCodeResult(ret)}cameraHolder.setSurface(cameraPreviewNode!!.combineSurfaceTexture.surface,qrCodeDecoder?.getSurface()).invalidate()}總結
整個流程還是比較簡單的,并且經過測試發現識別速度還是挺快的。跟zxing的demo程序比較,這個實現還是比較簡單的。并且沒有過多的冗余內容,比較適合集成到應用中實現簡單的二維碼識別功能。
git地址
https://github.com/mjlong123123/Render/tree/prototype/qrcode
我的公眾號已經開通,公眾號會同步發布。
歡迎關注我的公眾號
總結
以上是生活随笔為你收集整理的Camera2实现二维码扫描功能(qrcode scanner)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 乘法逆元 java_浅谈乘法逆元(示例代
- 下一篇: unity 获取深度图(drawcall