如何从numpy数组中查找指定尺寸且无零值的圆形图像块
问题描述
假设我有一张灰度图像,其中包含若干黑色像素,如下图所示:
我需要在该图像中查找不含任何零值的图像块,为简化问题,允许图像块重叠。难点在于我需要的不是矩形块,而是圆形块,示例如下:
请注意图像中存在大量符合要求的块,此处仅手动绘制了少量用于演示。
使用嵌套for循环可以实现该需求,但效率较低,并非最优方案,参考代码如下:
# find one circular patch for y in range(-radius, radius): for x in range(-radius, radius): if x**2 + y**2 < radius**2: # this pixel in inside the circular patch patch_x, patch_y = img_x + x, img_y + y
我尝试用卷积操作实现该功能但暂未成功,当前代码如下:
import cv2 import numpy as np radius = 20 img = cv2.imread('img.png', cv2.CV_8UC1) candidates = img != 0 patch_shape = (radius, radius) out = np.lib.stride_tricks.as_strided( candidates, shape=(candidates.shape[0] - patch_shape[0] + 1, \ candidates.shape[1] - patch_shape[1] + 1, \ *patch_shape), strides=2*img.strides, writeable=False, ) patches = np.argwhere(out.all(axis=(-2, -1)))
我的最终目标是从numpy数组中查找所有(至少10个)指定尺寸、无零值的圆形图像块,求最优实现方案。
最优实现方案
核心思路
使用形态学腐蚀操作实现,该逻辑完全匹配需求:只有当圆形结构元覆盖的所有像素均为非零有效值时,对应中心位置才会被标记为有效。OpenCV的形态学操作底层做了高度优化,执行效率远高于手动循环或滑动窗方案。
完整实现代码
import cv2 import numpy as np radius = 20 # 读取灰度图 img = cv2.imread('img.png', cv2.IMREAD_GRAYSCALE) # 1. 生成二值掩码:非零像素标记为255,零像素标记为0 mask = np.where(img != 0, 255, 0).astype(np.uint8) # 2. 生成指定半径的圆形结构元 kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (2 * radius + 1, 2 * radius + 1)) # 3. 执行腐蚀操作,得到的结果中值为255的位置就是符合要求的圆形块圆心 eroded = cv2.erode(mask, kernel) # 4. 提取所有有效圆心坐标,格式为[[y1, x1], [y2, x2], ...] valid_centers = np.argwhere(eroded == 255) # 取前10个符合要求的圆形块中心 top10_centers = valid_centers[:10]
补充说明
- 你之前的滑动窗方案是对整个矩形窗口做全有效校验,没有过滤圆形外的像素,因此得到的是全有效矩形块的左上角,不符合圆形块的校验要求。
- 如果需要允许圆形超出图像边界参与校验,可在腐蚀前对掩码做padding处理:
mask = cv2.copyMakeBorder(mask, radius, radius, radius, radius, cv2.BORDER_CONSTANT, value=0),超出图像范围的部分会被视为无效像素。
内容的提问来源于stack exchange,提问作者ravi
相关产品推荐
相关产品推荐

