使用numpy将图像转换为灰度图

4
我有一个由numpy.array矩阵表示的图像,该矩阵是nxm三元组(r,g,b),我想使用自己的函数将其转换为灰度图像。

我的尝试失败了,无法将nxmx3矩阵转换为单值nxm矩阵,这意味着从数组[r,g,b]开始,我得到了[gray, gray, gray],但我需要gray

例如,初始颜色通道:[150 246 98]。 转换为灰色后:[134 134 134]。 我需要的是:134

我该如何做到这一点?

我的代码:

def grayConversion(image):
    height, width, channel = image.shape
    for i in range(0, height):
        for j in range(0, width):
            blueComponent = image[i][j][0]
            greenComponent = image[i][j][1]
            redComponent = image[i][j][2]
            grayValue = 0.07 * blueComponent + 0.72 * greenComponent + 0.21 * redComponent
            image[i][j] = grayValue
    cv2.imshow("GrayScale",image)
    return image

请使用向量化代替嵌套的for循环。 - Quickbeam2k1
你能详细说明一下吗?@Quickbeam2k1 - thesamiroli
我不确定我是否正确理解了你的问题。opencv转换方面到底有什么问题?你想自己实现opencv转换吗? - xFL
OpenCV转换没有任何问题。 是的,我想要一个实现自己代码的图像二维数组。 - thesamiroli
如果我的回答解决了你的问题,请考虑接受它作为正确答案。 - Luca Cappelletti
显示剩余4条评论
3个回答

5

以下是可用的代码示例:

def grayConversion(image):
    grayValue = 0.07 * image[:,:,2] + 0.72 * image[:,:,1] + 0.21 * image[:,:,0]
    gray_img = grayValue.astype(np.uint8)
    return gray_img

orig = cv2.imread(r'C:\Users\Jackson\Desktop\drum.png', 1)
g = grayConversion(orig)

cv2.imshow("Original", orig)
cv2.imshow("GrayScale", g)
cv2.waitKey(0)
cv2.destroyAllWindows()

2

使用apply_along_axis的解决方案

可以使用apply_along_axis来实现解决方案:

import numpy as np
def grayscale(colors):
    """Return grayscale of given color."""
    r, g, b = colors
    return 0.21 * r + 0.72 * g + 0.07 * b

image = np.random.uniform(255, size=(10,10,3))
result = np.apply_along_axis(grayscale, 2, image)

示例

10x10 图像

现在我们可以开始可视化结果:

from matplotlib import pyplot as plt
plt.subplot(1,2,1)
plt.imshow(image)
plt.subplot(1,2,2)
plt.imshow(result, cmap='gray')

Example results

文本示例(2x2图像)

为了在文本中呈现实际结果,我将使用一个较小的数组,只是一个2x2的图像:

image = np.random.uniform(250, size=(2,2,3))

这段内容是:

array([[[205.02229826, 109.56089703, 163.74868594],
    [ 11.13557763, 160.98463727, 195.0294515 ]],

   [[218.15273335,  84.94373737, 197.70228018],
    [ 75.8992683 , 224.49258788, 146.74468294]]])

让我们使用自定义
result = np.apply_along_axis(grayscale, 2, image)

"并且转换的输出为:"
array([[127.62263079, 157.64461409],
   [117.94766108, 197.76399547]])

我们也可以使用与上面相同的代码来可视化这个简单的示例:

Smaller example

进一步建议

如果您想应用自己的自定义函数,则apply_along_axis是正确的方法,但您应该考虑使用更纯粹的numpy方法,如Eric提出的方法,或者如果可能的话,只需使用cv2选项加载黑白图像:

cv2.imread('smalltext.jpg',0)

那么,结果变量应该是灰度图像,对吗?或者我错过了什么,因为当我尝试显示它时,它只显示白色像素。 - thesamiroli
是的,但他要求使用自己的自定义函数。 - Luca Cappelletti
1
你的评论给人留下了误解,认为使用apply_along_axis更好,因为它避免了Python循环 - 但实际上apply_along_axis正是在执行Python循环。 - Eric
Eric 评论已被删除,你是正确的。 - Luca Cappelletti
@thesamiroli 我也这么认为。当使用cv2灰度加载cv2.imread('smalltext.jpg',0)时会发生什么? - Luca Cappelletti
@LucaCappelletti 这不是问题的重点。OP想要使用numpy将图像转换为灰度。 - Jeru Luke

2
您可以使用点积:
gray_image = image.dot([0.07, 0.72, 0.21])

或者甚至可以手动完成整个操作:

b = image[..., 0]
g = image[..., 1]
r = image[..., 2]
gray_image = 0.21 * r + 0.72 * g + 0.07 * b

不要忘记转换回0-255:

gray_image = np.min(gray_image, 255).astype(np.uint8)

图像仍然是一个三维数组。 - thesamiroli
你的意思是 gray_image.ndim == 3 吗?在我的机器上是2。 - Eric

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接