如何用5×5核遍历图像并输出滤波后的像素值数组(Python)
手动复现cv2.filter2D遍历过程并记录每次迭代结果
要实现和cv2.filter2D一致的遍历逻辑,同时将每次核处理的结果存入kernel_vals数组,需要明确两个关键点:边界填充处理(cv2.filter2D默认会自动填充边界以保证输出尺寸和输入一致)和互相关运算(OpenCV的滤波本质是互相关而非严格卷积,对于全1核来说结果无差异,但逻辑上要对齐)。
实现步骤与代码
import numpy as np import cv2 # 示例输入:100×100的灰度图(可替换为你的实际图像) image = np.random.randint(0, 256, (100, 100), dtype=np.uint8) # 定义5×5均值核 kernel = np.ones((5, 5), np.float32) / 25 # 初始化存储结果的数组 kernel_vals = [] # 计算核的半径,用于边界填充(5×5核的半径为2) pad_radius = (kernel.shape[0] - 1) // 2 # 对图像做边界填充,匹配cv2.filter2D默认的BORDER_REFLECT_101规则 padded_img = cv2.copyMakeBorder(image, pad_radius, pad_radius, pad_radius, pad_radius, cv2.BORDER_DEFAULT) # 遍历原始图像的每个像素位置(对应filter2D输出的每个像素) for y in range(image.shape[0]): for x in range(image.shape[1]): # 从填充后的图像中提取当前位置对应的5×5图像块 img_patch = padded_img[y:y+kernel.shape[0], x:x+kernel.shape[1]] # 计算互相关:图像块与核逐元素相乘后求和 pixel_val = np.sum(img_patch.astype(np.float32) * kernel) # 转换回原图像的数据类型(如果输入是uint8则取整) pixel_val = np.uint8(pixel_val) if image.dtype == np.uint8 else pixel_val # 计算当前迭代的索引(行优先) iter_idx = y * image.shape[1] + x # 按要求格式存入数组:[[迭代索引], [处理后的像素值]] kernel_vals.append(np.array([[iter_idx], [pixel_val]])) # 验证结果与cv2.filter2D一致性 filtered_img = cv2.filter2D(image, -1, kernel) # 随机取一个位置验证,比如(10,10) print(filtered_img[10,10] == kernel_vals[10*100+10][1][0]) # 输出True表示一致
关键细节说明
- 边界填充:
cv2.filter2D默认使用BORDER_REFLECT_101(即边界像素对称反射,不重复边界值),手动实现时必须用同样的填充规则,否则边缘区域的结果会和filter2D输出不一致。 - 索引计算:采用行优先的索引方式,第y行第x列的像素对应的迭代索引为
y*100 + x,覆盖0到9999的所有迭代(对应100×100的输出图像)。 - 数据类型转换:输入图像通常是
uint8类型,计算时先转为float32避免溢出,结果再转回原类型,和cv2.filter2D的行为对齐。
若仅需有效区域(无边界填充)
如果不需要处理边缘,只保留核完全覆盖图像的有效区域(输出尺寸为96×96),可以去掉边界填充步骤,修改遍历范围:
output_h = image.shape[0] - kernel.shape[0] + 1 output_w = image.shape[1] - kernel.shape[1] + 1 for y in range(output_h): for x in range(output_w): img_patch = image[y:y+5, x:x+5] pixel_val = np.sum(img_patch.astype(np.float32) * kernel) pixel_val = np.uint8(pixel_val) if image.dtype == np.uint8 else pixel_val iter_idx = y * output_w + x kernel_vals.append(np.array([[iter_idx], [pixel_val]]))
内容的提问来源于stack exchange,提问作者Zachary Partlo
相关产品推荐
相关产品推荐

