我想使用来自视觉框架的VNDetectTextRectanglesRequest
来检测图像中仅包含一个字符(数字"9")的区域,背景为白色。我使用以下代码来执行此操作:
private func performTextDetection() {
let textRequest = VNDetectTextRectanglesRequest(completionHandler: self.detectTextHandler)
textRequest.reportCharacterBoxes = true
textRequest.preferBackgroundProcessing = false
let handler = VNImageRequestHandler(cgImage: loadedImage.cgImage!, options: [:])
DispatchQueue.global(qos: .userInteractive).async {
do {
try handler.perform([textRequest])
} catch {
print ("Error")
}
}
}
func detectTextHandler(request: VNRequest, error: Error?) {
guard let observations = request.results, !observations.isEmpty else {
fatalError("no results")
}
print("there is result")
}
我得到的观测结果数为 0,但是如果我提供黑色背景上带有文本"123"的图像,则"123"被检测为带有文本的区域。所描述的问题也发生在 2 位数字上,白色背景上的"22"也没有被检测到。
为什么在我的案例中,视觉 API 只检测白色背景上的 3 位数字 + 数字?
长字符仍然是 XCode 12.5 和 Swift 5 中 VNRecognizeTextRequest 和 VNDetectTextRectanglesRequest 的问题。
我见过VNDetectTextRectanglesRequest在一张纸上找到几乎所有的单个单词,但无法检测到单独的字符[在处理整个图像时]。将属性 VNDetectTextRectanglesRequest.regionOfInterest 设置为较小的区域可能会有所帮助。
对我有用的是让单个字符占据VNRecognizeTextRequest的更多感兴趣区域(ROI)。我在各种高度上测试了单个字符,很明显,一旦单个字符在ROI内达到一定大小,它们就会开始阅读。
对于某些单个字符,当 ROI 大约是字符本身宽度的三倍和高度的三倍时,似乎会发生检测。这是一个相当狭窄的兴趣区域。正确放置它是另一个问题,但也是可以解决的。
如果处理时间不是应用程序的问题,则可以创建一个数组 [CGRect],该数组跨越怀疑包含单独字符的区域。
我的怀疑是,当VNRecognizeTextRequest对类似于笔画的边缘内容,边缘密度和/或图像特征执行初始检查时,如果找不到足够的候选者,它会提前退出。初始检查可能只是一个嵌入式VNDetectTextRectanglesRequest。无论初始检查是什么,它运行得都很快,所以我不认为它那么复杂。
有关描边检测以查找字符的更多信息,请搜索有关描边宽度变换的 SO 帖子和文章。还有这个:https://www.microsoft.com/en-us/research/publication/detecting-text-in-natural-scenes-with-stroke-width-transform/。SWT旨在处理"自然"图像,例如在户外看到的文本。
有一些技巧可以解决这个问题。其中一些黑客令人不快,但对于特定的应用程序,它们可能是值得的。
- 创建小感兴趣区域 (ROI) 的网格。在一个ROI上运行文本请求。
- 作为VNDetectTextRectanglesRequest的廉价替代品,查找具有边缘内容的图像区域,这些区域表明可能存在单个字符。如果不出意外,这可能有助于忽略没有边缘内容的区域。
- 在处理图像之前,请尝试使用缩放筛选器来放大图像。这可以确保单个字符足够大,可以读取。(对于CIFilters,一个非常方便的资源是 https://cifilter.io/)
- 在映像上运行多个通道。首先,对完整映像运行 OCR。然后获取已阅读单词的边界框。搜索盒子之间的可疑间隙。在可疑的空白区域上运行小 ROI 的网格。
- 使用 Tesseract 作为备份。(https://www.seemuapps.com/swift-optical-character-recognition-tutorial)