如何根据初始亮度更改图像中像素的颜色?
How to change the colour of pixels in an image depending on their initial luminosity?
目的是拍摄彩色图像,将一定亮度范围内的任何像素点变为黑色。例如,如果亮度是像素 RGB 值的平均值,则值低于 50 的任何像素都将变为黑色。
我尝试开始使用 PIL 并转换为灰度,但在尝试找到可以识别光度值并使用该信息来操纵像素图的解决方案时遇到了麻烦。
我创建了一个函数,如果像素的亮度小于参数,则 returns 带有 True
的列表,如果不是,则带有 False
。它包括 RGB 或 RGBA 选项(真或假)
def get_avg_lum(pic,avg=50,RGBA=False):
num=3
numd=4
if RGBA==False:
num=2
numd=3
li=[[[0]for y in range(0,pic.size[1])] for x in range(0,pic.size[0])]
for x in range(0,pic.size[0]):
for y in range(0,pic.size[1]):
if sum(pic.getpixel((x,y))[:num])/numd<avg:
li[x][y]=True
else:
li[x][y]=False
return(li)
a=get_avg_lum(im)
列表中的像素匹配,因此图像上的 (0,10) 在列表中为 [0][10]。
希望这对您有所帮助。我的模块用于标准 PIL
对象。
有很多方法可以做到这一点,但最简单且可能最快的方法是使用 Numpy,您应该习惯于在 Python:
中使用图像处理
from PIL import Image
import numpy as np
# Load image and ensure RGB, not palette image
im = Image.open('start.png').convert('RGB')
# Make into Numpy array
na = np.array(im)
# Make all pixels of "na" where the mean of the R,G,B channels is less than 50 into black (0)
na[np.mean(na, axis=-1)<50] = 0
# Convert back to PIL Image to save or display
result = Image.fromarray(na)
result.show()
变成这样:
进入这个:
另一种略有不同的方法是将图像转换为更传统的灰度,而不是平均亮度:
# Load image and ensure RGB
im = Image.open('start.png').convert('RGB')
# Calculate greyscale version
grey = im.convert('L')
# Point process over pixels to make mask of darker ones
mask = grey.point(lambda p: 255 if p<50 else 0)
# Paste black (i.e. 0) into image where mask indicates it is dark
im.paste(0, mask=mask)
请注意,在 PIL 使用的 ITU-R 601-2 亮度变换中,蓝色通道的重要性要低得多(参见蓝色的较低权重 114 与红色的 299 和绿色的 587)在公式中:
L = R * 299/1000 + G * 587/1000 + B * 114/1000
所以蓝色阴影被认为更暗并变成黑色。
另一种方法是像上面那样制作灰度和蒙版。然后在比较原始和蒙版时在每个位置选择较暗的像素:
from PIL import Image, ImageChops
im = Image.open('start.png').convert('RGB')
grey = im.convert('L')
mask = grey.point(lambda p: 0 if p<50 else 255)
res = ImageChops.darker(im, mask.convert('RGB'))
结果与上面相同。
另一种方式,纯 PIL 并且可能最接近您实际要求的方式,是通过对通道进行平均来得出光度值:
# Load image and ensure RGB
im = Image.open('start.png').convert('RGB')
# Calculate greyscale version by averaging R,G and B
grey = im.convert('L', matrix=(0.333, 0.333, 0.333, 0))
# Point process over pixels to make mask of darker ones
mask = grey.point(lambda p: 255 if p<50 else 0)
# Paste black (i.e. 0) into image where mask indicates it is dark
im.paste(0, mask=mask)
另一种方法可能是将图像拆分为其组成的 RGB 通道,计算通道上的数学函数并使用结果遮罩:
from PIL import Image, ImageMath
# Load image and ensure RGB
im = Image.open('start.png').convert('RGB')
# Split into RGB channels
(R, G, B) = im.split()
# Evaluate mathematical function over channels
dark = ImageMath.eval('(((R+G+B)/3) <= 50) * 255', R=R, G=G, B=B)
# Paste black (i.e. 0) into image where mask indicates it is dark
im.paste(0, mask=dark)
目的是拍摄彩色图像,将一定亮度范围内的任何像素点变为黑色。例如,如果亮度是像素 RGB 值的平均值,则值低于 50 的任何像素都将变为黑色。
我尝试开始使用 PIL 并转换为灰度,但在尝试找到可以识别光度值并使用该信息来操纵像素图的解决方案时遇到了麻烦。
我创建了一个函数,如果像素的亮度小于参数,则 returns 带有 True
的列表,如果不是,则带有 False
。它包括 RGB 或 RGBA 选项(真或假)
def get_avg_lum(pic,avg=50,RGBA=False):
num=3
numd=4
if RGBA==False:
num=2
numd=3
li=[[[0]for y in range(0,pic.size[1])] for x in range(0,pic.size[0])]
for x in range(0,pic.size[0]):
for y in range(0,pic.size[1]):
if sum(pic.getpixel((x,y))[:num])/numd<avg:
li[x][y]=True
else:
li[x][y]=False
return(li)
a=get_avg_lum(im)
列表中的像素匹配,因此图像上的 (0,10) 在列表中为 [0][10]。
希望这对您有所帮助。我的模块用于标准 PIL
对象。
有很多方法可以做到这一点,但最简单且可能最快的方法是使用 Numpy,您应该习惯于在 Python:
中使用图像处理from PIL import Image
import numpy as np
# Load image and ensure RGB, not palette image
im = Image.open('start.png').convert('RGB')
# Make into Numpy array
na = np.array(im)
# Make all pixels of "na" where the mean of the R,G,B channels is less than 50 into black (0)
na[np.mean(na, axis=-1)<50] = 0
# Convert back to PIL Image to save or display
result = Image.fromarray(na)
result.show()
变成这样:
进入这个:
另一种略有不同的方法是将图像转换为更传统的灰度,而不是平均亮度:
# Load image and ensure RGB
im = Image.open('start.png').convert('RGB')
# Calculate greyscale version
grey = im.convert('L')
# Point process over pixels to make mask of darker ones
mask = grey.point(lambda p: 255 if p<50 else 0)
# Paste black (i.e. 0) into image where mask indicates it is dark
im.paste(0, mask=mask)
请注意,在 PIL 使用的 ITU-R 601-2 亮度变换中,蓝色通道的重要性要低得多(参见蓝色的较低权重 114 与红色的 299 和绿色的 587)在公式中:
L = R * 299/1000 + G * 587/1000 + B * 114/1000
所以蓝色阴影被认为更暗并变成黑色。
另一种方法是像上面那样制作灰度和蒙版。然后在比较原始和蒙版时在每个位置选择较暗的像素:
from PIL import Image, ImageChops
im = Image.open('start.png').convert('RGB')
grey = im.convert('L')
mask = grey.point(lambda p: 0 if p<50 else 255)
res = ImageChops.darker(im, mask.convert('RGB'))
结果与上面相同。
另一种方式,纯 PIL 并且可能最接近您实际要求的方式,是通过对通道进行平均来得出光度值:
# Load image and ensure RGB
im = Image.open('start.png').convert('RGB')
# Calculate greyscale version by averaging R,G and B
grey = im.convert('L', matrix=(0.333, 0.333, 0.333, 0))
# Point process over pixels to make mask of darker ones
mask = grey.point(lambda p: 255 if p<50 else 0)
# Paste black (i.e. 0) into image where mask indicates it is dark
im.paste(0, mask=mask)
另一种方法可能是将图像拆分为其组成的 RGB 通道,计算通道上的数学函数并使用结果遮罩:
from PIL import Image, ImageMath
# Load image and ensure RGB
im = Image.open('start.png').convert('RGB')
# Split into RGB channels
(R, G, B) = im.split()
# Evaluate mathematical function over channels
dark = ImageMath.eval('(((R+G+B)/3) <= 50) * 255', R=R, G=G, B=B)
# Paste black (i.e. 0) into image where mask indicates it is dark
im.paste(0, mask=dark)