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

如何用OpenCV和Python实现不受颜色差异影响的图像阈值化?

解决明暗反转图像的统一阈值化问题

嘿,我来帮你搞定这个阈值化的难题!这种一张图字母亮于背景、另一张字母暗于背景的情况,确实会让普通固定阈值化失效,咱们用自适应判断+动态阈值化的思路就能统一输出白背景黑字母的结果。

核心思路

关键在于先判断每张图里「字母是亮的还是暗的」,然后动态选择阈值化的方向(直接二值化/反转二值化),具体步骤如下:

1. 先将图像转为灰度图

不管输入是彩色还是灰度图,先统一转成灰度通道,简化后续处理:

import cv2
img = cv2.imread("your_image_path.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

2. 用Otsu法自动计算最优阈值

Otsu阈值法会自动分析图像的像素分布,找到能最大化前景(字母)和背景差异的阈值,比手动设阈值靠谱得多:

thresh_val, _ = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

3. 判断字母的明暗属性

因为字母的面积通常远小于背景,我们可以通过统计「阈值以下的暗像素数量」和「阈值以上的亮像素数量」来判断:

  • 如果暗像素更少 → 字母是深色的(背景亮),直接用普通二值化
  • 如果亮像素更少 → 字母是浅色的(背景暗),用反转二值化来翻转明暗

代码实现:

# 统计暗像素和亮像素的数量
dark_pixel_count = cv2.countNonZero(gray < thresh_val)
total_pixels = gray.shape[0] * gray.shape[1]
light_pixel_count = total_pixels - dark_pixel_count

# 动态选择阈值化方式
if dark_pixel_count < light_pixel_count:
    # 字母为深色,直接二值化:背景白,字母黑
    _, final_thresh = cv2.threshold(gray, thresh_val, 255, cv2.THRESH_BINARY)
else:
    # 字母为浅色,反转二值化:翻转后背景白,字母黑
    _, final_thresh = cv2.threshold(gray, thresh_val, 255, cv2.THRESH_BINARY_INV)

完整可运行代码

把上面的步骤封装成函数,方便批量处理两张图:

import cv2

def get_uniform_black_text_white_bg(img_path):
    # 读取图像
    img = cv2.imread(img_path)
    if img is None:
        raise ValueError(f"无法读取图像:{img_path}")
    
    # 转灰度
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # Otsu自动计算阈值
    thresh_val, _ = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    
    # 统计明暗像素数量
    dark_count = cv2.countNonZero(gray < thresh_val)
    total_pixels = gray.size
    light_count = total_pixels - dark_count
    
    # 生成统一结果
    if dark_count < light_count:
        _, result = cv2.threshold(gray, thresh_val, 255, cv2.THRESH_BINARY)
    else:
        _, result = cv2.threshold(gray, thresh_val, 255, cv2.THRESH_BINARY_INV)
    
    return result

# 测试两张图
result1 = get_uniform_black_text_white_bg("light_text_dark_bg.jpg")
result2 = get_uniform_black_text_white_bg("dark_text_light_bg.jpg")

# 保存结果
cv2.imwrite("uniform_result1.jpg", result1)
cv2.imwrite("uniform_result2.jpg", result2)

特殊情况处理

如果你的字母和背景面积差不多(比如全填充的大字母),可以换一种判断逻辑:

  1. 取图像四个角落的像素(假设角落都是背景),计算背景的平均亮度
  2. 随机取图像中心区域的几个像素(假设是字母),对比中心和角落的亮度
  3. 如果中心比角落暗 → 字母是深色;如果中心比角落亮 → 字母是浅色,再决定是否反转

这种方法更适合极端场景,不过大部分普通图文场景用前面的像素数量统计法就足够了。

内容的提问来源于stack exchange,提问作者BuddyRJ

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:32:01