使用Vision框架VNDetectTextRectanglesRequest无法识别单双数字问题
为什么VNDetectTextRectanglesRequest无法识别白背景下的单个/两位数字?
我尝试使用Vision框架的VNDetectTextRectanglesRequest识别白背景下仅含单个数字“9”的图像文本区域,但实际运行后observations结果数量为0。奇怪的是,黑背景下的数字“123”可以被正常识别,而且白背景下的两位数字“22”也无法被识别,只有3位及以上的数字才能在白背景下被检测到。
我的检测代码如下:
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") }
请问这是什么原因导致的,该如何解决?
这个问题其实和VNDetectTextRectanglesRequest的默认检测阈值以及文本特征有关,我来拆解一下原因和解决方法:
核心原因
- 默认最小文本高度阈值过高:
VNDetectTextRectanglesRequest默认的minimumTextHeight参数值(通常是0.05,即文本高度占图像高度的5%)可能过滤掉了单个/两位数字这类较小的文本块。白背景下的单个数字本身视觉占比小,加上对比度的影响(黑底白字的对比度在视觉上更容易被检测模型捕捉),就会出现检测不到的情况。 - 文本块的特征匹配逻辑:Vision的文本检测模型更倾向于识别有连续字符的文本区域,单个或两个字符的文本块在白背景下的特征不够明显,容易被模型判定为非文本区域。
解决方法
1. 调整最小文本高度阈值
显式设置minimumTextHeight为更小的值,比如0.01(根据你的图像实际尺寸调整,确保数字高度占比至少达到这个值):
private func performTextDetection() { let textRequest = VNDetectTextRectanglesRequest(completionHandler: self.detectTextHandler) textRequest.reportCharacterBoxes = true textRequest.preferBackgroundProcessing = false // 调整最小文本高度阈值,适配小尺寸数字 textRequest.minimumTextHeight = 0.01 let handler = VNImageRequestHandler(cgImage: loadedImage.cgImage!, options: [:]) DispatchQueue.global(qos: .userInteractive).async { do { try handler.perform([textRequest]) } catch { print ("Error") } } }
2. 增强图像对比度(可选)
如果调整阈值后还是检测不到,可以尝试反转图像(将白底黑字转为黑底白字),因为Vision对黑底白字的文本检测兼容性更好:
// 反转图像的示例代码 func invertedImage(from image: UIImage) -> UIImage? { guard let cgImage = image.cgImage else { return nil } let ciImage = CIImage(cgImage: cgImage) guard let filter = CIFilter(name: "CIColorInvert") else { return nil } filter.setValue(ciImage, forKey: kCIInputImageKey) guard let outputImage = filter.outputImage else { return nil } return UIImage(ciImage: outputImage) } // 在performTextDetection中使用反转后的图像 let invertedImg = invertedImage(from: loadedImage)! let handler = VNImageRequestHandler(cgImage: invertedImg.cgImage!, options: [:])
3. 检查图像分辨率
确保你的输入图像分辨率足够,数字的实际像素高度不要太小(比如至少20像素以上)。如果图像分辨率太低,可以先对图像进行放大处理后再检测。
额外提示
如果你不仅需要检测文本区域,还需要识别数字内容,可以考虑使用VNRecognizeTextRequest,它的文本检测逻辑对小字符的兼容性也更好,同时能直接返回识别出的文本内容。
内容的提问来源于stack exchange,提问作者AndrzejZ




