欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android基于OpenCV實現(xiàn)QR二維碼檢測

 更新時間:2021年06月18日 09:24:08   作者:易冬  
QR碼比普通一維條碼具有快速讀取和更大的存儲資料容量,也無需要像一維條碼般在掃描時需要直線對準掃描儀。因此其應用范圍已經(jīng)擴展到包括產(chǎn)品跟蹤,物品識別,文檔管理,庫存營銷等方面。本文講解Android基于OpenCV實現(xiàn)QR二維碼檢測的步驟

QR二維碼

QR碼(英語:Quick Response Code;全稱為快速響應矩陣圖碼)是二維碼的一種,于1994年由日本DENSO WAVE公司發(fā)明。QR來自英文Quick Response的縮寫,即快速反應,因為發(fā)明者希望QR碼可以快速解碼其內(nèi)容。QR碼使用四種標準化編碼模式(數(shù)字、字母數(shù)字、字節(jié)(二進制)和日文(Shift_JIS))來存儲數(shù)據(jù)。QR碼常見于日本,為目前日本最通用的二維空間條碼,在世界各國廣泛運用于手機讀碼操作。QR碼比普通一維條碼具有快速讀取和更大的存儲資料容量,也無需要像一維條碼般在掃描時需要直線對準掃描儀。因此其應用范圍已經(jīng)擴展到包括產(chǎn)品跟蹤,物品識別,文檔管理,庫存營銷等方面?!揪S基百科】

QR二維碼格式

QR碼呈正方形,常見的是黑白兩色。在3個角落,印有較小,像“回”字的正方圖案。這3個是幫助解碼軟件定位的圖案,用戶不需要對準,無論以任何角度掃描,資料仍然可以正確被讀取。日本QR碼的標準JIS X 0510在1999年1月發(fā)布,而其對應的ISO國際標準ISO/IEC18004,則在2000年6月獲得批準。根據(jù)Denso Wave公司的網(wǎng)站資料,QR碼是屬于開放式的標準,QR碼的規(guī)格公開,雖由Denso Wave公司持有的專利權益,但不會被運行。除了標準的QR碼之外,也存在一種稱為“微型QR碼”的格式,是QR碼標準的縮小版本,主要是為了無法處理較大型掃描的應用而設計。微型QR碼同樣有多種標準,最高可存儲35個字符?!揪S基百科】

QR二維碼結構

QR碼最大特征為其左上,右上,左下三個大型的如同“回”字的黑白間同心方圖案,為QR碼識別定位標記,失去其中一個會影響識別。而呈棋盤般分布的有別與大定位標記的較小的同心方則為其校正標記,用于校正識別,版本1沒有校正標記,版本2在右下方,其中心點在左下和右上定位標記的外邊框的相交點,版本10開始以每個等距的方式出現(xiàn)在右下校正點至左下和右上定位標記的外邊框的連線、左上與左下定位標記的外邊框的連線、左上與右上定位標記的外邊框的連線之間、這四邊線上等距點對邊相連線,版本10等距有1個,版本25為3個,版本40為5個?!揪S基百科】

API

QRCodeDetector類結構

檢測QR二維碼

public boolean detect(Mat img, Mat points)
  • 參數(shù)一:img,待檢測是否含有QR二維碼的的灰度圖或者彩色(BGR)圖像。
  • 參數(shù)二:points,檢測到的QR二維碼的最小區(qū)域四邊形的4個頂點坐標集合。
  • 返回值:布爾類型,true,代表檢測到QR二維碼;false,代表未檢測到QR二維碼。
public boolean detectMulti(Mat img, Mat points)
  • 參數(shù)一:img,待檢測是否含有QR二維碼的的灰度圖或者彩色(BGR)圖像。
  • 參數(shù)二:points,多個檢測結果QR二維碼的最小區(qū)域四邊形的4個頂點坐標集合。
  • 返回值:布爾類型,true,代表檢測到QR二維碼;false,代表未檢測到QR二維碼。

識別QR二維碼

public String decode(Mat img, Mat points, Mat straight_qrcode) 
  • 參數(shù)一:img,含有QR二維碼的灰度圖像或者彩色(BGR)圖像。
  • 參數(shù)二:points,detect方法得到的points值。數(shù)據(jù)量不可為空。
  • 參數(shù)三:straight_qrcode,經(jīng)過矯正和二值化的QR二維碼?!究蛇x參數(shù)】
  • 返回值:字符串類型,如果解碼失敗,則為空串。
public boolean decodeMulti(Mat img, Mat points, List<String> decoded_info, List<Mat> straight_qrcode)
  • 參數(shù)一:img,含有QR二維碼的灰度圖像或者彩色(BGR)圖像。
  • 參數(shù)二:points,detect方法得到的points值。數(shù)據(jù)量不可為空。
  • 參數(shù)三:decoded_info,多個二維碼的解碼信息。
  • 參數(shù)四:straight_qrcode,所有檢測到的二維碼矯正和二值化的后的結果集合?!究蛇x參數(shù)】
  • 返回值:布爾類型,true,代表解碼成功,反之,解碼失敗。

檢測并識別QR二維碼

public String detectAndDecode(Mat img, Mat points, Mat straight_qrcode)
  • 參數(shù)一:img,含有QR二維碼的灰度圖像或者彩色(BGR)圖像。
  • 參數(shù)二:points,檢測到的QR二維碼的最小區(qū)域四邊形的4個頂點坐標。
  • 參數(shù)三:straight_qrcode,經(jīng)過矯正和二值化的QR二維碼?!究蛇x參數(shù)】
  • 返回值:字符串類型,如果解碼失敗,則為空串。
public boolean detectAndDecodeMulti(Mat img, List<String> decoded_info, Mat points, List<Mat> straight_qrcode)
  • 參數(shù)一:img,含有QR二維碼的灰度圖像或者彩色(BGR)圖像。
  • 參數(shù)二:decoded_info,多個二維碼的解碼信息。
  • 參數(shù)三:points,檢測到的多個QR二維碼的最小區(qū)域四邊形的4個頂點坐標集合?!究蛇x參數(shù)】
  • 參數(shù)四:straight_qrcode,所有檢測到的二維碼矯正和二值化的后的結果集合?!究蛇x參數(shù)】
  • 返回值:字符串類型,如果解碼失敗,則為空串。

操作

/**
 * QR二維碼檢測
 * author: yidong
 * 2020/10/27
 */
class QRDetectActivity : AppCompatActivity() {

    private lateinit var mBinding: ActivityQrDetectBinding
    private lateinit var mQRCodeDetector: QRCodeDetector

    private var mPhotoSavePath = ""
    private lateinit var mUri: Uri
    private lateinit var mSource: Mat
    private lateinit var mGray: Mat
    private lateinit var mOperationSheet: BottomSheetDialog
    private lateinit var mSheetBinding: LayoutQrDetectOpBinding

    private lateinit var mPhotoSheet: BottomSheetDialog
    private lateinit var mPhotoOpBinding: LayoutPhotoOpBinding


    // 請求相機權限
    private val requestCameraPermission =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) {
            if (it) {
                mPhotoSavePath =
                    cacheDir.path + File.separator + "${System.currentTimeMillis()}.png"
                mUri = MediaStoreUtils.getIntentUri(this, File(mPhotoSavePath))
                requestCamera.launch(mUri)
            } else {
                Toast.makeText(applicationContext, "無相機權限", Toast.LENGTH_SHORT).show()
            }
        }

    // 請求外部存儲權限
    private val requestStoragePermission =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) {
            if (it) {
                pickImage.launch("image/*")
            } else {
                Toast.makeText(applicationContext, "無存儲權限", Toast.LENGTH_SHORT).show()
            }
        }


    private val requestCamera = registerForActivityResult(ActivityResultContracts.TakePicture()) {
        if (it) {
            val bgr = Imgcodecs.imread(mPhotoSavePath, Imgcodecs.IMREAD_COLOR)
            if (bgr.empty()) {
                Toast.makeText(applicationContext, "讀取拍照結果失敗", Toast.LENGTH_SHORT).show()
                return@registerForActivityResult
            } else {
                Imgproc.cvtColor(bgr, mSource, Imgproc.COLOR_BGR2RGB)
                Imgproc.cvtColor(bgr, mGray, Imgproc.COLOR_BGR2GRAY)
                mBinding.ivLena.showMat(mSource)
            }
        } else {
            Toast.makeText(applicationContext, "拍照失敗", Toast.LENGTH_SHORT).show()
        }
    }

    private val pickImage = registerForActivityResult(ActivityResultContracts.GetContent()) {
        if (it != null) {
            val filePath = MediaStoreUtils.getMediaPath(this, it)
            if (filePath.isNullOrEmpty()) {
                Toast.makeText(applicationContext, "讀取圖片失敗", Toast.LENGTH_SHORT).show()
                return@registerForActivityResult
            }
            val bgr = Imgcodecs.imread(filePath, Imgcodecs.IMREAD_COLOR)
            if (bgr.empty()) {
                Toast.makeText(applicationContext, "讀取圖片失敗", Toast.LENGTH_SHORT).show()
                return@registerForActivityResult
            } else {
                Imgproc.cvtColor(bgr, mSource, Imgproc.COLOR_BGR2RGB)
                Imgproc.cvtColor(bgr, mGray, Imgproc.COLOR_BGR2GRAY)
                mBinding.ivLena.showMat(mSource)
            }
        } else {
            Toast.makeText(applicationContext, "選圖失敗", Toast.LENGTH_SHORT).show()
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_qr_detect)
        mQRCodeDetector = QRCodeDetector()
        mSource = Mat()
        mGray = Mat()
        val bgr = Utils.loadResource(this, R.drawable.qrcode)
        Imgproc.cvtColor(bgr, mSource, Imgproc.COLOR_BGR2RGB)
        Imgproc.cvtColor(bgr, mGray, Imgproc.COLOR_BGR2GRAY)
        mBinding.ivLena.showMat(mSource)
        createDialog()
    }

    private fun createDialog() {
        mOperationSheet = BottomSheetDialog(this)
        mSheetBinding = LayoutQrDetectOpBinding.inflate(layoutInflater, null, false)
        mOperationSheet.setContentView(mSheetBinding.root)
        mSheetBinding.tvDetect.setOnClickListener {
            mOperationSheet.dismiss()
            doDetect()
        }
        mSheetBinding.tvDecode.setOnClickListener {
            mOperationSheet.dismiss()
            doDecode()
        }

        mPhotoSheet = BottomSheetDialog(this)
        mPhotoOpBinding = LayoutPhotoOpBinding.inflate(layoutInflater, null, false)
        mPhotoSheet.setContentView(mPhotoOpBinding.root)
        mPhotoOpBinding.tvCamera.setOnClickListener {
            mPhotoSheet.dismiss()
            requestCameraPermission.launch(
                Manifest.permission.CAMERA
            )
        }
        mPhotoOpBinding.tvPhoto.setOnClickListener {
            mPhotoSheet.dismiss()
            requestStoragePermission.launch(
                Manifest.permission.WRITE_EXTERNAL_STORAGE
            )

        }
    }

    private fun doDetect() {
        val points = Mat()
        val isHasQr = mQRCodeDetector.detect(mSource, points)
        if (isHasQr) {
            val pointArr = FloatArray(8)
            points.get(0, 0, pointArr)
            Log.d(App.TAG, pointArr.toList().toString())
            val tmp = mSource.clone()
            for (i in pointArr.indices step 2) {
                val start = Point(pointArr[i % 8].toDouble(), pointArr[(i + 1) % 8].toDouble())
                val end = Point(pointArr[(i + 2) % 8].toDouble(), pointArr[(i + 3) % 8].toDouble())
                Imgproc.line(tmp, start, end, Scalar(255.0, 0.0, 0.0), 8, Imgproc.LINE_8)
            }
            mBinding.ivResult.showMat(tmp)
            tmp.release()
        }
    }

    private fun doDecode() {
        val points = Mat()
        val isHasQr = mQRCodeDetector.detect(mGray, points)
        if (isHasQr) {
            val result = mQRCodeDetector.decode(mGray, points)
            if (result.isEmpty()) {
                Toast.makeText(applicationContext, "無法解碼", Toast.LENGTH_SHORT).show()
            } else {
                Snackbar.make(mBinding.root, "解碼結果:$result", 3000).show()
            }
            Log.d(App.TAG, result)
        } else {
            Toast.makeText(applicationContext, "未檢測到QRCode", Toast.LENGTH_SHORT).show()
        }
    }

    private fun selectMedia() {
        if (this::mPhotoSheet.isInitialized) {
            mPhotoSheet.show()
        }
    }

    private fun selectOps() {
        if (this::mOperationSheet.isInitialized) {
            mOperationSheet.show()
        }
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.menu_qr_detect, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.itemId) {
            R.id.menu_pick_photo -> selectMedia()
            R.id.menu_qr_ops -> selectOps()
        }
        return true
    }

    override fun onDestroy() {
        mSource.release()
        mGray.release()
        super.onDestroy()
    }
}

結果

源碼

github.com/onlyloveyd/…

以上就是Android基于OpenCV實現(xiàn)QR二維碼檢測的詳細內(nèi)容,更多關于Android OpenCV實現(xiàn)QR二維碼檢測的資料請關注腳本之家其它相關文章!

相關文章

  • Android開發(fā)X Y軸Board的繪制教程示例

    Android開發(fā)X Y軸Board的繪制教程示例

    這篇文章主要為大家介紹了Android開發(fā)X Y軸Board的繪制教程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • Android學習筆記之應用單元測試實例分析

    Android學習筆記之應用單元測試實例分析

    這篇文章主要介紹了Android學習筆記之應用單元測試,結合實例形式較為詳細的分析了Android單元測試的實現(xiàn)原理與具體步驟,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-11-11
  • android的消息處理機制(圖文+源碼分析)—Looper/Handler/Message

    android的消息處理機制(圖文+源碼分析)—Looper/Handler/Message

    這篇文章寫的非常好,深入淺出;android的消息處理機制(圖+源碼分析)—Looper,Handler,Message是一位大三學生自己剖析的心得,感興趣的朋友可以了解下哦,希望對你有所幫助
    2013-01-01
  • Android網(wǎng)絡技術HttpURLConnection詳解

    Android網(wǎng)絡技術HttpURLConnection詳解

    這篇文章主要為大家詳細介紹了Android網(wǎng)絡技術HttpURLConnection的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • Android 五大布局方式詳解

    Android 五大布局方式詳解

    本文主要介紹Android 五大布局的知識資料,這里整理了詳細的布局資料及實現(xiàn)示例代碼,和實現(xiàn)效果圖,有興趣的小伙伴可以參考下
    2016-09-09
  • Flutter 路由插件fluro的使用

    Flutter 路由插件fluro的使用

    使用原生的路由基本上能夠滿足大部分需求,但如果想要對頁面做類似瀏覽器 url 那樣的路由,或者控制頁面跳轉(zhuǎn)的轉(zhuǎn)場動畫,那么原生的路由需要做不少的改造。在 pub 上,有優(yōu)秀的路由插件 fluro 解決這類問題。本文介紹該插件的使用方法
    2021-06-06
  • Android自定義控件實現(xiàn)帶數(shù)值和動畫的圓形進度條

    Android自定義控件實現(xiàn)帶數(shù)值和動畫的圓形進度條

    這篇文章主要為大家詳細介紹了Android自定義控件實現(xiàn)帶數(shù)值和動畫的圓形進度條,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • Android自定義控件樣式實例詳解

    Android自定義控件樣式實例詳解

    這篇文章主要介紹了Android自定義控件樣式的方法,結合實例形式分析說明了常見樣式的含義與使用方法,需要的朋友可以參考下
    2016-01-01
  • Android實戰(zhàn)教程第六篇之一鍵鎖屏應用問題解決

    Android實戰(zhàn)教程第六篇之一鍵鎖屏應用問題解決

    這篇文章主要為大家詳細介紹了Android一鍵鎖屏應用開發(fā)過程中出現(xiàn)問題的解決方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • Android自定義控件實現(xiàn)球賽比分條效果

    Android自定義控件實現(xiàn)球賽比分條效果

    這篇文章主要為大家詳細介紹了Android自定義控件實現(xiàn)球賽比分條效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-12-12

最新評論