基本概念
浮雕就是把所要呈现的图像突起于石头表面,根据凹凸的程度不同从而形成三维的立体感。计算机产生浮雕效果原理与之类似,即通过勾画图像的轮廓,并且降低周围的像素值,从而产生一张具有立体感的浮雕效果图片。这里我们通过相邻元素相减的方法得到轮廓与边缘的差,从而获得凹凸的立体感觉。
基本原理是将图片中像素的点与相邻点的rgb值进行相减,然后加上128,得到中间值灰色。因为相邻点基本上都是rgb比较相似的,所以相似的点的处理结果基本上临近128,而不相近颜色的值则偏离128较远,所以可以得到一个类似于浮雕的图像。
相邻元素相减中“相邻”可以有很多种选择,比如可以用左上一个像素减右下一个像素,即I(x,y)= I(x-1,y-1)- I(x+1,y+1),也可以用左上三个像素减右下三个像素,即I(x,y)= I(x-1,y-1)+ I(x-1,y)+I(x,y-1) -I(x+1,y+1) -I(x+1,y) -I(x,y+1),甚至可以用左上五个像素减右下五个像素。但经过实践,用三个像素相减做出的浮雕不至于太浅,也不至于太深(这里的浅、深指凹凸程度),所以接下来就用三个像素相减的方法。
具体实现方式有遍历、模板(卷积核)、傅里叶变化。傅里叶变化方法的逻辑是傅里叶变换的一个性质——时域中的卷积等于频域里的乘积,可以先把图像以及上面提到的卷积核变换到频域,然后相乘即可。
具体实现
浮雕算法原理:对图像的每一个点进行如下滤波运算(见下图),展开来说,就是对于坐标为(i,j)点,进行的计算为dst(i,j)=src(i+1,j+1) - src(i-1,j-1)+128,然后切剪到0-255之间。
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int calmp(int value, int minValue = 0, int maxValue = 255) {
if (value < minValue)
return minValue;
else if (value > maxValue)
return maxValue;
return value;
}
void reliefTrans(Mat& src, Mat& dst) {
dst = src.clone();
int rowNumber = dst.rows;
int colNumber = dst.cols;
if (src.channels() == 1)
{
for (int i = 1; i < rowNumber - 1; ++i) {
for (int j = 1; j < colNumber - 1; ++j) {
dst.at<uchar>(i, j) = calmp(src.at<uchar>(i + 1, j + 1) - src.at<uchar>(i - 1, j - 1) + 128);
}
}
}
else if (src.channels() == 3) {//color image
for (int i = 1; i < rowNumber - 1; ++i) {
for (int j = 1; j < colNumber - 1; ++j) {
for (int n = 0; n < src.channels(); ++n) {
dst.at<cv::Vec3b>(i, j)[n] = calmp(src.at<cv::Vec3b>(i + 1, j + 1)[n] - src.at<cv::Vec3b>(i - 1, j - 1)[n] + 128);
}
}
}
}
}
int main() {
Mat srcImage = imread("coins.png",0);
Mat dstImage;
reliefTrans(srcImage, dstImage);
imshow("Origin", srcImage);
imshow("Embossment", dstImage);
waitKey(0);
return 0;
}