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