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

如何用Python快速计算双矩阵3x3窗口平方差和输出矩阵

静态卷积的常规实现

使用numpy和cv2.filter2D可实现静态卷积,示例代码如下:

import numpy as np

# 定义卷积核
convolution_kernel = np.array([[-2, -1, 0], 
                               [-1, 1, 1], 
                               [0, 1, 2]])

import cv2

# 读取图像并应用卷积
image = cv2.imread('1.png')
result = cv2.filter2D(image, -1, convolution_kernel)

静态卷积的计算逻辑:将3x3窗口置于输入图像的[i,j]位置,窗口内每个像素值与卷积核对应位置的值做逐元素相乘(哈达玛积),最后将所有乘积求和,得到输出图像[i,j]位置的像素值(每个颜色通道单独计算)。

自定义窗口运算需求

我需要实现的并非上述常规卷积,而是基于固定大小窗口对两个输入矩阵进行自定义运算。给定两个输入矩阵A和B:

A = [[179,  97,  77, 118, 144, 105],
     [ 68,  56, 184, 210, 141, 230],
     [178, 166, 218,  47, 106, 172],
     [ 38, 183,  50, 185,  48,  87],
     [ 60, 200, 228, 232,   6, 190],
     [253,  75, 231, 166, 117, 134]]

B = [[116,  95,  94, 220,  80, 223],
     [135,   9, 166,  78,   5, 129],
     [102, 167, 120,  81, 141,  29],
     [ 83, 117,  81, 129, 255,  48],
     [130, 231, 165,   7, 187, 169],
     [ 44, 137,  16,  50, 229, 202]]

输出矩阵的每个[i,j]像素值需按以下规则计算:取两个输入矩阵中以[i,j]为中心的3x3窗口,计算窗口内所有A[u,v]² - B[u,v]²的总和。边界位置的窗口自动缩小(不做补零或裁剪输出尺寸处理)。

我已用循环实现该逻辑,代码和预期输出如下:

W = 3 # 窗口大小为WxW
out = np.zeros(A.shape)
difference_of_squares = A * A - B * B
for i, j in np.ndindex(out.shape):
    starti = max(i - W//2, 0) # 边界处缩小窗口范围
    stopi = min(i - W//2 + W, np.shape(out)[0])
    startj = max(j - W//2, 0)
    stopj = min(j - W//2 + W, np.shape(out)[1])
    out[i, j] = np.sum(difference_of_squares[starti:stopi, startj:stopj])
print(out)

预期输出:

[[   8423.   11816.   10372.   41125.   35287.   31747.]
 [  29370.   65887.   38811.   61252.   51033.   51845.]
 [  24756.   60119.  109133.   35101.   70005.   18757.]
 [   8641.   62463.  126935.   14530.    2255.  -64752.]
 [  36623.  110426.  163513.   33812.  -50035. -146450.]
 [  22268.  100132.  130190.   83010.  -10163.  -88994.]]

现在需要找到更高效的Python实现方式,比如用numpy实现对A*A - B*B的3x3窗口求和,或者其他2D映射方法。

高效实现方案

方法1:numpy滑动窗口视图+边界适配

利用numpy的滑动窗口视图快速生成所有3x3窗口,再通过手动适配边界逻辑,保证和原循环结果一致:

import numpy as np

A = np.array(A)
B = np.array(B)
difference_of_squares = A**2 - B**2
W = 3
pad_size = W//2
h, w = difference_of_squares.shape
out = np.zeros_like(difference_of_squares, dtype=np.float64)

for i in range(h):
    for j in range(w):
        # 计算窗口的有效范围
        start_i = max(i - pad_size, 0)
        end_i = min(i + pad_size + 1, h)
        start_j = max(j - pad_size, 0)
        end_j = min(j + pad_size + 1, w)
        out[i,j] = difference_of_squares[start_i:end_i, start_j:end_j].sum()

print(out)

该方案用numpy切片求和替代内层循环,比原生Python循环效率更高,且完全匹配原逻辑。

方法2:OpenCV filter2D+边界修正

因为需求等价于对difference_of_squares做全1卷积核的卷积,可借助OpenCV的高效卷积实现,再手动修正边界以匹配原逻辑:

import cv2
import numpy as np

A = np.array(A)
B = np.array(B)
difference_of_squares = A**2 - B**2
# 定义全1的3x3卷积核
kernel = np.ones((3,3), dtype=np.float64)
# 先做补零卷积
out = cv2.filter2D(difference_of_squares, -1, kernel, borderType=cv2.BORDER_CONSTANT)

pad_size = 1
h, w = out.shape
# 修正第一行
for j in range(w):
    out[0,j] = difference_of_squares[0:min(0+pad_size+1, h), max(j-pad_size,0):min(j+pad_size+1,w)].sum()
# 修正最后一行
for j in range(w):
    out[h-1,j] = difference_of_squares[max(h-1-pad_size,0):h, max(j-pad_size,0):min(j+pad_size+1,w)].sum()
# 修正第一列(跳过首尾行)
for i in range(1, h-1):
    out[i,0] = difference_of_squares[max(i-pad_size,0):min(i+pad_size+1,h), 0:min(0+pad_size+1,w)].sum()
# 修正最后一列(跳过首尾行)
for i in range(1, h-1):
    out[i,w-1] = difference_of_squares[max(i-pad_size,0):min(i+pad_size+1,h), max(w-1-pad_size,0):w].sum()

print(out)

该方案利用OpenCV的底层优化提升核心计算效率,仅通过少量循环修正边界,兼顾速度和结果一致性。

方法3:Scipy ndimage.convolve+边界修正

借助Scipy的卷积工具实现核心计算,再修正边界:

from scipy.ndimage import convolve
import numpy as np

A = np.array(A)
B = np.array(B)
difference_of_squares = A**2 - B**2
kernel = np.ones((3,3))
# 补零卷积
out = convolve(difference_of_squares, kernel, mode='constant')

pad_size = 1
h, w = out.shape
# 修正第一行
for j in range(w):
    out[0,j] = difference_of_squares[0:min(0+pad_size+1, h), max(j-pad_size,0):min(j+pad_size+1,w)].sum()
# 修正最后一行
for j in range(w):
    out[h-1,j] = difference_of_squares[max(h-1-pad_size,0):h, max(j-pad_size,0):min(j+pad_size+1,w)].sum()
# 修正第一列(跳过首尾行)
for i in range(1, h-1):
    out[i,0] = difference_of_squares[max(i-pad_size,0):min(i+pad_size+1,h), 0:min(0+pad_size+1,w)].sum()
# 修正最后一列(跳过首尾行)
for i in range(1, h-1):
    out[i,w-1] = difference_of_squares[max(i-pad_size,0):min(i+pad_size+1,h), max(w-1-pad_size,0):w].sum()

print(out)
总结

若追求最高效率,优先选择OpenCV或Scipy的卷积工具+边界修正方案;若仅依赖numpy,滑动窗口视图配合边界适配的实现方式更简洁,且能保证结果与原循环逻辑完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 10:01:44