日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Camera2实现二维码扫描功能(qrcode scanner)

發(fā)布時(shí)間:2024/1/1 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Camera2实现二维码扫描功能(qrcode scanner) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

實(shí)現(xiàn)二維碼識(shí)別的流程

  • 開啟Camera
  • 創(chuàng)建ImageReader
  • 通過ImageReader獲取surface對(duì)像
  • 設(shè)置surface對(duì)象給camera并啟動(dòng)preview
  • 當(dāng)有preview數(shù)據(jù)產(chǎn)生時(shí)ImageReader的onImageAvailable回調(diào)會(huì)被調(diào)用
  • 調(diào)用ImageReader 的acquireLatestImage()方法獲取image數(shù)據(jù)
  • 把image數(shù)據(jù)傳遞給QRCodeReader進(jìn)行識(shí)別
  • 啟動(dòng)camera

    這里我已經(jīng)把Camera2封裝成CameraHolder
    ,通過CameraHolder可以方便的操作Camera。首先生成一個(gè)CameraHolder的對(duì)象,然后在activity調(diào)用onCreate的時(shí)候開啟camera。

    private val cameraHolder by lazy {CameraHolder(glSurfaceView.context)}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)cameraHolder.cameraId = CAMERA_REAR//設(shè)置后置攝像頭啟動(dòng)cameraHolder.open().invalidate()//啟動(dòng)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)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。