任务:将图片中三个圆形图案以及字母(共四个)单独取出 ,分别保存为四个新图片,图片大小与原图一致,图案尽量位于图片中心。三个圆形图案在新图片中改成不与于原来的填充色。
1.读取图片
2.预处理:二值化或色彩分割找目标区域
3.提取每个圆形图案(红、绿、蓝)和文字区域的掩膜
4.将掩膜区域提取出来并改变颜色(对圆形)
5.让内容居中对齐,保存新图片
6.保存为新图片(共四张)
7.完整代码和常见问题解答
cv2.imread(filename, flags)
filename
:要读取的图片路径。
flags
:
cv2.IMREAD_COLOR
:以彩色方式读取(默认),忽略透明度。
cv2.IMREAD_GRAYSCALE
:灰度模式。
cv2.IMREAD_UNCHANGED
:保留原通道数(包括透明度)。
import cv2
img = cv2.imread('你的图片路径.png', cv2.IMREAD_COLOR)
img
是一个NumPy数组,shape如 (768, 768, 3)。
路径不对:文件名或路径写错会导致img is None。
通道混乱:OpenCV默认BGR,和PIL不一样。
所有图像处理项目的第一步!
要把圆形/文字提取出来,先得“找出来”目标区域。常见办法:颜色分割(因本图颜色非常分明),或二值化(处理黑白)。
利用HSV颜色空间可以更容易分割出特定颜色(比如红色、绿色、蓝色)。
HSV比BGR分割色彩更自然!
转换颜色空间:cv2.cvtColor(src, code)
做掩膜:cv2.inRange(src, lowerb, upperb)
cv2.cvtColo
src
:输入图像
code
:如 cv2.COLOR_BGR2HSV
cv2.inRange
src
:输入图像(如HSV)
lowerb
, upperb
:下界、上界数组,指定筛选的颜色范围
import numpy as np
# 1. 转HSV
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 2. 取红色掩膜
lower_red1 = np.array([0, 100, 100])
upper_red1 = np.array([10, 255, 255])
lower_red2 = np.array([160, 100, 100])
upper_red2 = np.array([180, 255, 255])
mask_red = cv2.inRange(img_hsv, lower_red1, upper_red1) | cv2.inRange(img_hsv, lower_red2, upper_red2)
# 取绿色掩膜
lower_green = np.array([40, 100, 100])
upper_green = np.array([80, 255, 255])
mask_green = cv2.inRange(img_hsv, lower_green, upper_green)
# 取蓝色掩膜
lower_blue = np.array([100, 100, 100])
upper_blue = np.array([140, 255, 255])
mask_blue = cv2.inRange(img_hsv, lower_blue, upper_blue)
mask_red/green/blue
是二维数组,掩膜,白色是提取区域。
颜色分割、目标检测前处理。
“OpenCV”字母为黑色,背景较亮,可用二值化+开运算处理。
灰度化后用阈值分割,选用cv2.THRESH_BINARY_INV
,之后用cv2.morphologyEx
平滑mask。
灰度化:cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
阈值:cv2.threshold(src, thresh, maxval, type)
形态学:cv2.morphologyEx(src, op, kernel, iterations)
cv2.cvtColor
src
:输入
code
:cv2.COLOR_BGR2GRAY
cv2.threshold
src
:输入灰度图
thresh
:阈值(分界线)
maxval
:最大值(合格给的奖励分)
type
:如 cv2.THRESH_BINARY_INV
(反转二值:奖励给不合格的那一边!)
cv2.morphologyEx
src
:输入图片(一般是二值图,0-255的那种)
op
:
cv2.MORPH_ERODE
(腐蚀:吃掉边缘,去小白点/收缩白区域)
cv2.MORPH_DILATE
(膨胀:膨胀:扩大白区域,填小黑洞/连通白块)
cv2.MORPH_OPEN
(开操作(先腐蚀后膨胀):去除小白噪点,保留整体结构)
cv2.MORPH_CLOSE
(闭操作(先膨胀后腐蚀):填补小黑洞,封闭白区域)
cv2.MORPH_TOPHAT
(顶帽:原图-开操作,提取细小高亮区域)
cv2.MORPH_BLACKHAT
(黑帽:黑帽:闭操作-原图,提取细小暗区域)
kernel
:结构元素(就是“刷子”形状,比如3x3的小方块)
iterations
:迭代次数(默认1,做几遍)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, mask_text = cv2.threshold(gray, 80, 255, cv2.THRESH_BINARY_INV)
kernel = np.ones((3,3), np.uint8)
mask_text = cv2.morphologyEx(mask_text, cv2.MORPH_OPEN, kernel, iterations=1)
mask_text
:和图像等大,只有文字部分是255,背景是0。
阈值要调:80 是大致的,你可以根据图片适当调整。
OCR预处理、二值化分割。
字母掩膜同时包含圆圈和字母,需要用掩膜逻辑操作去掉圆圈,只保留字母。
用掩膜或运算合成所有圆圈掩膜,再对字母掩膜做掩膜与非操作,只剩下字母部分。
按位或:cv2.bitwise_or(src1, src2)
按位与:cv2.bitwise_and(src1, src2)
按位非:cv2.bitwise_not(src)
mask_circles = cv2.bitwise_or(mask_red, mask_green)
mask_circles = cv2.bitwise_or(mask_circles, mask_blue)
mask_text_only = cv2.bitwise_and(mask_text, cv2.bitwise_not(mask_circles))
mask_text_only
:仅包含“OpenCV”字母的掩膜。
目标去重、抠像时去背景干扰
要求将掩膜区域提取出来并居中显示,同时为圆圈区域重新赋色,字母区域设为白色。
用mask将内容“抠出来”,赋予指定颜色,再通过数组操作实现居中摆放。
def extract_and_recolor(mask, color_bgr):
out = np.zeros_like(img)
for i in range(3):
out[:,:,i] = mask // 255 * color_bgr[i]
# 居中
ys, xs = np.where(mask > 0)
if len(xs) == 0:
return out
x_min, x_max, y_min, y_max = xs.min(), xs.max(), ys.min(), ys.max()
crop = out[y_min:y_max+1, x_min:x_max+1]
h_img, w_img = img.shape[:2]
h_crop, w_crop = crop.shape[:2]
base = np.zeros_like(img)
y_start = (h_img - h_crop) // 2
x_start = (w_img - w_crop) // 2
base[y_start:y_start+h_crop, x_start:x_start+w_crop] = crop
return base
# 新色方案
purple = (180, 30, 180) # 红变紫
orange = (0, 140, 255) # 绿变橙
yellow = (0, 255, 255) # 蓝变黄
white = (255, 255, 255) # 字母变白
img_red_new = extract_and_recolor(mask_red, purple)
img_green_new = extract_and_recolor(mask_green, orange)
img_blue_new = extract_and_recolor(mask_blue, yellow)
img_text_new = extract_and_recolor(mask_text_only, white)
四张同原图大小的新图片,只包含一个内容,且内容居中。
单目标提取、图片美化、素材抠图、目标重组
最终需将所有单独区域拼成一张大图,方便展示。
用NumPy数组拼接,将四张同尺寸图片摆放到大画布四个象限。
h, w = img.shape[:2]
out = np.zeros((h*2, w*2, 3), dtype=np.uint8)
out[0:h, 0:w] = img_red_new
out[0:h, w:2*w] = img_green_new
out[h:2*h, 0:w] = img_blue_new
out[h:2*h, w:2*w] = img_text_new
cv2.imwrite('result_four_parts_letters_only.png', out)
out
:拼接后的2h×2w大图,四个内容分别位于左上、右上、左下、右下。
视觉演示、图片对比、批量分割结果展示。
import cv2
import numpy as np
img = cv2.imread('/mnt/data/a93d67e5-f727-4a10-a8de-b5bc68ed7513.png')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 圆圈mask
lower_red1 = np.array([0, 70, 50])
upper_red1 = np.array([10, 255, 255])
lower_red2 = np.array([170, 70, 50])
upper_red2 = np.array([180, 255, 255])
mask_red = cv2.inRange(hsv, lower_red1, upper_red1) | cv2.inRange(hsv, lower_red2, upper_red2)
lower_green = np.array([36, 70, 50])
upper_green = np.array([89, 255, 255])
mask_green = cv2.inRange(hsv, lower_green, upper_green)
lower_blue = np.array([90, 70, 50])
upper_blue = np.array([128, 255, 255])
mask_blue = cv2.inRange(hsv, lower_blue, upper_blue)
# 字母掩膜
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, mask_text = cv2.threshold(gray, 80, 255, cv2.THRESH_BINARY_INV)
kernel = np.ones((3,3), np.uint8)
mask_text = cv2.morphologyEx(mask_text, cv2.MORPH_OPEN, kernel, iterations=1)
# 去掉圆圈,只保留字母
mask_circles = cv2.bitwise_or(mask_red, mask_green)
mask_circles = cv2.bitwise_or(mask_circles, mask_blue)
mask_text_only = cv2.bitwise_and(mask_text, cv2.bitwise_not(mask_circles))
# 提取并变色、居中
def extract_and_recolor(mask, color_bgr):
out = np.zeros_like(img)
for i in range(3):
out[:,:,i] = mask // 255 * color_bgr[i]
ys, xs = np.where(mask > 0)
if len(xs) == 0:
return out
x_min, x_max, y_min, y_max = xs.min(), xs.max(), ys.min(), ys.max()
crop = out[y_min:y_max+1, x_min:x_max+1]
h_img, w_img = img.shape[:2]
h_crop, w_crop = crop.shape[:2]
base = np.zeros_like(img)
y_start = (h_img - h_crop) // 2
x_start = (w_img - w_crop) // 2
base[y_start:y_start+h_crop, x_start:x_start+w_crop] = crop
return base
purple = (180, 30, 180)
orange = (0, 140, 255)
yellow = (0, 255, 255)
white = (255, 255, 255)
img_red_new = extract_and_recolor(mask_red, purple)
img_green_new = extract_and_recolor(mask_green, orange)
img_blue_new = extract_and_recolor(mask_blue, yellow)
img_text_new = extract_and_recolor(mask_text_only, white)
h, w = img.shape[:2]
out = np.zeros((h*2, w*2, 3), dtype=np.uint8)
out[0:h, 0:w] = img_red_new
out[0:h, w:2*w] = img_green_new
out[h:2*h, 0:w] = img_blue_new
out[h:2*h, w:2*w] = img_text_new
cv2.imwrite('result_four_parts_letters_only.png', out)