Take the 2-minute tour ×
Signal Processing Stack Exchange is a question and answer site for practitioners of the art and science of signal, image and video processing. It's 100% free, no registration required.

I am looking to create an algorithm which adds a bevel effect to a bitmap using it's alpha as a bump map.

How would I go doing something like this? I have tried specular lighting but I only get the highlight and not the shade.

Here is the effect I am talking about(made using Photoshop): enter image description here

All of these were done using size: 30px(The depth of the bevel from the contour of the bitmap), angle 130, altitude 50.

From left to right, top to bottom:

  1. Chisel Hard bevel
  2. Chisel Soft Bevel
  3. Smooth Bevel
  4. Chisel Hard with soften: 16px - a blurred bevel?

I am trying to create each of these effects, how would I go about creating the basic bevel? and what do I need to get to each of these from that bevel

share|improve this question

2 Answers 2

up vote 8 down vote accepted

This can be accomplished with a convolution of the distance transform.

Use a distance transform on the edge of the mask. Then threshold this distance transform to remove values beyond some distance. I think the secret to getting the shading is to convolve the distance transform result with a kernel that looks something like this:

[ -1.0  -1.0  -1.0
  -1.0   0.0   0.0
  -1.0   0.0   1.0 ]

This should get you started in the right direction:

#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);

enter image description here

    //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);

enter image description here

    //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);

enter image description here

    waitKey(0);
}
share|improve this answer
    
Those look awesome! The one with soften looks like a blur, but how would I go making the "Smooth Bevel" from them? –  Shedokan Oct 29 '11 at 10:36
    
I believe Smooth Bevel blurs the distance mask before convolution, and Soften blurs the result after convolution. –  Matt M. Oct 30 '11 at 0:51

Photoshop's Bevel and Emboss works predictably:

1) Compute a distance transform in a temporary 8-bit single channel image

  • Chisel uses the Euclidean Distance Transform with a Chamfer metric (3x3, 5x5, or 7x7 depending on size). You can use an exact euclidean distance transform if you'd like, I prefer the one from Meijster since it can be made anti-aliased ("A General Algorithm for Computing Distance Transforms in Linear Time", MEIJSTER).

  • Smooth Bevel uses a Chamfer 5-7-11 distance transform followed by two applications of a box blur, to produce the bump map.

2) Apply bump mapping to the intermediate distance transform image. Blinn's original technique is suitable.

3) For softening you can perform a convolution on the surface normals or you can filter them using a kernel.

4) Using the bump map the surface normals are combined with the global light source to compute the lighting intensity as a value from -1 to 1 where negative values are shadows, positive values are highlights, and the absolute value is the magnitude of the light source.

5) Two 8-bit single channel temporary images are calculated, one from the highlight intensities and the other from the shadows. From there it is is trivial matter to use each masks to tint the layer using a colour, blend mode, and opacity - one mask for the highlights and the other for the shadows.

Visual Basic source code for implementing some of this can be found here:

http://www.Planet-Source-Code.com/vb/scripts/ShowCode.asp?txtCodeId=51640&lngWId=1

Please visit my open source LayerEffects project to learn more:

https://github.com/vinniefalco/LayerEffects.git

I hope this helps someone.

share|improve this answer
    
Thank you, I am very much interested in the Gaussian Distance Transform you mentioned, are you aware of any code available? I'm not able to read formulas well. :( –  Shedokan Oct 13 '12 at 21:00
    
I have not found anything about the GDT, other than the information I have already posted. –  Vinnie Falco Oct 13 '12 at 23:54

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.