Android OpenCV(四十):QR二维码检测

  • 参数一:img,含有QR二维码的灰度图像或者彩色(BGR)图像。
  • 参数二:points,detect方法得到的points值。数据量不可为空。
  • 参数三:straight_qrcode,经过矫正和二值化的QR二维码。【可选参数】
  • 返回值:字符串类型,如果解码失败,则为空串。

public boolean decodeMulti(Mat img, Mat points, List decoded_info, List straight_qrcode)

  • 参数一:img,含有QR二维码的灰度图像或者彩色(BGR)图像。
  • 参数二:points,detect方法得到的points值。数据量不可为空。
  • 参数三:decoded_info,多个二维码的解码信息。
  • 参数四:straight_qrcode,所有检测到的二维码矫正和二值化的后的结果集合。【可选参数】
  • 返回值:布尔类型,true,代表解码成功,反之,解码失败。

检测并识别QR二维码

public String detectAndDecode(Mat img, Mat points, Mat straight_qrcode)

  • 参数一:img,含有QR二维码的灰度图像或者彩色(BGR)图像。
  • 参数二:points,检测到的QR二维码的最小区域四边形的4个顶点坐标。
  • 参数三:straight_qrcode,经过矫正和二值化的QR二维码。【可选参数】
  • 返回值:字符串类型,如果解码失败,则为空串。

public boolean detectAndDecodeMulti(Mat img, List decoded_info, Mat points, List straight_qrcode)

  • 参数一:img,含有QR二维码的灰度图像或者彩色(BGR)图像。
  • 参数二:decoded_info,多个二维码的解码信息。
  • 参数三:points,检测到的多个QR二维码的最小区域四边形的4个顶点坐标集合。【可选参数】
  • 参数四:straight_qrcode,所有检测到的二维码矫正和二值化的后的结果集合。【可选参数】
  • 返回值:字符串类型,如果解码失败,则为空串。

操作

/**

  • 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()
}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值