You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 17:05:55