Set white background for a png instead of transparency with OpenCV Set white background for a png instead of transparency with OpenCV python-3.x python-3.x

Set white background for a png instead of transparency with OpenCV


Here's a basic script that will replace all fully transparent pixels with white and then remove the alpha channel.

import cv2#load image with alpha channel.  use IMREAD_UNCHANGED to ensure loading of alpha channelimage = cv2.imread('your image', cv2.IMREAD_UNCHANGED)    #make mask of where the transparent bits aretrans_mask = image[:,:,3] == 0#replace areas of transparency with white and not transparentimage[trans_mask] = [255, 255, 255, 255]#new image without alpha channel...new_img = cv2.cvtColor(image, cv2.COLOR_BGRA2BGR)


I do not know exactly what that error is, but I was testing just now a possible solution for you. Even it is in C++, I guess you can convert it easily to python.

 /* Setting data info */std::string test_image_path = "Galicia.png";/* General variables */cv::namedWindow("Input image", cv::WINDOW_NORMAL);cv::namedWindow("Input image R", cv::WINDOW_NORMAL);cv::namedWindow("Input image G", cv::WINDOW_NORMAL);cv::namedWindow("Input image B", cv::WINDOW_NORMAL);cv::namedWindow("Input image A", cv::WINDOW_NORMAL);cv::namedWindow("Output image", cv::WINDOW_NORMAL);/* Process */cv::Mat test_image = cv::imread(test_image_path, cv::IMREAD_UNCHANGED);std::cout << "Image type: " << test_image.type() << std::endl;// Split channels of the png filesstd::vector<cv::Mat> pngChannels(4);cv::split(test_image, pngChannels);cv::imshow("Input image", test_image);cv::imshow("Input image R", pngChannels[0]);cv::imshow("Input image G", pngChannels[1]);cv::imshow("Input image B", pngChannels[2]);cv::imshow("Input image A", pngChannels[3]);// Set to 255(white) the RGB channels where the Alpha channel(mask) is 0(transparency)pngChannels[0].setTo(cv::Scalar(255), pngChannels[3]==0);pngChannels[1].setTo(cv::Scalar(255), pngChannels[3]==0);pngChannels[2].setTo(cv::Scalar(255), pngChannels[3]==0);// Merge again the channelscv::Mat test_image_output;cv::merge(pngChannels, test_image_output);// Show the merged channels.cv::imshow("Output image", test_image_output);// For saving with changes, conversion is needed.cv::cvtColor(test_image_output, test_image_output, cv::COLOR_RGBA2RGB);cv::imwrite("Galicia_mod.png", test_image_output);

I complement the code with this screenshot that may help you to understand better my solution:

enter image description here

Best Wishes,Arritmic


All previous answers use binarizing but mask can be non binary. In that case you can use alpha blending with white background

def alpha_blend_with_mask(foreground, background, mask): # modified func from link    # Convert uint8 to float    foreground = foreground.astype(float)    background = background.astype(float)    # Normalize the mask mask to keep intensity between 0 and 1    mask = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)    mask = mask.astype(float) / 255    # Multiply the foreground with the mask matte    foreground = cv2.multiply(mask, foreground)    # Multiply the background with ( 1 - mask )    background = cv2.multiply(1.0 - mask, background)    # Add the masked foreground and background.    return cv2.add(foreground, background).astype(np.uint8)img_with_white_background = alpha_blend_with_mask(img[..., :3], np.ones_like(clip_img) * 255, img[..., 3])