Android Kotlin应用ML Kit V2识别带点格式日期失败求解决方案
解决ML Kit无法识别带点格式日期的问题
针对你遇到的带点格式日期(如dd.MM.yyyy、MM.yyyy等)无法被识别的问题,可从扩展格式匹配逻辑和优化文本识别准确性两个方向解决,以下是具体方案:
一、快速适配:扩展正则与格式处理逻辑
当前代码的findDateFormat函数未包含带点分隔的日期格式,且DateFormat枚举也没有对应类型,这是直接原因。只需补充相关规则即可:
1. 补充DateFormat枚举值
先在ExpirationDateViewModel的DateFormat枚举中添加带点格式的类型:
enum class DateFormat { // 原有枚举... DD_MM_YYYY_DOT, DD_MM_DOT, MM_YYYY_DOT }
2. 更新findDateFormat函数
在格式匹配数组中加入带点格式的正则规则(注意点号需要转义):
private fun findDateFormat(date: String): ExpirationDateViewModel.DateFormat? { val formats = arrayOf( // 原有规则... "\\b\\d{1,2}\\.\\d{1,2}\\.\\d{4}\\b" to ExpirationDateViewModel.DateFormat.DD_MM_YYYY_DOT, "\\b\\d{1,2}\\.\\d{1,2}\\b" to ExpirationDateViewModel.DateFormat.DD_MM_DOT, "\\b\\d{1,2}\\.\\d{4}\\b" to ExpirationDateViewModel.DateFormat.MM_YYYY_DOT ) return formats.firstOrNull { date.matches(Regex(it.first)) }?.second }
3. 完善processImageProxy中的格式转换逻辑
在when分支中添加带点格式的处理:
val format = when(validFormat){ // 原有分支... ExpirationDateViewModel.DateFormat.DD_MM_YYYY_DOT -> "dd.MM.yyyy" ExpirationDateViewModel.DateFormat.DD_MM_DOT -> { date = "$date.${LocalDate.now().year}" "dd.MM.yyyy" } ExpirationDateViewModel.DateFormat.MM_YYYY_DOT -> { date = "01.$date" "dd.MM.yyyy" } }
4. 更新传入的regex参数
确保调用processImageProxy时传入的正则包含带点格式,比如:
val dateRegex = Regex("""\b\d{1,2}[./-]\d{1,2}[./-]?\d{0,4}\b""") // 调用processImageProxy时传入该regex
二、优化ML Kit文本识别准确性(如果ML Kit未识别出点)
如果ML Kit本身没有识别出日期中的点(比如把点识别成其他字符或漏识别),可以尝试以下优化:
- 启用Document Text Recognition:ML Kit的文档文本识别模型更适合印刷体文本,相比普通文本识别对特殊字符的识别更准确,只需将
TextRecognizer替换为DocumentTextRecognizer即可。 - 图像预处理:在传入ML Kit前,对图像进行对比度增强、去噪处理,提升点字符的辨识度。
- 自定义模型训练:如果通用模型效果始终不佳,可以使用Google AutoML Vision训练自定义文本识别模型,针对带点日期的场景优化识别效果。
修改后的完整关键代码示例
// 补充枚举 enum class DateFormat { DD_MM_YYYY_SLASH, DD_MM_SLASH, MM_YYYY_SLASH, DD_MM_YYYY_UNDERSCORE, DD_MM_UNDERSCORE, MM_YYYY_UNDERSCORE, DD_MM_YYYY_SCORE, DD_MM_SCORE, MM_YYYY_SCORE, DD_MM_YYYY_DOT, DD_MM_DOT, MM_YYYY_DOT // 新增带点格式 } // 更新findDateFormat private fun findDateFormat(date : String) : ExpirationDateViewModel.DateFormat?{ val formats = arrayOf( "\\b\\d{1,2}/\\d{1,2}/\\d{4}\\b" to ExpirationDateViewModel.DateFormat.DD_MM_YYYY_SLASH, "\\b\\d{1,2}/\\d{1,2}\\b" to ExpirationDateViewModel.DateFormat.DD_MM_SLASH, "\\b\\d{1,2}/\\d{4}\\b" to ExpirationDateViewModel.DateFormat.MM_YYYY_SLASH, "\\b\\d{1,2}-\\d{1,2}-\\d{4}\\b" to ExpirationDateViewModel.DateFormat.DD_MM_YYYY_SCORE, "\\b\\d{1,2}-\\d{1,2}\\b" to ExpirationDateViewModel.DateFormat.DD_MM_SCORE, "\\b\\d{1,2}-\\d{4}\\b" to ExpirationDateViewModel.DateFormat.MM_YYYY_SCORE, "\\b\\d{1,2}_\\d{1,2}_\\d{4}\\b" to ExpirationDateViewModel.DateFormat.DD_MM_YYYY_UNDERSCORE, "\\b\\d{1,2}_\\d{1,2}\\b" to ExpirationDateViewModel.DateFormat.DD_MM_UNDERSCORE, "\\b\\d{1,2}_\\d{4}\\b" to ExpirationDateViewModel.DateFormat.MM_YYYY_UNDERSCORE, // 新增带点格式 "\\b\\d{1,2}\\.\\d{1,2}\\.\\d{4}\\b" to ExpirationDateViewModel.DateFormat.DD_MM_YYYY_DOT, "\\b\\d{1,2}\\.\\d{1,2}\\b" to ExpirationDateViewModel.DateFormat.DD_MM_DOT, "\\b\\d{1,2}\\.\\d{4}\\b" to ExpirationDateViewModel.DateFormat.MM_YYYY_DOT ) return formats.firstOrNull { date.matches(Regex(it.first)) }?.second } // 更新processImageProxy中的when分支 @OptIn(ExperimentalGetImage::class) private fun processImageProxy( textRecognition: TextRecognizer, imageProxy: ImageProxy, regex: Regex ){ imageProxy.image?.let { image -> val inputImage = InputImage.fromMediaImage(image, imageProxy.imageInfo.rotationDegrees) textRecognition.process(inputImage) .addOnSuccessListener { text -> regex.find(text.text)?.let { val validFormat = findDateFormat(it.value) if(validFormat != null){ var date = it.value val format = when(validFormat){ // 原有分支... ExpirationDateViewModel.DateFormat.DD_MM_YYYY_SLASH -> "dd/MM/yyyy" ExpirationDateViewModel.DateFormat.DD_MM_SLASH -> { date = "$date/${LocalDate.now().year}" "dd/MM/yyyy" } ExpirationDateViewModel.DateFormat.MM_YYYY_SLASH -> { date = "01/$date" "dd/MM/yyyy" } ExpirationDateViewModel.DateFormat.DD_MM_YYYY_UNDERSCORE -> "dd_MM_yyyy" ExpirationDateViewModel.DateFormat.DD_MM_UNDERSCORE -> { date = "${date}_${LocalDate.now().year}" "dd_MM_yyyy" } ExpirationDateViewModel.DateFormat.MM_YYYY_UNDERSCORE -> { date = "01_$date" "dd_MM_yyyy" } ExpirationDateViewModel.DateFormat.DD_MM_YYYY_SCORE -> "dd-MM-yyyy" ExpirationDateViewModel.DateFormat.DD_MM_SCORE -> { date = "$date-${LocalDate.now().year}" "dd-MM-yyyy" } ExpirationDateViewModel.DateFormat.MM_YYYY_SCORE -> { date = "01-$date" "dd-MM-yyyy" } // 新增带点格式分支 ExpirationDateViewModel.DateFormat.DD_MM_YYYY_DOT -> "dd.MM.yyyy" ExpirationDateViewModel.DateFormat.DD_MM_DOT -> { date = "$date.${LocalDate.now().year}" "dd.MM.yyyy" } ExpirationDateViewModel.DateFormat.MM_YYYY_DOT -> { date = "01.$date" "dd.MM.yyyy" } } try{ val dateParsed = LocalDate.parse(date, DateTimeFormatter.ofPattern(format)) val foundDate = ExpirationDateViewModel.ExpirationDate(dateParsed,validFormat,false) if(dateParsed.isAfter(LocalDate.now())){ if(foundDate != expirationDateViewModel.date.value){ expirationDateViewModel.modifyExpirationDate(foundDate) vibrate() } } }catch (_: Exception){ } } } } .addOnFailureListener { imageProxy.close() }.addOnCompleteListener { imageProxy.image?.close() imageProxy.close() } } }
内容的提问来源于stack exchange,提问作者valentin fernandes
相关产品推荐
相关产品推荐

