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

基于Numpy/OpenCV实现黑白图像边缘白色像素保留的技术求助

问题描述

处理黑白图像,仅保留与黑色像素相邻的白色像素,其余白色像素转为黑色。已掌握循环列表实现的方法,但希望改用Numpy实现,尝试的代码要么导致图像全黑,要么无任何变化,附上尝试代码及处理前后图像,寻求Numpy或OpenCV解决方案。

尝试代码

from PIL import Image
import numpy as np

a = Image.open('a.png')
a = a.convert('L')
a_np = np.array(a)

# 查看数组
print(a_np)
# 输出示例:
# array([[0, 0, 0, ..., 0, 0, 0],
#        [0, 0, 0, ..., 0, 0, 0],
#        ...,
#        [0, 0, 0, ..., 0, 0, 0]], dtype=uint8)

mask = np.pad(a_np[1:-1,1:-1],1,mode='wrap') != 0
print(mask)
# 输出示例:全False的数组

print(np.where(mask == True))
# 输出示例:(array([ 98,  98, ..., 981]), array([393, ..., 686]))

a_np[mask] = 0
print(a_np)
# 输出全0数组

print(np.where(a_np == 1))
# 输出空数组

处理前后图像

  • 处理前图像:黑白图像,包含大面积白色区域及黑色轮廓/区域
  • 处理后期望图像:仅保留与黑色像素相邻的白色边缘,其余白色区域转为黑色

解决方案

方法一:Numpy实现

核心思路:标记原始白色像素,通过移位操作检查每个白色像素的8邻域是否存在黑色像素,仅保留满足条件的白色像素。

from PIL import Image
import numpy as np

# 读取图像并转为灰度数组(0=黑,255=白)
img = Image.open('a.png').convert('L')
img_np = np.array(img)

# 标记所有白色像素
white_pixels = img_np == 255

# 创建数组,标记每个像素的8邻域是否存在黑色像素
has_black_neighbor = np.zeros_like(img_np, dtype=bool)

# 移位检查8个方向的邻域
has_black_neighbor[1:] |= img_np[:-1] == 0          # 上
has_black_neighbor[:-1] |= img_np[1:] == 0          # 下
has_black_neighbor[:,1:] |= img_np[:,:-1] == 0      # 左
has_black_neighbor[:,:-1] |= img_np[:,1:] == 0      # 右
has_black_neighbor[1:,1:] |= img_np[:-1,:-1] == 0   # 左上
has_black_neighbor[1:,:-1] |= img_np[:-1,1:] == 0   # 右上
has_black_neighbor[:-1,1:] |= img_np[1:,:-1] == 0   # 左下
has_black_neighbor[:-1,:-1] |= img_np[1:,1:] == 0   # 右下

# 保留符合条件的白色像素,其余设为黑色
result_np = np.where(white_pixels & has_black_neighbor, 255, 0).astype(np.uint8)

# 保存结果
result_img = Image.fromarray(result_np)
result_img.save('result_numpy.png')

方法二:OpenCV实现

利用形态学腐蚀操作,快速提取白色区域的边缘(即与黑色相邻的白色像素)。

import cv2
import numpy as np

# 读取灰度图像
img = cv2.imread('a.png', cv2.IMREAD_GRAYSCALE)

# 二值化,确保图像只有黑(0)白(255)两色
_, binary_img = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)

# 创建3x3结构元素,用于腐蚀操作
kernel = np.ones((3,3), np.uint8)

# 腐蚀白色区域,得到内部的白色部分
eroded = cv2.erode(binary_img, kernel, iterations=1)

# 原始白色区域减去腐蚀后的区域,得到边缘(与黑色相邻的白色像素)
result_cv = binary_img - eroded

# 保存结果
cv2.imwrite('result_opencv.png', result_cv)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 17:45:42