一夜未眠,一直在找一个好点的方法将带alpha通道的png图片叠加到其他三通道图片上。

下面进入正题:

在这段代码中,cvAdd4cMat 其实是一个宏,由 CA4M_EXCAT 宏来控制它展开成什么。

#ifdef CA4M_EXCAT
#define cvAdd4cMat cvAdd4cMat_e
#else
#define cvAdd4cMat cvAdd4cMat_q
#endif

注:e版函数是精确版,q版函数是快速版。我也不知道实际使用e版和q版差别多大,速度e版更快,但是绘制出来的质量我用肉眼完全看不出差别,文章后面有我对两版函数速度测试的说明。如果你要直接使用我的模块,那么我建议你不要定义CA4M_EXCAT这个宏。因为我认为q版函数更加优秀。如果你不知道怎么使用它,你可以到底部获得演示程序的下载地址。

原理:

显存中每个点是以BGR方式存储的,B、G、R分别叫蓝色通道、绿色通道、红色通道

而对于一些图片来所,它们还需要有一个A通道,阿尔法通道,即不透明度通道。来控制这个点的不透明度,其实所谓的不透明度,只在与其他图片叠时反应出来。

对于某一个像素点的叠加公式:

   b = b1 * a1/255 + b0 * (255 - a1)/255g = g1 * a1/255 + g0 * (255 - a1)/255r = r1 * a1/255 + r0 * (255 - a1)/255
那么把这个单点的计算公式转换成矩阵的计算公式,通过Opencv对矩阵运算的优势,可极大的提高叠加的效率。
那么我通过split函数分解矩阵的通道
把png图片分解为B1矩阵,G1矩阵,R1矩阵,A1矩阵
把背景图片分解为了B0矩阵,G0矩阵,R0矩阵。
于是叠加的结果:
令alpha = A1 , 令beta = 255 - alpha。注意:alpha和beta依然是矩阵
 B=B1 * alpha/255 + B0 * beta/255G=G1 * alpha/255 + G0 * beta/255R=R1 * alpha/255 + R0 * beta/255
如果使用scale增益这个参数,那么:
newalpha = alpha * scale
newbeta = 255 - newalpha

以上只是该模块的基本思想,为了防止溢出,减少冗余计算,源码在算法上做了较大的调整,具体请看代码了:

cvAdd4cMat.h

#pragma once#include <vector>
#include <opencv2/opencv.hpp>static int createtable = false;//init lookup-table;
static cv::Mat table(1, 256, CV_32FC1);
static cv::Mat otable(1, 256, CV_32FC1);
int cvAdd4cMat_e(cv::Mat &dst, cv::Mat &scr, double scale);
int cvAdd4cMat_e(cv::Mat &dst, cv::Mat &scr);
int cvAdd4cMat_q(cv::Mat &dst, cv::Mat &scr, double scale = 1.0);
void InitLookupTable(void);#ifdef CA4M_EXCAT
#define cvAdd4cMat cvAdd4cMat_e
#else
#define cvAdd4cMat cvAdd4cMat_q
#endif

cvAdd4cMat.cpp

#include "cvAdd4cMat.h"int cvAdd4cMat_e(cv::Mat &dst, cv::Mat &scr, double scale)
{if (createtable == false){InitLookupTable();}if (dst.channels() != 3 || scr.channels() != 4){return 0;}if (scale < 0.01)return 1;std::vector<cv::Mat> scr_channels;std::vector<cv::Mat> dstt_channels;split(scr, scr_channels);split(dst, dstt_channels);CV_Assert(scr_channels.size() == 4 && dstt_channels.size() == 3);cv::Mat alpha(dst.rows, dst.cols, CV_32FC1);LUT(scr_channels[3], table, alpha);for (int i = 0; i < 3; i++){scr_channels[i].convertTo(scr_channels[i], CV_32FC1);dstt_channels[i].convertTo(dstt_channels[i], CV_32FC1);dstt_channels[i] = dstt_channels[i].mul(1 - alpha*scale);dstt_channels[i] += scr_channels[i].mul(alpha * scale);dstt_channels[i].convertTo(dstt_channels[i], CV_8UC1);}merge(dstt_channels, dst);return 1;
}int cvAdd4cMat_e(cv::Mat &dst, cv::Mat &scr)
{if (createtable == false){InitLookupTable();}if (dst.channels() != 3 || scr.channels() != 4){return 0;}std::vector<cv::Mat>scr_channels;std::vector<cv::Mat>dstt_channels;split(scr, scr_channels);split(dst, dstt_channels);CV_Assert(scr_channels.size() == 4 && dstt_channels.size() == 3);cv::Mat alpha(dst.rows, dst.cols, CV_32FC1);cv::Mat beta(dst.rows, dst.cols, CV_32FC1);LUT(scr_channels[3], table, alpha);LUT(scr_channels[3], otable, beta);for (int i = 0; i < 3; i++){scr_channels[i].convertTo(scr_channels[i], CV_32FC1);dstt_channels[i].convertTo(dstt_channels[i], CV_32FC1);dstt_channels[i] = dstt_channels[i].mul(beta);dstt_channels[i] += scr_channels[i].mul(alpha);dstt_channels[i].convertTo(dstt_channels[i], CV_8UC1);}merge(dstt_channels, dst);return 1;
}int cvAdd4cMat_q(cv::Mat &dst, cv::Mat &scr, double scale)
{if (dst.channels() != 3 || scr.channels() != 4){return true;}if (scale < 0.01)return false;std::vector<cv::Mat>scr_channels;std::vector<cv::Mat>dstt_channels;split(scr, scr_channels);split(dst, dstt_channels);CV_Assert(scr_channels.size() == 4 && dstt_channels.size() == 3);if (scale < 1){scr_channels[3] *= scale;scale = 1;}for (int i = 0; i < 3; i++){//newalpha equal scale * alphadstt_channels[i] = dstt_channels[i].mul(255.0 / scale - scr_channels[3], scale / 255.0);dstt_channels[i] += scr_channels[i].mul(scr_channels[3], scale / 255.0);}merge(dstt_channels, dst);return true;
}void InitLookupTable(void)
{for (int i = 0; i < 256; i++){table.at<float>(i) = i / 255.0f;otable.at<float>(i) = 1 - table.at<float>(i);}createtable = true;
}

对两版函数的分析:

for (int i = 0; i < 5000;i++)
cvAdd4cMat(img1_t2, img2);
e版测两次:26344ms 26547ms
q版测两次:20094ms 19996ms

for (int i = 0; i < 5000;i++)
cvAdd4cMat(img1_t2, img2, 1.5);
e版测两次:29851ms 29725ms
q版测两次:21051ms 21023ms

for (int i = 0; i < 5000;i++)
cvAdd4cMat(img1_t2, img2, 0.5);
e版测两次:29281ms 29221ms
q版测两次:22031ms 22031ms

综上看出
  e版函数平均每次绘图4ms,q版函数平均每次绘图6ms。
  e版函数在绘制速度上不如q版函数,e版函数绘制时如果使用scale参数,速度还会减慢10%左右
  q版函数相对更快,但在scale参数小于1时因为算法原因,绘制速度也会减慢10%左右

下面是我写的一个小example:

下载地址:http://download.csdn.net/detail/u013097499/7483975

OPENCV 实现png绘制,alpha通道叠加。相关推荐

  1. python opencv 为图片添加alpha通道并设置透明,判断是否存在alpha通道

    读取图片 使用函数cv2.imread(filepath,flags)读入一副图片 filepath:要读入图片的完整路径 flags:读入图片的标志 cv2.IMREAD_COLOR:默认参数,读入 ...

  2. unity加载sprite_Unity 分离贴图 alpha 通道实践

    引言 在做手机游戏时可能会遇到这些问题: UI 同学天天抱怨 iOS 上一些透明贴图压缩后模糊不堪 一些古早的 Android 手机上同样的贴图吃内存超过其他手机数倍,游戏经常闪退 这篇文章给出了一种 ...

  3. Unity 分离贴图 alpha 通道实践

    在做手机游戏时可能会遇到这些问题: UI 同学天天抱怨 iOS 上一些透明贴图压缩后模糊不堪 一些古早的 Android 手机上同样的贴图吃内存超过其他手机数倍,游戏经常闪退 这篇文章给出了一种手机游 ...

  4. OpenCV绘制透明底的图片,简单易懂讲解alpha通道怎么用

    今天忽然想做抠图和图形绘制,那这里就涉及到一个透明底的问题 OpenCV是很强大的,但是网上大多教程并没有讲清楚 alpha 通道的参数怎么设置 首先我们来看最简单的非 alpha 通道代码: imp ...

  5. 【计算机视觉】OPENCV对于有alpha通道的透明背景图片的读取和图片叠加

    这个是我自己做的粗略的螺旋丸的图,导出为png并带有alpha通道. 最后和一只狗合成成这个样子. 效果还是可以的. 为了实现这个效果,首先我们要明白具有透明通道的图片的OpenCV的读取方式.在Op ...

  6. OPENCV对于有alpha通道的透明背景图片的读取和图片叠加

    这个是我自己做的粗略的螺旋丸的图,导出为png并带有alpha通道. 最后和一只狗合成成这个样子. 效果还是可以的. 为了实现这个效果,首先我们要明白具有透明通道的图片的opencv的读取方式.在Op ...

  7. 使用opencv中的merge()函数为BGR图像添加alpha通道

    先上代码: #!/usr/bin/env python # -*- coding: utf-8 -*- # 图像处理开发需求.图像处理接私活挣零花钱,请加微信/QQ 2487872782 # 图像处理 ...

  8. 【笔记】opencv的python实现·像素处理 像素访问 alpha通道

    像素概念 计算机在处理某个图像时,会首先将其划分为一个个小方块,每个小方块是一个独立的处理单位,成为像素点 记录一些基础语法: ,X[:,0]就是取矩阵X的所有行的第0列的元素,X[:,1] 就是取所 ...

  9. OpenCV中拆分通道、合并通道、alpha通道的讲解及实战演示(附python源码 超详细)

    需要源码和图片请点赞关注收藏后评论区留言私信~~~ 在BGR色彩空间中,图像的通道由B通道.G通道和B通道构成,下面将介绍OpenCV提供的方法拆分和合并通道 一.拆分通道 为了拆分图像中的通道 Op ...

  10. 【Opencv入门】RGB三通道直方图的计算与绘制

    文章目录 一. 直方图概述 Overview of histogram 二.直方图的建立 Establishment of histogram 三.直方图的作用 The function of his ...

最新文章

  1. docker镜像创建redis5.0.3容器集群
  2. java怎么通过ip地址查具体地址_制作通过IP 查询地址的java版程序
  3. 用Unity快速开发太空飞机大战游戏实战经验分享(上)
  4. jdk8永久代从方法区移除的验证
  5. jzoj6826-[2020.10.17提高组模拟]隔膜【博弈论】
  6. UNIX(多线程):13---condition_variable、wait、notify_one、notify_all
  7. LeetCode 1020. 飞地的数量(图的BFS/DFS)
  8. JDK+SDK 环境变量记录
  9. cpu 被挂起和阻塞_同步异步阻塞非阻塞并发并行讲解
  10. Visual Studio Code 使用 ESLint 增强代码风格检查
  11. VS2010:外部依赖目录错误,怎么办
  12. 二十年后的回眸(1)——报到上班
  13. Hvv近期0day总结二
  14. VM14 15 pro Mac更改最大分辨率
  15. vi: 未找到命令_vi技巧和窍门:十个很棒的命令一定会给您的朋友留下深刻的印象...
  16. 美丽炫酷的Html5简历网页模板
  17. 【安全】eWebeditor编辑器上传webshell
  18. Java泛型详解:<T>和Class<T>的使用。泛型类,泛型方法的详细使用实例
  19. C/C++cmath库常用函数
  20. leetcode算法练习 JavaScript实现

热门文章

  1. 计算机地图概括的原理,第五章地图概括与自动综合
  2. red hat linux7下载地址,Red Hat Enterprise Linux 7 百度下载地址分享
  3. 全球及中国电子材料市场需求分析与十四五投资潜力预测报告2021年版
  4. SEO优化:站群的操作方法有哪些,网站集群系统是什么?
  5. 计算机和现代通讯的应用,现代计算机通信技术特点及通信网络的应用.docx
  6. 河北对口升学计算机VB知识点,vb对口升学试题.docx
  7. 2022电大国家开放大学网上形考任务-电子商务概论非免费(非答案)
  8. 以太网--车载以太网
  9. 【渝粤题库】陕西师范大学209019 鲁迅研究 作业(专升本)
  10. 服务器来料检测作用,IQC来料检验项目