【问题标题】:trouble displaying image HSI converted to RGB python无法显示图像 HSI 转换为 RGB python
【发布时间】:2019-03-27 02:52:34
【问题描述】:

我一直在研究一种算法,在 python 3 中将 RGB 转换为 HSI,反之亦然,它使用 matplotlib 显示结果图像和每个通道。

问题在于将 HSI 显示为 RGB 结果图像:每个通道单独显示正确,但是当它一起显示树通道时,我得到一个奇怪的图像。

顺便说一句,当我用 OpenCV 保存结果图像时,它会正确显示图像。

Resulted display

我做了什么,但没有任何改变:

  • 将值四舍五入,如果它通过 1,则将 1 赋给像素

  • 在HSI到RGB的转换中,改为用0定义R、G、B数组,用1定义数组

  • 在RGB到HSI的转换中,将[0,360],[0,1],[0,1]之间的值更改为[0,360],[0,255],[0,255]之间的值是否四舍五入

  • 改用 Jupyter notebook,使用 google 或 Spider 的 collab.research

  • 在终端上执行代码,但它给了我空白窗口

显示图片的功能:

def show_images(T, cols=1):
  N = len(T)  
  fig = plt.figure()
  for i in range(N):
      a = fig.add_subplot(np.ceil(N/float(cols)), cols, i+1)
      try:
        img,title = T[i]
      except ValueError:
        img,title = T[i], "Image %d" % (i+1) 
      if(img.ndim == 2):
        plt.gray()
      plt.imshow(img)
      a.set_title(title)
      plt.xticks([0,img.shape[1]]), plt.yticks([0,img.shape[0]])
  fig.set_size_inches(np.array(fig.get_size_inches()) * N)
  plt.show()

然后主函数这样做:

image = bgr_to_rgb(cv2.imread("rgb.png"))

img1 = rgb_to_hsi(image)
img2 = hsi_to_rgb(img1)

show_images([(image,"RGB"),
         (image[:,:,0],"Red"),
         (image[:,:,1],"Green"),
         (image[:,:,2],"Blue")], 4)
show_images([(img1,"RGB->HSI"),
         (img1[:,:,0],"Hue"),
         (img1[:,:,1],"Saturation"),
         (img1[:,:,2],"Intensity")], 4)
show_images([(img2,"HSI->RGB"),
         (img2[:,:,0],"Red"),
         (img2[:,:,1],"Green"),
         (img2[:,:,2],"Blue")], 4)

将 RGB 转换为 HSI:

def rgb_to_hsi(img):
  zmax = 255 # max value
  # values in [0,1]
  R = np.divide(img[:,:,0],zmax,dtype=np.float)
  G = np.divide(img[:,:,1],zmax,dtype=np.float)
  B = np.divide(img[:,:,2],zmax,dtype=np.float)

  # Hue, when R=G=B -> H=90
  a = (0.5)*np.add(np.subtract(R,G), np.subtract(R,B)) # (1/2)*[(R-G)+(R-B)]
  b = np.sqrt(np.add(np.power(np.subtract(R,G), 2) , np.multiply(np.subtract(R,B),np.subtract(G,B))))
  tetha = np.arccos( np.divide(a, b, out=np.zeros_like(a), where=b!=0) ) # when b = 0, division returns 0, so then tetha = 90
  H = (180/math.pi)*tetha # convert rad to degree
  H[B>G]=360-H[B>G]

  # saturation = 1 - 3*[min(R,G,B)]/(R+G+B), when R=G=B -> S=0
  a = 3*np.minimum(np.minimum(R,G),B) # 3*min(R,G,B)
  b = np.add(np.add(R,G),B) # (R+G+B)
  S = np.subtract(1, np.divide(a,b,out=np.ones_like(a),where=b!=0))

  # intensity = (1/3)*[R+G+B]
  I = (1/3)*np.add(np.add(R,G),B)

  return np.dstack((H, zmax*S, np.round(zmax*I))) # values between [0,360], [0,255] e [0,255]

将 HSI 转换为 RGB:

  def f1(I,S): # I(1-S)
    return np.multiply(I, np.subtract(1,S))
  def f2(I,S,H): # I[1+(ScosH/cos(60-H))]
    r = math.pi/180
    a = np.multiply(S, np.cos(r*H)) # ScosH
    b = np.cos(r*np.subtract(60,H)) # cos(60-H)
    return np.multiply(I, np.add(1, np.divide(a,b)) )
  def f3(I,C1,C2): # 3I-(C1+C2)
    return np.subtract(3*I, np.add(C1,C2))

  def hsi_to_rgb(img):
    zmax = 255 # max value
    # values between[0,360], [0,1] and [0,1]
    H = img[:,:,0]
    S = np.divide(img[:,:,1],zmax,dtype=np.float)
    I = np.divide(img[:,:,2],zmax,dtype=np.float)

    R,G,B = np.ones(H.shape),np.ones(H.shape),np.ones(H.shape) # values will be between [0,1]
    # for 0 <= H < 120
    B[(0<=H)&(H<120)] = f1(I[(0<=H)&(H<120)], S[(0<=H)&(H<120)])
    R[(0<=H)&(H<120)] = f2(I[(0<=H)&(H<120)], S[(0<=H)&(H<120)], H[(0<=H)&(H<120)])
    G[(0<=H)&(H<120)] = f3(I[(0<=H)&(H<120)], R[(0<=H)&(H<120)], B[(0<=H)&(H<120)])

    # for 120 <= H < 240
    H = np.subtract(H,120)
    R[(0<=H)&(H<120)] = f1(I[(0<=H)&(H<120)], S[(0<=H)&(H<120)])
    G[(0<=H)&(H<120)] = f2(I[(0<=H)&(H<120)], S[(0<=H)&(H<120)], H[(0<=H)&(H<120)])
    B[(0<=H)&(H<120)] = f3(I[(0<=H)&(H<120)], R[(0<=H)&(H<120)], G[(0<=H)&(H<120)])

    # for 240 <= H < 360
    H = np.subtract(H,120)
    G[(0<=H)&(H<120)] = f1(I[(0<=H)&(H<120)], S[(0<=H)&(H<120)])
    B[(0<=H)&(H<120)] = f2(I[(0<=H)&(H<120)], S[(0<=H)&(H<120)], H[(0<=H)&(H<120)])
    R[(0<=H)&(H<120)] = f3(I[(0<=H)&(H<120)], G[(0<=H)&(H<120)], B[(0<=H)&(H<120)])

    return np.dstack( ((zmax*R) , (zmax*G) , (zmax*B)) ) # values between [0,255]

【问题讨论】:

    标签: python image numpy opencv matplotlib


    【解决方案1】:

    如果你看一下matplotlib的imshow documentation,你会看到以下几行:

    X : array-like or PIL image 图像数据。支持的阵列形状 是:

    (M, N):带有标量数据的图像。数据使用可视化 颜色图。 (M, N, 3):具有 RGB 值(float 或 uint8)的图像。 (M, N, 4):具有 RGBA 值(float 或 uint8)的图像,即包括 透明度。前两个维度 (M, N) 定义行和 图像的列。

    对于浮点数,RGB(A) 值应在 [0 .. 1] 范围内或 [0 .. 255]对于整数。超出范围的值将被剪裁到这些 界限。

    它告诉你它应该在什么范围内......在你的情况下,HSI 值在色调中从 0-360 变为 255,任何高于它的值。这就是为什么 OpenCV 使用 0-180 的 Hue 范围的原因之一,以便能够将其放入该范围内。

    然后 HSI->RGB 似乎以浮点形式返回图像,然后它将在 1.0 中被裁剪。

    这只会发生在显示器上,但如果你保存图像,它很可能会被剪裁,也许它会被保存为 16 位图像。

    可能的解决方案:

    • 将 0-1 或 0-255 的值标准化(这可能会更改最小值和最大值)然后显示(不要忘记将其转换为 np.uint8)。

      李>
    • 创建一个始终在可能值范围内的范围。

    这是出于显示或保存目的...如果您使用 0-360 至少保存为 16 位

    【讨论】:

    • 谢谢@api55!我将这些值标准化为 0-255 并将其转换为 np.uint8,它起作用了!
    • @kuro 没问题,请注意,如果您将 cv2.normalize 与 NORM_MINMAX 一起使用,标准化可能会产生意想不到的结果。如果您手动进行缩放,您可以始终使用相同的最小值和相同的最大值来避免这种意外行为:) 顺便说一句,如果这解决了您的问题,您应该接受有类似问题的人的答案,以知道该解决方案有效
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多