采用图像合成公式进行计算,不要把 alpha 通道当成二值图处理;
![](https://img-blog.csdnimg.cn/img_convert/2084d310f1d44aba5c7223d0304b1d67.png)
使用指针直接访问图像数据,遍历像素完成对整张图的处理,并和使用at
函数的版本对比运行时间(注意打开编译优化,visualstudio用release模式)
下图的代码为之前用at函数进行alpha的融合:
![](https://img-blog.csdnimg.cn/img_convert/79d2714d138522c51ddce9c194aa727b.png)
然后这里用指针进行访问像素:
首先定义三个指针,uchar*img_data=img.data等
![](https://img-blog.csdnimg.cn/img_convert/1b8f338090b594365cab4495c9ccc018.png)
然后根据对应通道进行alpha融合。
由于这里将其当成一维数据来处理,所以对应通道需要进行相应的跳跃式
![](https://img-blog.csdnimg.cn/img_convert/a94e19013dac410fc07d6c6623d596d4.png)
![](https://img-blog.csdnimg.cn/img_convert/76b5ed3e742a1748f5f50a5c95d0f688.png)
将两种不同访问像素的方法封装成两个函数,然后在main函数里应用
clock分别进行计时如下:
![](https://img-blog.csdnimg.cn/img_convert/e8b17c27605474ed9792a41311bf2292.png)
两次融合结果如下:可以发现使用指针更快。
![](https://img-blog.csdnimg.cn/img_convert/25dac3c9e2dc0761643d1647f5d4fcd2.png)
问题1:
刚开始用指针访问像素进行alpha融合时,产生了以下问题:
![](https://img-blog.csdnimg.cn/img_convert/b8cf43e78806f4b0f1b238b727a5ac36.png)
解决:由于代码实现是需要两张图片相同尺寸的,所以在alpha融合前需要
将两张图片尺寸进行统一化。
![](https://img-blog.csdnimg.cn/img_convert/9ba057cb0de43fe4c3d9b575af2654fc.png)
1.访问像素值有以下几种方法:
数组索引方法
指针方法
迭代器方法
数组方法介绍:
OpenCV 提供了 at()函数,它是一个模板函数,返回指定位置矩阵元素的引
用,常用的有:
数组方法访问 RGB 图像:Mat.at<Vec3b>(h, w)
数组方法访问灰度图:Mat.at<uchar>(h, w)
如上面的函数所示,数组方法访问图像指定坐标处的像素值主要是调用
Mat 对象的 at 方法,其中(h,w)好理解,就是要访问的像素值得二维坐标,尖括
号里的内容是访问方式,因为 RGB 图像中有 3 个通道各自的像素值,因此以 Vec3b
的方式来访问,即 3 个字节元素的 vector 向量,而灰度图只有一个元素,类型为
uchar 字节数据,因此以 uchar 方式访问。
指针方法介绍:
得到每一行的首地址:Mat.ptr<type>(h)
OpenCV 提供了指针方法来访问操作像素值,h 是行数,得到每一行的首地
址后可以按照这个地址往后对像素值进行遍历。
Mat.ptr<type>(h)返回 Mat 对象
的第 h 行的头指针,如下图所示:
![](https://img-blog.csdnimg.cn/img_convert/e2f3b09843c668d735c30b1dfbb571cb.png)
对于三通道图像,bgr.pt<uchar>(i)同样指向第 i 行的首元素,但是与单通
道的图像不一样,三通道的图像中一个像素点有 BGR 三个像素值,可以看下面的
图来区别单通道和三通道 Mat 在内存中的实际分布情况(假设内存地址从左往右
:
![](https://img-blog.csdnimg.cn/img_convert/ffab701e7f2f7dd884e75bb83df3c51f.png)
因 此 像 gray.ptr<uchar>(0)[0] 那 样 类 型 设 为 uchar 来 操 作 时 ,
bgr.ptr<uchar>(0)[n]得到的是一个像素点内某个通道的值,因为三通道图像一
。
所以对于三通道图像,可以使用 bgr.ptr<Vec3b>(0)[n]>来获得一个像素
点的值,这个时候 vec3b 是一个包含三个值的向量。
用迭代器来遍历:
下面的方法可以让我们来为图像中的像素声明一个迭代器:
MatIterator_<Vec3b> it;
Mat_<Vec3b>::iterator it;
如果迭代器指向一个 const 图像,则可以用下面的声明:
MatConstIterator<Vec3b> it; 或者
Mat_<Vec3b>::const_iterator it;
图像的邻域操作
很多时候,我们对图像处理时,要考虑它的邻域,比如 3*3 是我们常用的,
这在图像滤波、去噪中最为常见,如果在一次图像遍历过程中进行邻域的运算。
下面我们进行一个简单的滤波操作,滤波算子为[0 –1 0;-1 5 –1;0 –1 0]。
它可以让图像变得尖锐,而边缘更加突出。
2.Alpha 融合:
Alpha 融合是一种将前景通过透明度叠加到背景上的过程。透明度通常是图
像的第四通道,当然也可以被分离出来成为一个单独的图像。这个透明的掩模通
常被称为 alpha 掩模。
在上述图片中,左上是前景图片;右上是灰度 alpha 掩模;左下是背景图片,
右下是融合结果。alpha 融合背后的数学原理是相当直接的。在每一个像素位置,
利用 alpha 模板(
a)来融合前景图值和背景图像值。
以上的 alpha 模板的像素值实际计算的时候会从[0,255] 被归一化到
[0,1]。从以上的等式我们知道:
1. 当 a=0, 输出的像素值属于背景。
2. 当 a=1, 输出的像素值属于前景。
3. 当 0<a<1,输出像素值是前背景的混合 ,为何融合效果更自然,通常在
alpha 模板的边界上的像素值是位于 0 到 1 之间。