我需要扫描图像,看看每个像素的3x3窗口中的值是否与某个图案匹配。我使用以下代码
import numpy as np
import cv2
im = cv2.imread("image.png")
h, w = im.shape[:2]
for i in range(1, h-1):
for j in range(1, w-1):
p2 = im[i-1, j]
p3 = im[i-1, j+1]
p4 = im[i, j+1]
p5 = im[i+1, j+1]
p6 = im[i+1, j]
p7 = im[i+1, j-1]
p8 = im[i, j-1]
p9 = im[i-1, j-1]
# code for checking the pattern looks something like this:
if (p2 + p3 + p9) == 1 and p4 == 0 and p5 == 1:
val = True
但上面的代码需要永远完成。我是Python和numpy的新手,如何有效地扫描2d numpy数组?
实际上我正试图将这个thinning code从C ++移植到Python。
答案 0 :(得分:3)
我最终使用scipy.weave来编写用于迭代Numpy数组的内联C ++代码。它使代码运行得非常快。以前天真的方法需要134秒才能完成处理300x150图像。虽然这种方法只需要75毫秒。
如果您感兴趣,以下是Python中的完整细化代码:
# Code for thinning a binary image using Zhang-Suen algorithm
from scipy import weave
import numpy as np
import cv2
import sys
def _thinningIteration(im, iter):
I, M = im, np.zeros(im.shape, np.uint8)
expr = """
for (int i = 1; i < NI[0]-1; i++) {
for (int j = 1; j < NI[1]-1; j++) {
int p2 = I2(i-1, j);
int p3 = I2(i-1, j+1);
int p4 = I2(i, j+1);
int p5 = I2(i+1, j+1);
int p6 = I2(i+1, j);
int p7 = I2(i+1, j-1);
int p8 = I2(i, j-1);
int p9 = I2(i-1, j-1);
int A = (p2 == 0 && p3 == 1) + (p3 == 0 && p4 == 1) +
(p4 == 0 && p5 == 1) + (p5 == 0 && p6 == 1) +
(p6 == 0 && p7 == 1) + (p7 == 0 && p8 == 1) +
(p8 == 0 && p9 == 1) + (p9 == 0 && p2 == 1);
int B = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
int m1 = iter == 0 ? (p2 * p4 * p6) : (p2 * p4 * p8);
int m2 = iter == 0 ? (p4 * p6 * p8) : (p2 * p6 * p8);
if (A == 1 && B >= 2 && B <= 6 && m1 == 0 && m2 == 0) {
M2(i,j) = 1;
}
}
}
"""
weave.inline(expr, ["I", "iter", "M"])
return (I & ~M)
def thinning(src):
dst = src.copy() / 255
prev = np.zeros(src.shape[:2], np.uint8)
diff = None
while True:
dst = _thinningIteration(dst, 0)
dst = _thinningIteration(dst, 1)
diff = np.absolute(dst - prev)
prev = dst.copy()
if np.sum(diff) == 0:
break
return dst * 255
if __name__ == "__main__":
src = cv2.imread("image.png")
if src == None:
sys.exit()
bw = cv2.cvtColor(src, cv2.cv.CV_BGR2GRAY)
_, bw2 = cv2.threshold(bw, 10, 255, cv2.THRESH_BINARY)
bw2 = thinning(bw2)
cv2.imshow("src", bw)
cv2.imshow("thinning", bw2)
cv2.waitKey()
示例源图像和细化结果:
有用的教程:Python Numpy Performance
答案 1 :(得分:1)
你可以用三个回合来做到这一点。创建三个模板/掩码数组
1/3 0 0
1/3 0 0
1/3 0 0
0 0 0
0 0 1
0 0 0
0 0 0
0 0 0
0 0 1
对每个数组执行卷积。然后你的结果将由:
给出output = (convolved_with_first == 1) & (convolved_with_second == 0) & ...
答案 2 :(得分:0)
编辑鉴于您的实际模式搜索,我会选择以下内容:
from numpy.lib.stride_tricks import as strided
win_img = as_strided(im, shape=(h, w - 3 + 1, 3),
strides=im.strides + im.strides[-1:])
cond_1 = np.sum(win_img, axis=-1) == 1
cond_2 = im == 0
cond_3 = im == 1
cond = cond_1[:-2, :] & cond_2[1:-1, 2:] & cond_3[2:, 2:]
现在cond[i, j]
具有以im[i+1, j+1]
为中心的窗口的布尔值,并且在每个方向上比原始图像短两个项目。您可以为整个图像获取一个布尔数组:
cond_im = np.zeros_like(im, dtype=bool)
cond_im[1:-1, 1:-1] = cond
获取阵列的窗口视图:
from numpy.lib.stride_tricks import as strided
win_img = as_strided(im, shape=(h - 3 + 1, w - 3+ 1 , 3, 3),
strides=im.strides * 2)
现在win_img[i, j]
是一个(3, 3)
数组,其中包含左上角3x3
图片i, j
窗口的内容。
如果您所使用的模式是形状为pattern
的数组(3, 3)
,则可以执行以下操作:
np.where(np.all(np.all(win_img == pattern, axis=-1), axis=-1))
获取两个数组的元组,其中窗口左上角的行和列与模式匹配。
这里唯一的问题是,当你执行win_img == pattern
时,会创建一个9倍于图像大小的数组,如果图像非常大,这可能会很麻烦。如果您有内存问题,请将模式检查分成几个波段并循环遍历它们。超过10个波段的for循环仍将比当前两个嵌套循环在图像的整个宽度和高度上快得多。
答案 3 :(得分:0)
您可以尝试以下方法:
result_array = numpy.zeros((h-2, w-2)).astype(bool)
for i in xrange(1, h-1):
for j in xrange(1, w-1):
if (im[i, j+1] == 0 and
im[i+1, j+1] == 1 and
im[i-1,j] + im[i-1,j+1] + im[i-1, j-1]):
result_array[i,j] = True