OpenCV入门(4):透明图像(RGBA)的处理

RGBA色彩空间和Alpha通道

RGBA是代表Red(红色)Green(绿色)Blue(蓝色)和Alpha的色彩空间,虽然它有的时候被描述为一个颜色空间,但是它其实仅仅是在RGB色彩空间上附加了额外的Alpha通道。在计算机图形学中,一个RGB色彩空间的图形,是由红、绿、蓝三个色彩信息通道合成的,每个通道用了8位色彩深度,共计24位,包含了所有彩色信息。为实现图形的透明效果,采取在图形文件的处理与存储中附加上另一个8位信息的方法,这个附加的代表图形中各个素点透明度的通道信息就被叫做Alpha通道。

Alpha通道使用8位二进制数,可以表示256级灰度,取值范围是0~255。值为255的Alpha像素用以定义不透明的彩色像素,而值为0的Alpha通道像素用以定义透明像素,介于黑白之间的灰度(值为30-255)的Alpha像素用以定义不同程度的半透明像素。


处理带Alpha通道的透明图片

在使用OpenCV的imread()读取带透明部分的.png图片时,相对于jpg图片的直接读取,需要处理其alpha通道。如果直接以imread("图片路径", -1)的方式来读取而不作任何处理,直接imshow()出来的图片的透明部分会被自动生成的噪点覆盖。

原图(马赛克为透明部分):

未处理Alpha通道直接加载出来,透明部分被覆盖: 

因此要表现图片的透明情况,只能将其与其他图片叠时才能反映出来,通常是将一个抠过图的透明元素加载到背景中,这也是png格式透明图片在OpenCV中用到的最多的地方。

演示 :将一张背景透明的人物图叠加到背景图上

人物图(png格式,人物后面的马赛克为透明部分):

背景图:

 

代码示例: 

#include <opencv2/opencv.hpp>

using namespace cv;

void imageOverlay(const Mat &srcImage, Mat &dstImage, int x, int y);    // 图像叠加函数的定义

int main()
{
    // 创建两个图像矩阵,分别是要融合的人物和背景
    Mat people, background;
    people = imread("/home/efort/Downloads/people.png", -1);    // 此处要加上参数-1
    background = imread("/home/efort/Downloads/background.jpg");

    // 表示从背景的第(150, 267)开始设置对人物的叠加
    imageOverlay(people, background, 150, 267);
    imshow("富士山下", background);

    waitKey(0);

    return 0;
}

// 图像叠加函数的实现
void imageOverlay(const Mat &people, Mat &background, int x, int y)
{
    int channelNum = 3; // rgb通道数为3
    int alpha = 0;  // alpha值表示图像透明度,0代表完全透明,1代表完全不透明

    for (int i = 0; i < people.rows; i++)
    {
        for(int j = 0; j < people.cols * 3; j += 3)
        {
            alpha = people.ptr<uchar>(i)[j / 3*4 + 3];

            if(alpha != 0)
            {
                for (int k = 0; k < 3; k++)
                {
                    // jpg不存在alpha通道,所以给读取出来的数组增加一个alpha的维度
                    if( (i+y < background.rows) && (i+y>=0) &&
                        ((j+x*3) / 3*3 + k < background.cols*3) && ((j+x*3) / 3*3 + k >= 0) &&
                        (i/channelNum*4 + k < background.cols*4) && (j/channelNum*4 + k >=0) )
                    {
                        background.ptr<uchar>(i+y)[(j+x*channelNum) / channelNum*channelNum + k] = people.ptr<uchar>(i)[(j) / channelNum*4 + k];
                    }
                }
            }
        }
    }
}

 叠加后的运行结果如下:

 
  • 15
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值