如何去除图像中除文字数字外的多余内容,仅保留昵称、伤害值、BOSS名称?
提问内容
图片链接:
我已尝试通过以下简单代码,将不在特定像素值范围内的像素设为白色,其余设为黑色:
if (newpix[i] > 179 && newpix[i] < 228 && newpix[i+1] > 177 && newpix[i+1] < 249 && newpix[i+2] > 220 && newpix[i+2] < 256){ newpix[i] = 0; newpix[i+1] = 0; newpix[i+2] = 0; } else if (newpix[i] > 63 && newpix[i] < 146 && newpix[i+1] > 96 && newpix[i+1] < 182 && newpix[i+2] > 123 && newpix[i+2] < 220) { newpix[i] = 0; newpix[i+1] = 0; newpix[i+2] = 0; } else { newpix[i] = 255; newpix[i+1] = 255; newpix[i+2] = 255; }
处理结果:
上述方案虽可正常运行,但仍有优化空间。我期望最终仅保留图像中的昵称、伤害值、BOSS名称,其余内容全部去除,请问有什么更优的实现方法?
回答
你现在用固定RGB区间做二值化的方案最大的问题是鲁棒性差,只要画面明暗、色调出现微小变动,阈值就会失效,同时也没法区分和文字同色的非文字区域,可以按照下面的步骤优化:
- 更换为HSV颜色空间做阈值过滤
RGB三个通道的数值会同步受亮度影响,硬写阈值的适配性很差。转换到HSV空间后,可以单独针对你要保留的两种文字的色相(H)区间做过滤,再搭配饱和度(S)、明度(V)的合理阈值,过滤效果会稳定很多,不会因为画面整体亮暗变化就出现大面积漏判或者误判。 - 增加形态学操作过滤噪点
做完颜色二值化之后,用22或者33的小核对二值图先做腐蚀再做膨胀(开运算),可以直接去掉孤立的小面积噪点,之后再做一次闭运算补全文字笔画的小缺口,避免文字出现断裂。 - 用连通域筛选只保留文字区域
对二值图提取所有连通域,根据目标文字的大小、宽高比做过滤:你截图里的文字高度基本在1220像素区间,单字宽高比在0.53之间,不符合这个范围的连通域直接填充为白色,就能去掉绝大多数同色的非文字区块。 - 固定ROI区域裁剪(效率最高的方案)
游戏界面的布局是固定的,昵称、伤害数值、BOSS名称只会出现在固定的屏幕区域,你可以直接把其他区域的像素全部设置为白色,不用做全图判断,处理效率能提升数倍,还能完全避免其他区域的干扰。
参考实现代码(Python+OpenCV)
import cv2 import numpy as np # 读取原始图片 img = cv2.imread("game_screenshot.png") # 转换为HSV颜色空间 hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 第一种文字(黄白色伤害值)的HSV阈值,可根据实际情况调整 lower_text1 = np.array([20, 30, 180]) upper_text1 = np.array([35, 80, 255]) # 第二种文字(青蓝色昵称/BOSS名)的HSV阈值,可根据实际情况调整 lower_text2 = np.array([90, 20, 90]) upper_text2 = np.array([110, 100, 210]) # 生成两种文字的掩码 mask1 = cv2.inRange(hsv, lower_text1, upper_text1) mask2 = cv2.inRange(hsv, lower_text2, upper_text2) mask = cv2.bitwise_or(mask1, mask2) # 形态学操作去噪+补全文字 kernel = np.ones((2,2), np.uint8) mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) # 连通域过滤非文字区域 num_labels, labels, stats, _ = cv2.connectedComponentsWithStats(mask, connectivity=8) # 初始化全白结果图 result = np.full_like(img, 255) for i in range(1, num_labels): w = stats[i, cv2.CC_STAT_WIDTH] h = stats[i, cv2.CC_STAT_HEIGHT] area = stats[i, cv2.CC_STAT_AREA] # 过滤不符合文字大小的连通域 if 10 < h < 25 and 5 < w < 100 and area > 30: result[labels == i] = [0,0,0] # 保存结果 cv2.imwrite("processed_result.png", result)
内容的提问来源于stack exchange,提问作者KawaiiNeko
相关产品推荐
相关产品推荐

