显示图像HSI转换为RGB python时出现问题

时间:2018-10-23 00:16:39

标签: python image numpy opencv matplotlib

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

麻烦的是显示HSI到RGB生成的图像:仅正确显示了每个通道,但是当一起显示树通道时,我得到了一个奇怪的图像。

顺便说一句,当我用OpenCV保存生成的图像时,它可以正确显示图像。

Resulted display

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

  • 将值取整,如果通过1,则将1赋予像素

  • 在将HSI转换为RGB的过程中,将R,G和B数组定义为零,而将数组定义为1。

  • 在RGB到HSI的转换中,将[0,360],[0,1],[0,1]之间的值更改为[0,360],[0,255],[0,255]之间的舍入或不舍入< / p>

  • 请使用Jupyter笔记本,而不要使用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]

1 个答案:

答案 0 :(得分:0)

如果您查看matplotlib的imshow documentation,将会看到以下几行:

  

X :类似数组或PIL的图像图像数据。支持的阵列形状   是:

     

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

     

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

这将告诉您应该在的范围...就您而言,HSI值在色相中为0-360,高于此值将被裁剪为255。这就是OpenCV使用Hue范围从0-180的原因之一,以便能够将其适合该范围。

然后,HSI-> RGB似乎以浮点数返回图像,然后将其裁剪为1.0。

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

可能的解决方案:

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

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

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