Java使用OpenCV去除图片白色刻度仅保留数字的实现方法

Java + OpenCV 实现方案
核心思路是利用白色刻度和目标数字的视觉特征差异做过滤:白色刻度是高亮度的细长线条,数字是低亮度的类方块字符,二者在像素亮度、连通域宽高比上差异明显,不需要复杂的OCR或者模型识别就能完成分离。
处理流程
- 读取原图后转灰度图,降低计算维度
- 二值化提取所有接近纯白的候选区域,初步锁定白色刻度的范围
- 对白色候选区域做连通域分析,通过「宽高比极端(细长条)+ 平均亮度接近纯白」的规则筛选出所有刻度
- 移除筛选出的刻度区域,如果不需要保留原背景,可以直接提取深色的数字区域,输出透明背景的结果,彻底排除背景干扰
核心实现代码
先确保本地环境已经配置好OpenCV的Java依赖,加载对应本地库,核心处理代码如下:
import org.opencv.core.*; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.imgproc.Imgproc; import java.util.ArrayList; import java.util.List; public class ScaleRemover { static { // 加载OpenCV本地库,根据自身环境调整库路径配置 System.loadLibrary(Core.NATIVE_LIBRARY_NAME); } public static void processImage(String inputPath, String outputPath) { // 读取带透明通道的原图 Mat src = Imgcodecs.imread(inputPath, Imgcodecs.IMREAD_UNCHANGED); Mat gray = new Mat(); Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGRA2GRAY); // 提取纯白区域掩码:像素亮度高于240的判定为白色候选 Mat whiteMask = new Mat(); Imgproc.threshold(gray, whiteMask, 240, 255, Imgproc.THRESH_BINARY); // 遍历所有白色连通域 List<MatOfPoint> contours = new ArrayList<>(); Mat hierarchy = new Mat(); Imgproc.findContours(whiteMask, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE); for (MatOfPoint contour : contours) { Rect bound = Imgproc.boundingRect(contour); // 计算连通域宽高比 double ratio = Math.max((double) bound.width / bound.height, (double) bound.height / bound.width); // 计算连通域内平均亮度 double avgBright = Core.mean(new Mat(gray, bound)).val[0]; // 判定为刻度的规则:细长(宽高比>3)+ 纯白(平均亮度>245) if (ratio > 3 && avgBright > 245) { // 将刻度区域填充为全透明 Imgproc.rectangle(src, bound, new Scalar(0, 0, 0, 0), -1); } } // 不需要原背景时,直接提取深色数字生成透明底结果 Mat numMask = new Mat(); // 提取亮度低于200的深色区域,也就是数字部分 Imgproc.threshold(gray, numMask, 200, 255, Imgproc.THRESH_BINARY_INV); Mat result = new Mat(src.size(), CvType.CV_8UC4, new Scalar(0, 0, 0, 0)); src.copyTo(result, numMask); // 输出结果 Imgcodecs.imwrite(outputPath, result); // 释放所有Mat资源避免内存泄漏 src.release(); gray.release(); whiteMask.release(); hierarchy.release(); numMask.release(); result.release(); for (MatOfPoint contour : contours) contour.release(); } public static void main(String[] args) { processImage("source.png", "result.png"); } }
参数调优提示
代码里的二值化阈值、宽高比阈值、亮度判定阈值可以根据实际处理效果微调:如果有短刻度被漏删,可以把宽高比阈值从3调低到2.5;如果有数字的白色边缘被误删,可以把亮度判定阈值从245调高到250。如果刻度尺寸比较统一,还可以增加连通域面积的判定规则,进一步提升过滤准确率。
内容的提问来源于stack exchange,提问作者rich25
相关产品推荐
相关产品推荐

