我处理图像像素。我想在一个特定的公式中为我的图像着色,并在使用HSV后将图像转换并保存为RGB空间。Opencv有转换颜色空间的功能,但是图像的颜色改变了我的图像。然后我用这个函数来转换像素,但是我的循环要运行很长时间。我用Python写了一段代码,其中包含一个需要很长时间才能执行的循环。您有哪些操作解决方案可以减少执行时间?我使用了线程,但它没有正确实现,时间也没有减少。我也用了np。Apply_along_axis,但是,这个函数增加了运行时间!
for i in range(row):
for j in range(col):
final[i][j][0], final[i][j][1], final[i][j][2] = colorir.HSV(final[i][j][0], final[i][j][1], final[i][j][2], max_sva=255).rgb()
当我用这段代码转换颜色时,我的图像显示为我想要的正确颜色,但是当我使用以下函数时,图像着色完全错误:
final = cv2.cvtColor(final,cv2.COLOR_HSV2RGB)
或
final = matplotlib.colors.hsv_to_rgb(final)
我想到的另一个问题是,是否有一种方法可以保存在色彩空间HSV中的图像,而无需将其转换为色彩空间RGB?没有涂错颜色?这样我就不必使用上面的运行时代码片段来转换了?
编辑:
我的图像大小是可变的:例如600x600这些循环的执行时间大约是15秒,应该小于1秒。我给灰度图像上色
下面是我的可执行代码:import numpy as np
from numpy import newaxis
import cv2
from colorir import HSV, sRGB
zero1 = np.zeros((row, col), dtype=int)
new1 = np.dstack((zero1, zero1, num12))
new1 = np.where(num12 > 250, 0, num12)
newww = np.where(new1 < 0, 0, new1)
minus = np.subtract(num1, num2)
minus_2 = minus
minus = np.where(minus <=0, 33, minus)
minus = np.where(num2 >= np.multiply(num1 , 1.1), 33, minus)
minus = np.where(np.logical_and(num2 <= np.multiply(num1 , 1.1),num2 >= np.multiply(num1 , 1)), 107, minus)
minus = np.where(num2 < np.multiply(num1 , 1), 209, minus)
a_255 = np.full([row, col], 255, dtype=int)
final = np.dstack((minus, newww, a_255))
for i in range(row):
for j in range(col):
final[i][j][0], final[i][j][1], final[i][j][2] = HSV(final[i][j][0], final[i][j][1], final[i][j][2], max_sva=255).rgb()
我的最终图像应该只包含我指定的绿色、蓝色和橙色,但是函数1为图像上色的是粉色和黄色,以及不相关的颜色。
一个小例子:
final = [[[105, 213, 235], [105, 213, 235], [105, 213, 235], [105, 213, 235], [105, 213, 235], [105, 213, 235]]]
final = np.asarray(final)
final = cv2.cvtColor(final,cv2.COLOR_HSV2BGR)
cv2.imshow("image", final)
cv2.waitKey(0)
当我使用cv2.cvtColor(final,cv2.COLOR_HSV2BGR)
运行上面的示例代码时,我遇到:
错误(输入图像的深度不支持:'VDepth::contains(depth)'其中'depth'为4 (CV_32S))
我必须使用np.float32
,但np.float32
颜色会破坏最终图像。
有两个问题:
- OpenCV使用0-180的色调通道范围(因为360不适合8位整数)。
- OpenCV默认为BGR,但如果你想要RGB,你需要使用
cv2.COLOR_HSV2RGB
,而不是cv2.COLOR_HSV2BGR
。
这是我对你的例子在最后的版本:
import numpy as np
import cv2
from colorir import HSV, sRGB
hsv = [[[105, 213, 235], [105, 213, 235], [105, 213, 235]]]
hsv = np.asarray(hsv)
rgb_colorir = np.zeros_like(hsv)
for i in range(hsv.shape[0]):
for j in range(hsv.shape[1]):
rgb_colorir[i][j][0], rgb_colorir[i][j][1], rgb_colorir[i][j][2] = HSV(hsv[i][j][0], hsv[i][j][1], hsv[i][j][2], max_sva=255).rgb()
hsv[:,:,0] //= 2 # OpenCV's different definition
hsv = hsv.astype(np.uint8) # OpenCV requires uint8
rgb_opencv = cv2.cvtColor(hsv, cv2.COLOR_HSV2RGB)
检查转换后的图像:
>>> rgb_colorir
array([[[ 88, 235, 39],
[ 88, 235, 39],
[ 88, 235, 39]]])
>>> rgb_opencv
array([[[ 91, 235, 39],
[ 91, 235, 39],
[ 91, 235, 39]]], dtype=uint8)
所以我们可以看到红色通道有一个小的差异,这可能是由舍入误差引起的。对于OpenCV的情况,我们必须将色调四舍五入到最接近的偶数度(因为整数除以2)。看到这种差异应该相当困难。
如果您想使用更精确的转换,请注意colorir.HSV
只是调用colorsys.hsv_to_rgb
,并且做了大量额外的工作,例如构建对象。但是除了标准化之外,它没有给你任何额外的东西。直接使用colorsys.hsv_to_rgb
应该更快。另外,colorsys
是标准库的一部分,所以最好直接使用它。
使用np.apply_along_axis()
来遍历图像。这应该是相对较快的,但它不会像OpenCV解决方案那么快。
import colorsys
rgb_colorsys = np.apply_along_axis(
lambda hsv: colorsys.hsv_to_rgb(hsv[0] / 360, hsv[1] / 255, hsv[2] / 255),
2,
hsv,
) * 255
结果:
>>> rgb_colorsys
array([[[ 87.77941176, 235. , 38.70588235],
[ 87.77941176, 235. , 38.70588235],
[ 87.77941176, 235. , 38.70588235]]])
当然你也可以尝试其他的库,比如scikit-image:
import skimage.color
rgb_skimage = skimage.color.hsv2rgb(hsv / [360, 255, 255]) * 255
Scikit-image对于如何存储HSV值也有不同的定义。它也适用于浮点格式,以避免舍入错误。结果:
>>> rgb_skimage
array([[[ 87.77941176, 235. , 38.70588235],
[ 87.77941176, 235. , 38.70588235],
[ 87.77941176, 235. , 38.70588235]]])
与DIPlib(披露:我是作者):
import diplib as dip
hsv_dip = dip.Convert(dip.Image(hsv, tensor_axis=2), "SFLOAT")
hsv_dip.SetColorSpace("HSV")
rgb_dip = dip.ColorSpaceManager.Convert(hsv_dip / [1, 255, 1], "RGB")
结果:
>>> np.asarray(rgb_dip)
array([[[ 87.77941176, 235. , 38.70588235],
[ 87.77941176, 235. , 38.70588235],
[ 87.77941176, 235. , 38.70588235]]])
请注意,OpenCV是唯一具有显著舍入误差的实现,其他实现产生相同的值。
对于浮点结果,np.round(...).astype(np.uint8)
将为您提供可以在pyplot中正常显示的RGB图像:
>>> np.round(rgb_dip).astype(np.uint8)
array([[[ 88, 235, 39],
[ 88, 235, 39],
[ 88, 235, 39]]], dtype=uint8)