【发布时间】:2023-04-01 02:35:01
【问题描述】:
我有一个函数可以循环 opencv 图像的 RGB 像素并对每个像素进行一些更改。但是这种方法很慢,我认为如果我可以使用 numpy 一次完成所有更改,它会快得多。
如何在 Numpy 中而不是循环中制作这些过滤器?
def apply_image_filter(image):
image = cv2.normalize(image, image, 0, 255, cv2.NORM_MINMAX)
h = image.shape[0]
w = image.shape[1]
# loop over the image, pixel by pixel
for y in range(0, h):
for x in range(0, w):
if np.all(image[y, x] == 0): # Ignore black pixels
continue
mean = np.mean(image[y, x])
maxdex = np.argmax(image[y, x])
maxval = image[y, x][maxdex]
# Equal RGB go to white or black
if np.all(image[y, x] == mean):
image[y, x] = [255, 255, 255] if mean > 100 else [0, 0, 0]
continue
# High color equals go to white
if np.all((mean * 0.85) < image[y, x]) and np.all((mean * 1.15) > image[y, x]):
image[y, x] = [255, 255, 255] if mean >= 90 else [0, 0, 0]
continue
if maxval > mean * 1.5:
image[y, x] = [0, 0, 0]
image[y, x][maxdex] = 255
continue
median = np.median(image[y, x])
if maxval > median * 1.5:
image[y, x] = [0, 0, 0]
image[y, x][maxdex] = 255
continue
return image
更具体地说,我如何将条件像素更新移到循环之外。
例如这一行:
if np.all((mean * 0.85) < image[y, x]) and np.all((mean * 1.15) > image[y, x]):
image[y, x] = [255, 255, 255] if mean >= 90 else [0, 0, 0]
它检查像素中的 R、G 和 B 值是否都在像素平均值的 15% 以内,如果是,则根据平均值将像素设置为黑色或白色。
如何移动此条件更新,以便它在一个 Numpy 命令中一次处理所有像素,而不是基于每个像素?
从 cmets 更新:
我已将均值、argmax 和中值移出循环,因此它们首先应用于整个数组。现在执行速度比以前快了大约 60%。但是我仍在为每个像素做条件语句。
def apply_image_filter(image):
image = cv2.normalize(image, image, 0, 255, cv2.NORM_MINMAX)
h = image.shape[0]
w = image.shape[1]
# These Numpy operations are now outside the loop
means = np.mean(image, axis=2)
maxdexes = np.argmax(image, axis=2)
medians = np.median(image, axis=2)
# loop over the image, pixel by pixel
for y in range(0, h):
for x in range(0, w):
if means[y, x] == 0: # Ignore black pixels
continue
# assign to local variables for readability
mean = means[y, x]
maxdex = maxdexes[y, x]
maxval = image[y, x][maxdex]
# Equal RGB go to white or black
if np.all(image[y, x] == mean):
image[y, x] = [255, 255, 255] if mean > 100 else [0, 0, 0]
continue
# High color equals go to white
if np.all((mean * 0.85) < image[y, x]) and np.all((mean * 1.15) > image[y, x]):
image[y, x] = [255, 255, 255] if mean >= 90 else [0, 0, 0]
continue
if maxval > mean * 1.5:
image[y, x] = [0, 0, 0]
image[y, x][maxdex] = 255
continue
if maxval > medians[y, x] * 1.5:
image[y, x] = [0, 0, 0]
image[y, x][maxdex] = 255
continue
return image
更新 #2(我的解决方案)
阅读 cmets 并回答后,我花了一些时间试图弄清楚如何“矢量化”我的代码,并且我相信我设法将我的每一个条件像素语句都移动到一个 numpy 向量操作中,这是我的更新后的代码,与原始代码的作用相同,但运行速度提高了大约 100 倍。
我觉得它失去了一些可读性,但为了 100 倍的加速,我只需要添加好的 cmets。
def apply_image_filter(image):
image = cv2.normalize(image, image, 0, 255, cv2.NORM_MINMAX)
means = np.mean(image, axis=2)
maxdexes = np.argmax(image, axis=2)
maxes = np.amax(image, axis=2)
mins = np.amin(image, axis=2)
image[np.logical_and(means == maxes, means > 100)] = 255
image[np.logical_and(means == maxes, means <= 100)] = 0
up_means = means * 1.15
down_means = means * 0.85
image[np.logical_and(means >= 90, np.logical_and(up_means > maxes, down_means < mins))] = 255
image[np.logical_and(means < 90, np.logical_and(up_means > maxes, down_means < mins))] = 0
up_means = means * 1.5
new_means = np.mean(image, axis=2)
higher_than_mean_logic = np.logical_and(maxes > up_means, new_means < 255)
image[higher_than_mean_logic] = 0
image[higher_than_mean_logic, maxdexes[higher_than_mean_logic]] = 255
new_maxes = np.amax(image, axis=2)
medians = np.median(image, axis=2)
medians_logic = np.logical_and(new_maxes > medians * 1.5, new_maxes < 255)
image[medians_logic] = 0
image[medians_logic, maxdexes[medians_logic]] = 255
return image
【问题讨论】:
-
尝试在询问之前解决这个问题。展示你的尝试。 How to Ask。 -- 这里有一个提示:你可以让
mean = np.mean(image, axis=2)在整个图像上得到它 -
我花了一整天的时间来解决这个问题。因此,根据您的提示,我可以将平均值移到像素循环之外并放置类似
means = np.mean(image, axis=2)然后mean = means[y, x]的内容,但它不会使循环更快。 -
循环不会运行得更快,因为它正在对其中的每个操作进行类型检查。您需要通过 NumPy 或 OpenCV 对操作进行矢量化。目前尚不清楚您要对循环做什么,并且您没有提供能够实际检查功能的测试图像,因此很难帮助您。还有
np.mean对整个矩阵进行操作,所以不知道为什么会出现在循环里面。 -
我的提示是 one 事情要做。您需要掌握这个想法并将其应用于所有其他操作(argmax 也可以采用轴参数......继续)。当您将所有内容移出循环后,循环已变为空。 -- @stateMachine
np.mean对给定的任何内容进行操作。在那个循环中,它被赋予了一个像素。它将返回三个颜色值的平均值。使用轴参数,它只对给定的轴进行操作,而将未提及的轴单独留下。