最近在读BGRA带透明通道的图像时,遇到一个bug。对于下图,csdn页面显示是白底的,
但是其实它是一张带透明通道的图像,在mac iterm上显示如下
因此利用opencv进行读取的时候,应该采用如下的方式
img = cv2.imread(image_path,cv2.IMREAD_UNCHANGED)
或者
img = cv2.imread(image_path,-1)
而非默认的方式
img = cv2.imread(image_path)
flags:标志位,{cv2.IMREAD_COLOR,cv2.IMREAD_GRAYSCALE,cv2.IMREAD_UNCHANGED}
cv2.IMREAD_COLOR:默认参数,读入一副彩色图片,忽略alpha通道,可用1作为实参替代
cv2.IMREAD_GRAYSCALE:读入灰度图片,可用0作为实参替代
cv2.IMREAD_UNCHANGED:顾名思义,读入完整图片,包括alpha通道,可用-1作为实参替代
PS:alpha通道,又称A通道,是一个8位的灰度通道,该通道用256级灰度来记录图像中的透明度复信息,定义透明、不透明和半透明区域,其中黑表示全透明,白表示不透明,灰表示半透明
因为如果按照后者的方式进行读取的话,会忽略掉透明通道,保存的时候,会是全黑的图像
打印原始图像矩阵也可以看到,是如下这样一种情况
![VOC 2007 Error Analysis](https://img-blog.csdnimg.cn/2fe41c25bcb241cf8718a24273d12b31.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA54y054y054yq54yq,size_11,color_FFFFFF,t_70,g_se,x_16#pic_center)
而如果按前者进行读取的话,保存的时候也得是png格式才行。
如果想保存的是jpg,也会是黑色。则需要进行BGRA到BGR的图像转换,转化为白底,然后进行保存,代码如下:
def convert_BGRA2BGR(image):
h,w,c = image.shape
b_channel, g_channel, r_channel, a_channel = cv2.split(image)
white = np.zeros((h,w), np.uint8)
white.fill(255)
b_channel = (255 - a_channel) / 255 * white + a_channel / 255 * b_channel
g_channel = (255 - a_channel) / 255 * white + a_channel / 255 * g_channel
r_channel = (255 - a_channel) / 255 * white + a_channel / 255 * r_channel
img_BGR = cv2.merge((b_channel, g_channel, r_channel))
img_BGR = img_BGR.astype(np.uint8)
return img_BGR
c++ 版本
cv::Mat convert_BGRA2BGR(cv::Mat &image){
int h = image.rows;
int w = image.cols;
int c = image.channels();
std::vector<Mat> channels;
split(image, channels);
cv::Mat b = channels[0];
cv::Mat g = channels[1];
cv::Mat r = channels[2];
cv::Mat a = channels[3];
cv::Mat background;
cv::Mat white(a.size(), a.type(), Scalar(255));
background = (white - a).mul(white) / 255;
cv::Mat B = background + (a / 255.0).mul(b);
cv::Mat G = background + (a / 255.0).mul(g);
cv::Mat R = background + (a / 255.0).mul(r);
std::vector<Mat> channels_ = {B,G,R};
cv::Mat imgBGR;
merge(channels_,imgBGR);
return imgBGR;
}