71

I want to convert a gray-scale image with shape (height,width) to a 3 channels image with shape (height,width,nchannels). The work is done with a for-loop, but there must be a neat way. Here is a piece code in program, can someone give a hint. please advice.

 30         if img.shape == (height,width): # if img is grayscale, expand
 31             print "convert 1-channel image to ", nchannels, " image."
 32             new_img = np.zeros((height,width,nchannels))
 33             for ch in range(nchannels):
 34                 for xx in range(height):
 35                     for yy in range(width):
 36                         new_img[xx,yy,ch] = img[xx,yy]
 37             img = new_img
Dylan
  • 1,315
  • 3
  • 12
  • 19
  • 1
    What is the question here? If you just want to change the dimensions, it's a simple reshape-operation. If you want to recreate colors it's not possible without some model / assumptions. Your grayscale image has no color-information and everything you can do is guessing colors (which might be simple and bad and more complex and not that bad; there are no limits). – sascha Oct 18 '16 at 23:38
  • @sascha I want to copy the gray scale image 3 times, so it agrees with the color image shape, then my program can treat the images as the same. But I want to have a better implementation without for-loop – Dylan Oct 18 '16 at 23:44
  • Just use a color conversion; `img_arr = cv2.cvtColor(img_arr, cv2.COLOR_GRAY2RGB)`, see https://docs.opencv.org/4.7.0/de/d25/imgproc_color_conversions.html – Ezward Mar 08 '23 at 20:19

1 Answers1

134

You can use np.stack to accomplish this much more concisely:

img = np.array([[1, 2], [3, 4]])
stacked_img = np.stack((img,)*3, axis=-1)
print(stacked_img)
 # array([[[1, 1, 1],
 #         [2, 2, 2]],
 #        [[3, 3, 3],
 #         [4, 4, 4]]])
Chris Mueller
  • 6,490
  • 5
  • 29
  • 35
  • 2
    I think that OP expects `[ [[1 1 1][2 2 2]] [[3 3 3][4 4 4]] ]` – furas Oct 18 '16 at 23:57
  • 1
    @furas Yep! using `axis=-1` achieves this (making 3 channels) – liamzebedee Oct 18 '17 at 00:44
  • 1
    The above code gets a shape of (w,h,1,3) which is wrong (Py 3.6) I instead needed stacked_img = np.squeeze(np.stack((rescaled,) * 3, -1)) to get it back to (w,h,3) – Richard Keene Jul 26 '18 at 21:06
  • 7
    First of all, it's not `(w,h,...)`, it's `(h,w,...)`. Second, OP's question has image of shape `(w,h)` and not `(w,h,1)`, so the posted solution is exactly right. Third, if you have image of shape `(w,h,1)`, you can use `np.concatenate` instead of `np.stack` and you'll get your desired result i.e. `np.concatenate((img,)*3, axis=-1)`. – Nagabhushan S N Jan 08 '20 at 03:24
  • 1
    One can also use np.tile to achieve this ...... np.tile(np.array( [ [1, 2], [3, 4] ] ))[...,None],(1,1,1)) – Vivasvan Patel Nov 11 '20 at 08:36
  • Came across this looking for a replacement for `from skimage.color import gray2rgb`, thanks for the tip! – Compholio Feb 21 '22 at 16:01