用OpenCV实现图像分割:提取Logo中的特定元素并重新着色

用OpenCV实现图像分割:提取Logo中的特定元素并重新着色

任务:将图片中三个圆形图案以及字母(共四个)单独取出 ,分别保存为四个新图片,图片大小与原图一致,图案尽量位于图片中心。三个圆形图案在新图片中改成不与于原来的填充色。

用OpenCV实现图像分割:提取Logo中的特定元素并重新着色_第1张图片

步骤总览

1.读取图片
2.预处理:二值化或色彩分割找目标区域
3.提取每个圆形图案(红、绿、蓝)和文字区域的掩膜
4.将掩膜区域提取出来并改变颜色(对圆形)
5.让内容居中对齐,保存新图片
6.保存为新图片(共四张)
7.完整代码和常见问题解答

第一步:读取图片

背景:几乎所有OpenCV任务都从读图像开始。常用函数是 cv2.imread()。

原理:OpenCV读取图片后会得到一个三维NumPy数组,shape是 (height, width, channels),默认是BGR格式。

函数原型

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颜色空间可以更容易分割出特定颜色(比如红色、绿色、蓝色)。
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 是二维数组,掩膜,白色是提取区域。

常见问题

  • 有时HSV上下限要调,图片不同会有差异。
  • 红色分布在0和180度两头,分两段取。

应用场景

颜色分割、目标检测前处理。

第三步:字母区域掩膜(二值化+形态学处理)

背景

“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:输入
  codecv2.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”字母的掩膜。

常见问题

  • 各掩膜形状需对齐。
  • 少用减法(OpenCV没有直接相减的mask),用“与非”更稳。

应用场景

目标去重、抠像时去背景干扰

第五步:内容提取与居中显示(变色)

背景

要求将掩膜区域提取出来并居中显示,同时为圆圈区域重新赋色,字母区域设为白色。

原理

用mask将内容“抠出来”,赋予指定颜色,再通过数组操作实现居中摆放。

自定义数组操作,无OpenCV专用API。

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)

变量内容

四张同原图大小的新图片,只包含一个内容,且内容居中。

常见问题

  • 居中效果和mask提取区域有关。
  • RGB和BGR颜色顺序注意区分。

应用场景

单目标提取、图片美化、素材抠图、目标重组

第六步: 多图拼接输出一张结果图片

背景

最终需将所有单独区域拼成一张大图,方便展示。

原理

用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)

用OpenCV实现图像分割:提取Logo中的特定元素并重新着色_第2张图片

你可能感兴趣的:(opencv,人工智能,计算机视觉)