如何在OpenCV C++中为图像内的轮廓化字符填充颜色?
解决字符轮廓填充颜色失败的问题
核心问题排查与修复
1. 图像预处理不匹配
findContours默认检测白色前景、黑色背景的轮廓,如果你的图像是黑色字符+白色背景,必须先反转图像,否则提取到的轮廓是背景而非字符:
import cv2 import numpy as np img = cv2.imread("2QWQn.png") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化并反转,得到白字黑底的二值图 ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV)
2. 轮廓提取模式错误
如果使用默认的轮廓检索模式,可能会提取到字符内部的空洞轮廓(比如'O'的内圈),导致pointPolygonTest误判。改用RETR_EXTERNAL只提取最外层轮廓:
contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
3. 坐标顺序搞反
pointPolygonTest的参数是(contour, (x, y), measureDist),其中x是列坐标(图像宽度方向),y是行坐标(图像高度方向)。很多人会把遍历的行/列顺序搞反,导致坐标完全错误:
fill_img = np.zeros_like(img) # 正确遍历:y是行,x是列 for y in range(fill_img.shape[0]): for x in range(fill_img.shape[1]): for cnt in contours: # 传入(x,y)而非(y,x) dist = cv2.pointPolygonTest(cnt, (x, y), False) if dist >= 0: # 0在轮廓上,1在内部 fill_img[y, x] = (0, 255, 0)
4. 过滤噪声轮廓
提取轮廓时可能会得到很多小噪声点,需要过滤掉面积过小的无效轮廓:
# 保留面积大于50的轮廓(阈值根据你的图像调整) valid_contours = [cnt for cnt in contours if cv2.contourArea(cnt) > 50]
更高效的替代方案
逐像素遍历效率极低,推荐直接用drawContours填充轮廓内部,一行代码搞定:
fill_img = np.zeros_like(img) # thickness=-1 表示填充轮廓内部 cv2.drawContours(fill_img, valid_contours, -1, (0, 255, 0), thickness=-1)
完整可运行代码
import cv2 import numpy as np # 读取图像 img = cv2.imread("2QWQn.png") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 预处理 ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV) # 提取并过滤轮廓 contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) valid_contours = [cnt for cnt in contours if cv2.contourArea(cnt) > 50] # 填充轮廓 fill_img = np.zeros_like(img) cv2.drawContours(fill_img, valid_contours, -1, (0, 255, 0), thickness=-1) # 显示结果 cv2.imshow("Original", img) cv2.imshow("Filled", fill_img) cv2.waitKey(0) cv2.destroyAllWindows()
内容的提问来源于stack exchange,提问作者bicboi
相关产品推荐
相关产品推荐

