对单个像素的RGB值进行函数迭代

1 投票
1 回答
3827 浏览
提问于 2025-04-18 00:57

我已经打开了我的图片,并且可以访问每个像素的RGB值。现在我想做的是对每个像素的RGB值应用一个函数。也就是说,我不想对整张图片的所有像素都用同样的方法,而是想根据每个像素的蓝色值是否大于红色值和绿色值来决定应用的方式(比如蓝色 > 红色 > 绿色,而不是绿色 > 红色 > 蓝色,等等)。

所以我的问题是,如何访问每个像素的RGB元素(而不是一次性访问整张图片的所有红色、绿色和蓝色值)?最终我的问题会变成“怎么做这个最快?”因为显然对每个像素单独应用一个函数会花费一些时间,但现在我只想找到任何解决方案。

感谢任何建议。

编辑以便更清楚/更具体:

其实我想根据127.5 - abs(127.5 - red/green/blue)的顺序来应用一组不同的指令,而不仅仅是根据红色 > 绿色 > 蓝色的顺序(我最开始是想简化,所以这样说的)。一旦确定了某个像素的顺序,就会应用相应的指令。再次强调,这个是逐个像素处理的——我不是根据整张图片的所有红色值来排序,而是只处理每个像素的RGB值。所以我想做的事情大概是这样的(这里我只展示六种可能顺序中的一种,其他五种为了简洁省略了):

def rgb_manip(red,green,blue):
    r_max = int(127.5 - abs(127.5 - red))
    g_max = int(127.5 - abs(127.5 - green))
    b_max = int(127.5 - abs(127.5 - blue))
    if r_max >= g_max >= b_max:
        if r_max >= g_max  +  b_max:
            new_red = red + g_max + b_max
            new_green = green - g_max
            new_blue = blue - b_max
        else:
            new_red = red + r_max
            new_green = green - r_max + b_max
            new_blue = blue - b_max
    # elif... And so on, with a different set of instructions for each of the 6 possibilities depending on the order of the r_max, g_max, b_max values (e.g., r_max >= b_max >= g_max or g_max >= r_max >= b_max, etc, etc)

1 个回答

2

如果你把图片转换成一个数组,就可以访问每个像素的RGB值,或者获取所有像素的某一个R、G或B值:

from __future__ import division
import numpy as np
from PIL import Image

im = Image.open(imfile)
arr = np.asarray(im)

arr[..., 0]  # All Red values
arr[..., 1]  # All Green values
arr[..., 2]  # All Blue values
arr[0, 0]    # RGB for first corner pixel
arr[m, n]    # RGB for pixel at [m, n]
arr[m, n, 0] # R value for pixel [m, n]
arr[m, n, c] # value for color c at pixel [m, n]

你可以使用 argsort 来给每个像素打分,像这样:

def transform(a, c=255/2):
    return c - np.abs(c - a)

ranking = transform(arr).argsort(axis=-1)

这会把标准值从小到大进行排序,沿着最后一个(颜色)轴进行。所以你会得到一个新的数组,这个数组里的每个“颜色”数组不再是RGB值,而是经过排序后的R、B和G值(我们称它们为“R'、B'、G'”)。比如,如果某个角落的像素有 G' > B' > R',那么 ranking[0, 0] 就会是 [0, 2, 1],因为R'(0)是最小的,接下来是B'(2),最后是最大的G'(1)。

这样做的好处是,你会得到一个数组,告诉你在每个像素上应该使用哪种方法。这个数组最多可以有六种不同的排序方式。建议你为每种排序方式定义一个单独的函数。这样,在函数内部只需要做一次决策(你例子中的第二个嵌套if/else),可以使用 np.where,它可以在满足某个条件的数组部分应用一种操作,而在其他部分应用另一种操作。这种方法只适用于两个选项,但如果有多个选项(if/elif/else),其他技术同样有效。

def bgr(a):
    """ for when B' < G' < R'
    """
    t = transform(a)
    red, green, blue = a.transpose([2,0,1])
    # same as: red, green, blue = a[..., 0], a[..., 1], a[..., 2] 
    r_max, g_max, b_max = t.transpose([2,0,1])
    assert np.all((b_max <= g_max) & (g_max <= r_max)), "doesn't match rank"
    condition = r_max >= g_max + b_max
    new_red = np.where(condition, red + g_max + b_max, red + r_max)
    new_green = np.where(condition, green - g_max, green - r_max + b_max)
    new_blue = blue - b_max
    return np.dstack([new_red, new_green, new_blue])

这个函数只适用于你例子中的第一个 if。我建议为这六种情况各自创建一个新函数,并把它们放进一个字典里,像这样:

functions = {
        (0, 1, 2) : rgb, # for R'<G'<B'
        (0, 2, 1) : rbg, # for R'<B'<G'
        #etc...
        }

如果你的输出也有RGB值:

out = np.empty_like(arr)

那么就循环遍历这六个排名/函数:

for rank, func in functions.items():
    mask = np.all(transform(arr).argsort(-1) == rank, -1)
    out[mask] = func(arr[mask])

撰写回答