Answers:
这可以通过距离变换的卷积来实现。
在蒙版的边缘上使用距离变换。然后对该距离变换进行阈值处理,以删除超出某个距离的值。我认为获取阴影的秘诀在于将距离转换结果与看起来像这样的内核进行卷积:
[ -1.0 -1.0 -1.0
-1.0 0.0 0.0
-1.0 0.0 1.0 ]
这应该使您朝正确的方向开始:
#include "opencv/cv.h"
#include "opencv/highgui.h"
using namespace cv;
using namespace std;
int main() {
Mat mask, dist, bevel;
mask = Mat::zeros(200, 400, CV_8U);
rectangle(mask, Point(30,30), Point(180,180), Scalar(255), -1);
circle(mask, Point(30,30), 50, Scalar(0), -1);
circle(mask, Point(180,180), 50, Scalar(0), -1);
circle(mask, Point(300,100), 75, Scalar(255), -1);
imshow("1",mask);
//find edges and invert image for distance transform
Canny(mask, dist, 50, 150);
dist = 255-dist;
distanceTransform(dist, dist, CV_DIST_L2, CV_DIST_MASK_5);
threshold(dist, dist, 20, 20, CV_THRESH_TRUNC);
blur(dist, dist, Size(3,3));
dist.convertTo(bevel, CV_8U);
equalizeHist(bevel, bevel);
imshow("2",bevel);
//convolve with secret sauce
float d[] = {-1,-2,-3,
-2, 0, 0,
-3, 0, 1 };
Mat kernel(3, 3, CV_32F, d);
kernel = kernel - mean(kernel)[0];
filter2D(dist, dist, CV_32F, kernel);
//normalize filtering result to [-1, 1]
double maxVal;
minMaxLoc(dist, NULL, &maxVal);
dist = 128 * dist / maxVal;
//convert and display result
dist.convertTo(bevel, CV_8U, 1, 128);
bevel = bevel.mul(mask)/255;
imshow("3", bevel);
waitKey(0);
}
Photoshop的Bevel和Emboss可以正常工作:
1)在一个临时的8位单通道图像中计算距离变换
凿子使用带有倒角度量标准的欧几里德距离变换(3x3、5x5或7x7,取决于大小)。如果需要,可以使用精确的欧几里德距离变换,我更喜欢Meijster的方法,因为它可以进行抗锯齿(“用于计算线性时间中距离变换的通用算法”,MEIJSTER)。
平滑斜角使用倒角5-7-11距离变换,然后两次应用盒子模糊,以生成凹凸贴图。
2)将凹凸贴图应用于中间距离变换图像。布林的原始技术是合适的。
3)要进行软化,可以对表面法线进行卷积,也可以使用内核对其进行过滤。
4)使用凹凸贴图,将表面法线与全局光源组合以将照明强度计算为-1到1的值,其中负值是阴影,正值是高光,绝对值是光的强度资源。
5)计算两个8位单通道临时图像,一个来自高光强度,另一个来自阴影。从那里开始,使用颜色,混合模式和不透明度使用每个蒙版对图层进行着色很简单-一个蒙版用于高光,另一个蒙版用于阴影。
可在此处找到用于实现其中一些功能的Visual Basic源代码:
http://www.Planet-Source-Code.com/vb/scripts/ShowCode.asp?txtCodeId=51640&lngWId=1
请访问我的开源LayerEffects项目以了解更多信息:
https://github.com/vinniefalco/LayerEffects.git
我希望这可以帮助别人。