我想将RGB图像转换为黑白RGB图像,其中如果像素的HSV值在某个范围内,则为黑色,否则为白色。
目前,我创建一个新图像,然后通过迭代其数据创建新像素值列表,然后使用.putdata()
将该列表放入形成新图像中。
感觉应该有更快的方法来做到这一点,例如使用.point(),但似乎
.point()不是给定像素,而是0到255的值。是否存在一个基于像素的
.point()转换?
我想将RGB图像转换为黑白RGB图像,其中如果像素的HSV值在某个范围内,则为黑色,否则为白色。
目前,我创建一个新图像,然后通过迭代其数据创建新像素值列表,然后使用.putdata()
将该列表放入形成新图像中。
感觉应该有更快的方法来做到这一点,例如使用.point(),但似乎
.point()不是给定像素,而是0到255的值。是否存在一个基于像素的
.point()转换?
好的,这个是有效的(修复了一些溢出错误):
import numpy, Image
i = Image.open(fp).convert('RGB')
a = numpy.asarray(i, int)
R, G, B = a.T
m = numpy.min(a,2).T
M = numpy.max(a,2).T
C = M-m #chroma
Cmsk = C!=0
# Hue
H = numpy.zeros(R.shape, int)
mask = (M==R)&Cmsk
H[mask] = numpy.mod(60*(G-B)/C, 360)[mask]
mask = (M==G)&Cmsk
H[mask] = (60*(B-R)/C + 120)[mask]
mask = (M==B)&Cmsk
H[mask] = (60*(R-G)/C + 240)[mask]
H *= 255
H /= 360 # if you prefer, leave as 0-360, but don't convert to uint8
# Value
V = M
# Saturation
S = numpy.zeros(R.shape, int)
S[Cmsk] = ((255*C)/V)[Cmsk]
# H, S, and V are now defined as integers 0-255
基于维基百科对HSV的定义。我会在有更多时间时仔细查看它。肯定有加速和可能存在的错误。如果您发现任何问题,请告诉我。干杯。
结果:
从这个色轮开始:
我得到了以下结果:
色相:
值:
饱和度:
c
始终被定义为M-m
。在你的代码中,应该将Value (v
) 的定义更改为 M
。Value 始终是 M
,仅适用于 hexcone 型号。 - PaulC
似乎為零(使用hsvwheel.png)而導致除以零的結果! - Stefan Profanter编辑2:现在返回与Paul代码相同的结果,正如它应该...
import numpy, scipy
image = scipy.misc.imread("test.png") / 255.0
r, g, b = image[:,:,0], image[:,:,1], image[:,:,2]
m, M = numpy.min(image[:,:,:3], 2), numpy.max(image[:,:,:3], 2)
d = M - m
# Chroma and Value
c = d
v = M
# Hue
h = numpy.select([c ==0, r == M, g == M, b == M], [0, ((g - b) / c) % 6, (2 + ((b - r) / c)), (4 + ((r - g) / c))], default=0) * 60
# Saturation
s = numpy.select([c == 0, c != 0], [0, c/v])
scipy.misc.imsave("h.png", h)
scipy.misc.imsave("s.png", s)
scipy.misc.imsave("v.png", v)
这段代码给出了颜色的 Hue 值在 0 到 360 之间,饱和度值在 0 到 1 之间,亮度值在 0 到 1 之间。我以图像格式查看了结果,它们看起来不错。
通过阅读您的问题,我不确定您是否只对 HSV 中的“Value”感兴趣。如果是这样,那么您可以跳过大部分代码。
然后,您可以根据这些值选择像素,并使用类似以下内容的代码将它们设置为 1(或白色/黑色):
newimage = (v > 0.3) * 1
Image.fromarray((255*h/360).astype('uint8'),'L').save('hsvwheel_Hb2.png')
),结果相同。这意味着错误与scipy的misc.imsave()
函数无关。您的算法仍然存在问题。 - PaulM
和 m
的定义 包括 alpha 通道。你的问题在于 scipy 是支持 alpha 的!把 m, M = numpy.min(image, 2), numpy.max(image, 2)
改为 m, M = numpy.min(image[:,:,:3], 2), numpy.max(image[:,:,:3], 2)
就可以解决问题了。 - Paul这个解决方案基于Paul的代码。我修复了除零错误并实现了RGB到HSL的转换。还有HSL到RGB的转换:
import numpy
def rgb_to_hsl_hsv(a, isHSV=True):
"""
Converts RGB image data to HSV or HSL.
:param a: 3D array. Retval of numpy.asarray(Image.open(...), int)
:param isHSV: True = HSV, False = HSL
:return: H,S,L or H,S,V array
"""
R, G, B = a.T
m = numpy.min(a, 2).T
M = numpy.max(a, 2).T
C = M - m #chroma
Cmsk = C != 0
# Hue
H = numpy.zeros(R.shape, int)
mask = (M == R) & Cmsk
H[mask] = numpy.mod(60 * (G[mask] - B[mask]) / C[mask], 360)
mask = (M == G) & Cmsk
H[mask] = (60 * (B[mask] - R[mask]) / C[mask] + 120)
mask = (M == B) & Cmsk
H[mask] = (60 * (R[mask] - G[mask]) / C[mask] + 240)
H *= 255
H /= 360 # if you prefer, leave as 0-360, but don't convert to uint8
# Saturation
S = numpy.zeros(R.shape, int)
if isHSV:
# This code is for HSV:
# Value
V = M
# Saturation
S[Cmsk] = ((255 * C[Cmsk]) / V[Cmsk])
# H, S, and V are now defined as integers 0-255
return H.swapaxes(0, 1), S.swapaxes(0, 1), V.swapaxes(0, 1)
else:
# This code is for HSL:
# Value
L = 0.5 * (M + m)
# Saturation
S[Cmsk] = ((C[Cmsk]) / (1 - numpy.absolute(2 * L[Cmsk]/255.0 - 1)))
# H, S, and L are now defined as integers 0-255
return H.swapaxes(0, 1), S.swapaxes(0, 1), L.swapaxes(0, 1)
def rgb_to_hsv(a):
return rgb_to_hsl_hsv(a, True)
def rgb_to_hsl(a):
return rgb_to_hsl_hsv(a, False)
def hsl_to_rgb(H, S, L):
"""
Converts HSL color array to RGB array
H = [0..360]
S = [0..1]
l = [0..1]
http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSL
Returns R,G,B in [0..255]
"""
C = (1 - numpy.absolute(2 * L - 1)) * S
Hp = H / 60.0
X = C * (1 - numpy.absolute(numpy.mod(Hp, 2) - 1))
# initilize with zero
R = numpy.zeros(H.shape, float)
G = numpy.zeros(H.shape, float)
B = numpy.zeros(H.shape, float)
# handle each case:
mask = (Hp >= 0) == ( Hp < 1)
R[mask] = C[mask]
G[mask] = X[mask]
mask = (Hp >= 1) == ( Hp < 2)
R[mask] = X[mask]
G[mask] = C[mask]
mask = (Hp >= 2) == ( Hp < 3)
G[mask] = C[mask]
B[mask] = X[mask]
mask = (Hp >= 3) == ( Hp < 4)
G[mask] = X[mask]
B[mask] = C[mask]
mask = (Hp >= 4) == ( Hp < 5)
R[mask] = X[mask]
B[mask] = C[mask]
mask = (Hp >= 5) == ( Hp < 6)
R[mask] = C[mask]
B[mask] = X[mask]
m = L - 0.5*C
R += m
G += m
B += m
R *=255.0
G *=255.0
B *=255.0
return R.astype(int),G.astype(int),B.astype(int)
def combineRGB(r,g,b):
"""
Combines separated R G B arrays into one array = image.
scipy.misc.imsave("rgb.png", combineRGB(R,G,B))
"""
rgb = numpy.zeros((r.shape[0],r.shape[1],3), 'uint8')
rgb[..., 0] = r
rgb[..., 1] = g
rgb[..., 2] = b
return rgb
我认为最快的结果可能是通过numpy实现。函数大致如下(更新,添加了更多示例细节):
limg = im.convert("L", ( 0.5, 0.5, 0.5, 0.5 ) )
na = numpy.array ( limg.getdata() )
na = numpy.piecewise(na, [ na > 128 ], [255, 0])
limg.pytdata(na)
limg.save("new.png")
na = numpy.piecewise(na, [ na[0] > 128 ], [255, 0])
但是,你必须小心,因为RGB图像的返回值要么是3元组,要么是4元组。
asarray()
函数是通常的转换技术,因为它可以节省一步。我不清楚你在使用piecewise()
做什么。你能详细说明一下吗? - Paul
scikits.image.color.rgb2hsv()
来获取HSV值,如果你能安装numpy/scipy等库的话,这是很好的选择。但是@paul,我敢打赌PIL中没有HSV函数,因为没有一种图像二进制格式存储它们的数据为HSV值。而且,最近在PIL中几乎没有添加任何东西...<哭脸/> - fish2000