前言
这是计算机视觉学习系列的第三篇文章,讲的是如何通过代码实现一些简单的滤镜功能。文章依然以经典的lena图作为操作示例。
基础版------基础色彩变换形成的风格
基本思路:我们可以通过将图片的色彩进行变换,为它赋予一种新的风格,这是最简单的一种滤镜实现方式。opencv已经提供了如下的一些颜色效果:
还提供了一段代码作为用法示例。相关代码这里就不全部复制粘贴了,感兴趣的uu自行查阅官方文档即可。核心代码其实就是这句:
cpp
applyColorMap(img_in, img_color, COLORMAP_DEEPGREEN);
其中,img_in
是输入的原图像的Mat形式,img_color
是处理后的Mat形式图像,COLORMAP_DEEPGREEN
宏对应于上图列表中的不同的颜色。 以下是笔者认为比较好看的效果,风格也是我给命名的。正所谓萝卜青菜各有所爱,大家当看个乐子就好。
复古风:
明艳风:
冷艳风:
森系风:
进阶版------实现Lomo效果
说起Lomo效果,一些喜欢玩相机的朋友应该不会陌生。以下是摘自网络的介绍:
lomo摄影是指使用专门的lomo相机或者其他相机,通过前期或后期的手段,产生夸张色彩和鲜明特点的图片,以及对画面的理解和表达的摄影。
大致思路及主要代码
首先,我们来看一张实现后的效果图:
那么,如何实现这种效果呢?通过观察,我们可以发现和原图像相比,它有两个特点:
- 暗指更暗,亮值更亮,形成的对比更明显。
- 图片中有一个明显的光圈,突出了光圈以内的部分,光圈以外则是阴影。
相应地,可以通过以下步骤来分别实现上述效果:
- 使用LUT(颜色查找表),利用曲线变幻来操纵红色通道。
- 产生曲线的公式是这样的: <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 1 + e − x − 0.5 s \frac{1}{1+e^-\frac{x-0.5}{s}} </math>1+e−sx−0.51
- 对应的编码实现如下:
cpp
const double E = std::exp(1.0);
Mat lut(1, 256, CV_8UC1);
for (int i = 0; i < 256; i++)
{
float x = (float)i / 256.0;
lut.at<uchar>(i) = cvRound(256 * (1 / (1 + pow(E, -((x - 0.5) / 0.1)))));
}
- 对图像进行暗晕效果处理。通俗来说,就是创建一个黑色背景的白色圆圈,并且对其进行模糊处理,从而实现类似于光晕的效果。编码实现如下:
cpp
Mat halo(img.rows, img.cols, CV_32FC3, Scalar(0.3, 0.3, 0.3));
circle(halo, Point(img.cols / 2, img.rows / 2), img.cols / 3, Scalar(1, 1, 1), -1);
blur(halo, halo, Size(img.cols / 3, img.cols / 3));
需要注意的通用点(非仅针对本效果)
那么,如何把上述的高对比图像与光晕相结合呢?其实很简单:把这两个矩阵相乘。
但是需要注意元素数据类型转换的问题。因为输入图像的矩阵元素值是整型,而经过模糊处理后的图像元素值范围则在0~1之间:(图源自官方文档)
为了避免精度丢失,可以先将输入图像转为32位浮点数形式,矩阵相乘后再转回去。代码实现如下:
cpp
Mat tmp;
result.convertTo(tmp, CV_32FC3);
multiply(tmp, halo, tmp);
tmp.convertTo(result, CV_8UC3);
参考资料
- OpenCV: OpenCV modules
- 《Learn Opencv 4 by Building Projects Second Edition》David Millan Escriva等著