学习opencv:PS滤镜—浮雕

实现浮雕效果的算子有很多,效果大同小异,不同算子的处理结果在细节上会有所差异。事实上,任何一阶差分算子都可用于实现浮雕效果,简单起见,这里使用算子[-1,1]。

代码如下

#include  
#include   
#include 
#include   

using namespace std;

int main()
{
	int rows, cols, i, j, tmp;
	int shift = 128, alpha = 1;
	cv::Mat img = cv::imread("D:\\timg.jpg");
	rows = img.rows;
	cols = img.cols;
	cv::Mat result(rows, cols - 1, CV_8UC3, cv::Scalar(0, 0, 0));

	for (i = 0; i < rows ; i++)
	{
		cv::Vec3b* data1 = img.ptr(i);
		cv::Vec3b* data2 = result.ptr(i);
		for (j = 0; j < cols - 1; j++)
		{
			tmp = (-data1[j][0] + data1[j + 1][0])*alpha + shift; //alpha决定雕刻"深度"
			data2[j][0] = tmp < 0 ? 0 : tmp>255 ? 255 : tmp;      //限制像素值范围在0~255
			tmp = (-data1[j][1] + data1[j + 1][1])*alpha + shift;
			data2[j][1] = tmp < 0 ? 0 : tmp>255 ? 255 : tmp;
			tmp = (-data1[j][2] + data1[j + 1][2])*alpha + shift;
			data2[j][2] = tmp < 0 ? 0 : tmp>255 ? 255 : tmp;
		}
	}
	cv::imshow("result", result);
	cv::waitKey(10000);
	return 0;
}

注意限制像素值范围很重要,否则当像素值超出范围时,int型数据赋给uchar型数据会溢出,在结果图像中会产生杂色。

效果如下

原图:

学习opencv:PS滤镜—浮雕_第1张图片

                                                                                               图1 原图

效果图:

学习opencv:PS滤镜—浮雕_第2张图片

                                                                                         图2  浮雕效果图 

上图整体呈现灰色,具有浮雕效果的立体感。边缘有略微的彩色,若要消除彩色,可将上图转为灰度图。调整代码中的alpha值,可改变雕刻"深度",增强或减弱立体感。

原理 

浮雕效果的特征是具有一定的立体感,这是通过明暗对比实现的,观察图2,可以发现一块凸起的左右边缘总有一侧比背景暗,而另一侧比背景亮,从而形成一种光线从一侧照向另一侧的视觉效果,进而形成立体感。若消除这种明暗对比,则不会形成立体感,将代码作如下修改,对差分结果取绝对值,去除明暗对比

-  tmp = (-data1[j][0] + data1[j + 1][0])*alpha + shift;
+  tmp = cv::abs(-data1[j][0] + data1[j + 1][0])*alpha + shift;
	
-  tmp = (-data1[j][1] + data1[j + 1][1])*alpha + shift;
+  tmp = cv::abs(-data1[j][1] + data1[j + 1][1])*alpha + shift;

-  tmp = (-data1[j][2] + data1[j + 1][2])*alpha + shift;
+  tmp = cv::abs(-data1[j][2] + data1[j + 1][2])*alpha + shift;

得到如下效果

学习opencv:PS滤镜—浮雕_第3张图片

                                                                                          图3  平面效果

可见,是差分算子决定了处理结果具有立体感。图像中颜色相近区域进行差分处理后,其值接近0,加上shift后像素各通道值均接近shift,因而呈现灰色,而边缘处值有较大变化,因此可能会呈现彩色,且亮度与背景不同,从而形成物体轮廓,边缘的明暗对比形成立体感,从而呈现浮雕效果。下图示意了处理过程

 学习opencv:PS滤镜—浮雕_第4张图片学习opencv:PS滤镜—浮雕_第5张图片

                            图4  原图                                                             图5 差分图

学习opencv:PS滤镜—浮雕_第6张图片

                                                                                          图7  结果图 

因为差分之后会存在负值,负值无法显示,因此需要一个基底衬托,一般取最大值的一半,即128,但不是绝对的。这就是图7中shift的作用,使暗边缘得以显示。

应用

图6到图7的过程可以看成是在一幅单色基底图像上叠加上差分图像,基底图像每个像素每个通道值均为shift,那么基底必须是单色图像吗,如果换成其他图像会呈现什么效果呢?下面我们尝试把一幅图像的差分图像叠加到另一幅图像上,使用图1作为基底,对图8作差分后叠加到基底上,看看会出现什么效果。

                                        

学习opencv:PS滤镜—浮雕_第7张图片

                                                                                                    图8 

代码如下

#include  
#include   
#include 
#include   

using namespace std;

int main()
{
	int rows, cols, i, j, tmp;
	int alpha = 1;
	cv::Mat img1 = cv::imread("D:\\seal.jpg"); //已知seal.jpg宽高均小于timg.jpg
	cv::Mat img2 = cv::imread("D:\\timg.jpg"); //基底图像
	rows = img1.rows;
	cols = img1.cols;

	for (i = 0; i < rows ; i++)
	{
		cv::Vec3b* data1 = img1.ptr(i);
		cv::Vec3b* data2 = img2.ptr(i);
		for (j = 0; j < cols - 1; j++)
		{
			tmp = (-data1[j][0] + data1[j + 1][0])*alpha + data2[j][0];
			data2[j][0] = tmp < 0 ? 0 : tmp>255 ? 255 : tmp;
			tmp = (-data1[j][1] + data1[j + 1][1])*alpha + data2[j][1];
			data2[j][1] = tmp < 0 ? 0 : tmp>255 ? 255 : tmp;
			tmp = (-data1[j][2] + data1[j + 1][2])*alpha + data2[j][2];
			data2[j][2] = tmp < 0 ? 0 : tmp>255 ? 255 : tmp;
		}
	}
	cv::imshow("result", img2);
	cv::waitKey(100000);
	return 0;
}

 效果如下图所示,在图1左上角敲了个钢印。

学习opencv:PS滤镜—浮雕_第8张图片

                                                                                           图9  钢印效果 

 仔细观察可以发现,图9中的钢印中间部分不明显,这是由于只计算了x方向的差分,而印章中间部分在x方向变化小,因此差分值较小。如果叠加上y方向的差分图,就会比较明显。

你可能感兴趣的:(图像处理)