問題と対策
AndroidのMLKitでCode39バーコードをスキャンすると、誤読が発生しやすい。
N回連続で同じ値を読み取れた場合に初めて採用することで、誤読を減らすことを考える。
実装
ImageAnalysis.Analyzerを実装したクラスに、連続検出のカウントロジックを追加する。
private class BarcodeAnalyzer(onBarcodeDetected: (String) -> Unit) : ImageAnalysis.Analyzer {
private val NUMBER_OF_DETECTION = 3 // 規定の検出回数
private var count = 0 // 連続して読み取った回数
private var previousValue = "" // 直前に読み取った値
override fun analyze(imageProxy: ImageProxy) {
...
scanner.process(image).addOnSuccessListener { barcodes ->
val value = barcodes.firstOrNull()?.rawValue ?: return@addOnSuccessListener
if (value != previousValue) {
previousValue = value
count = 0
}
count++
// N回連続で同じ値を読み取れた場合に採用する
if (count >= NUMBER_OF_DETECTION) {
onBarcodeDetected(value)
count = 0
}
}
.addOnCompleteListener {
imageProxy.close()
}
}
}
前回と同じ値を読み取ったらカウントを増やし、規定の回数に達した場合のみコールバックを呼ぶようにする。
規定の値を大きくするほど誤読は減るが、読み取りに時間がかかるようになる。
精度と性能のトレードオフとなる。
使い方
ImageAnalysisのインスタンスにsetAnalyzerで上記のクラスを設定する。
val imageAnalysis = ImageAnalysis.Builder()
.setBackpressureStrategy(...)
.build()
imageAnalysis.setAnalyzer(executor, BarcodeAnalyzer(
onBarcodeDetected = { value ->
/* バーコードに対する処理 */
}
))
1文字のバーコードについて
この方法でも、読み取り値が1文字の場合は精度が改善しにくい。1文字のバーコードはエンコードされる情報量が極端に少なく、誤認識に対する冗長性の低さが原因と考えられる。
ただし、Code39で1文字のバーコードは実用上ほぼ存在しない。
例えば、誤読による1文字の値が問題になる場合は、文字数でフィルタリングするとよい。
if (value.length <= 1) { return@addOnSuccessListener } // 1文字以下は無視
\確かな知識を身に着けたい、Androidアプリ開発を学びたい人にオススメ!/
