The image is below, I want all black pixels to be transparent and save it to png file.
You can do it fast and vectorised like this:
import cv2
import numpy as np
# Load image as Numpy array in BGR order
na = cv2.imread('I5jKW.png')
# Make a True/False mask of pixels whose BGR values sum to more than zero
alpha = np.sum(na, axis=-1) > 0
# Convert True/False to 0/255 and change type to "uint8" to match "na"
alpha = np.uint8(alpha * 255)
# Stack new alpha layer with existing image to go from BGR to BGRA, i.e. 3 channels to 4 channels
res = np.dstack((na, alpha))
# Save result
cv2.imwrite('result.png', res)
Notes:
1 You could equally use cv2.merge() in place of np.dstack() and it is probably faster.
2 You could equally use PIL/Pillow in place of the OpenCV functions to read/save images.
Here is another way to do that in Python/OpenCV/Numpy.
import cv2
import numpy as np
# load image
img = cv2.imread('girl_on_black.png')
# threshold on black to make a mask
color = (0,0,0)
mask = np.where((img==color).all(axis=2), 0, 255).astype(np.uint8)
# put mask into alpha channel
result = img.copy()
result = cv2.cvtColor(result, cv2.COLOR_BGR2BGRA)
result[:, :, 3] = mask
# save resulting masked image
cv2.imwrite('girl_on_black_transparent.png', result)
# display result, though it won't show transparency
cv2.imshow("MASK", mask)
cv2.imshow("RESULT", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
According to the documentation:
PNG images with an alpha channel can be saved using this function. To do this, create 8-bit (or 16-bit) 4-channel image BGRA, where the alpha channel goes last. Fully transparent pixels should have alpha set to 0, fully opaque pixels should have alpha set to 255/65535 (see the code sample below).
A transparent image comes with an extra channel which we call alpha channel and denote with BGRA in opencv. All you need to do is that creating a mask image which is in the format of BGRA. Then detect all the black pixels in the image and for those black pixels assign alpha channel of mask image to 0.
Note: With opencv imshow or others you will not be able to see a transparent image because opencv can not display alpha channel. So you need to write it with imwrite in the png format.
Note: Making transparent any pixel means that assigning its alpha channel to 0.
Here is the output of what I mean:
Since I am not familiar with python, I coded the steps in C++. Sorry for that.
#include <iostream>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
int main()
{
cv::Mat img = cv::imread("/ur/input/img.png",cv::IMREAD_COLOR);
cv::Mat mask = cv::Mat::zeros(cv::Size(img.cols,img.rows),CV_8UC4);
cv::namedWindow("Input",0);
cv::namedWindow("Output",0);
for(int i=0; i<mask.cols; i++)
{
for(int j=0; j<mask.rows; j++)
{
if(img.at<cv::Vec3b>(cv::Point(i,j))[0] == 0 &&
img.at<cv::Vec3b>(cv::Point(i,j))[1] == 0 &&
img.at<cv::Vec3b>(cv::Point(i,j))[2] == 0)
{
mask.at<cv::Vec4b>(cv::Point(i,j))[0] = img.at<cv::Vec3b>(cv::Point(i,j))[0];
mask.at<cv::Vec4b>(cv::Point(i,j))[1] = img.at<cv::Vec3b>(cv::Point(i,j))[1];
mask.at<cv::Vec4b>(cv::Point(i,j))[2] = img.at<cv::Vec3b>(cv::Point(i,j))[2];
mask.at<cv::Vec4b>(cv::Point(i,j))[3] = 0;
}
else {
mask.at<cv::Vec4b>(cv::Point(i,j))[0] = img.at<cv::Vec3b>(cv::Point(i,j))[0];
mask.at<cv::Vec4b>(cv::Point(i,j))[1] = img.at<cv::Vec3b>(cv::Point(i,j))[1];
mask.at<cv::Vec4b>(cv::Point(i,j))[2] = img.at<cv::Vec3b>(cv::Point(i,j))[2];
mask.at<cv::Vec4b>(cv::Point(i,j))[3] = 255;
}
}
}
cv::imshow("Input",img);
cv::imshow("Output",mask);
cv::imwrite("/ur/writing/dir/transparent.png",mask);
cv::waitKey(0);
return 0;
}