What is the best way to convert RGB image to RGBA in python using opencv?
Let’s say I have one array with shape
(185, 198, 3) - it is RGB
and the other is alpha mask with shape (185, 198)
How to merge them and save to file?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
With opencv3, this should work:
Python
# First create the image with alpha channel rgba = cv2.cvtColor(rgb_data, cv2.COLOR_RGB2RGBA) # Then assign the mask to the last channel of the image rgba[:, :, 3] = alpha_data
C++
# First create the image with alpha channel cv::cvtColor(rgb_data, rgba , cv::COLOR_RGB2RGBA); # Split the image for access to alpha channel std::vector<cv::Mat>channels(4); cv::split(rgba, channels); # Assign the mask to the last channel of the image channels[3] = alpha_data; # Finally concat channels for rgba image cv::merge(channels, 4, rgba);
Method 2
You may use cv2.merge() to add the alpha channel to the given RGB image, but first you need to split the RGB image to R, G and B channels, as per the documentation:
Python: cv2.merge(mv[, dst])
- mv – input array or vector of matrices to be merged; all the matrices in mv must have the same size and the same depth.
And this can be done as:
b_channel, g_channel, r_channel = cv2.split(img) alpha_channel = np.ones(b_channel.shape, dtype=b_channel.dtype) * 50 #creating a dummy alpha channel image. img_BGRA = cv2.merge((b_channel, g_channel, r_channel, alpha_channel))
Method 3
Since OpenCV images are just Numpy arrays, you can do this in one-line, nice and fast with Numpy. So here is the setup code:
import numpy as np # We'll synthesise a random image and a separate alpha channel full of 128 - semitransparent im = np.random.randint(0,256,(480,640,3), dtype=np.uint8) alpha = np.full((480,640), 128, dtype=np.uint8)
And here is the solution which is simply to stack the alpha channel onto the image in the “depth” axis, hence dstack():
result = np.dstack((im, alpha))
Method 4
Here is an another simple example using Grabcut, it helps to get the right order of channels when saving the image on disk vs pyplot.
from matplotlib import pyplot as plt
import numpy as np
import cv2
img = cv2.imread('image.jpg')
mask = np.zeros(img.shape[:2], np.uint8)
bgdModel = np.zeros((1,65), np.float64)
fgdModel = np.zeros((1,65), np.float64)
rect = (50, 50, 450, 290)
# Grabcut
cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 5, cv2.GC_INIT_WITH_RECT)
r_channel, g_channel, b_channel = cv2.split(img)
a_channel = np.where((mask==2)|(mask==0), 0, 255).astype('uint8')
img_RGBA = cv2.merge((r_channel, g_channel, b_channel, a_channel))
cv2.imwrite("test.png", img_RGBA)
# Now for plot correct colors :
img_BGRA = cv2.merge((b_channel, g_channel, r_channel, a_channel))
plt.imshow(img_BGRA), plt.colorbar(),plt.show()
Method 5
I’ll post here my answer in C++ since it may be helpful to others (there are already enough answers in python):
std::vector<cv::Mat> matChannels;
cv::split(mat, matChannels);
// create alpha channel
cv::Mat alpha(...);
matChannels.push_back(alpha);
cv::merge(matChannels, dst);
Method 6
import cv2 import numpy as np import skimage.exposure path_input_image="./input_image.png" input_image = cv2.imread(path_input_image2, cv2.IMREAD_UNCHANGED) input_image_alphachann = np.full((input_image.shape[0],input_image.shape[1]), 128, dtype=np.uint8) output_image = np.dstack((input_image, input_image_alphachann)) print(input_image.shape) print(output_image.shape) #(400, 200, 3); 3 channell rgb #(400, 200, 4); 4c channel rgba print(input_image.dtype) print(output_image.dtype) # uint8 path_output_image=path_input_image+'.alpha.png' cv2.imwrite(path_output_image, output_image)
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0