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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 01:06:30