Algoritmo de chanfro alfa de bitmap?


14

Eu estou olhando para criar um algoritmo que adiciona um efeito de chanfro a um bitmap usando alfa como um mapa de relevo.

Como eu faria algo assim? Eu tentei a iluminação especular, mas só consegui o destaque e não a sombra.

Aqui está o efeito que estou falando (feito usando o Photoshop): insira a descrição da imagem aqui

Todos estes foram feitos usando size: 30px(A profundidade do bisel do contorno do mapa de bits), angle 130, altitude 50.

Da esquerda para a direita, de cima para baixo:

  1. Formão Chanfro duro
  2. Cinzel Soft Bevel
  3. Chanfro suave
  4. Cinzel Duro com soften: 16px- um chanfro borrado?

Estou tentando criar cada um desses efeitos, como eu criaria o chanfro básico? e o que eu preciso chegar a cada um deles a partir desse chanfro

Respostas:


10

Isso pode ser realizado com uma convolução da transformação de distância.

Use uma transformação de distância na borda da máscara. Em seguida, limpe essa transformação de distância para remover valores além de alguma distância. Eu acho que o segredo para obter o sombreamento é envolver o resultado da transformação de distância com um kernel que se parece com isso:

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

Isso deve ajudá-lo a começar na direção certa:

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

insira a descrição da imagem aqui

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

insira a descrição da imagem aqui

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

insira a descrição da imagem aqui

    waitKey(0);
}

Aqueles parecem incríveis! Aquele com suavização parece um borrão, mas como eu faria o "Smooth Bevel" deles?
Shedokan

Acredito que o Smooth Bevel desfoque a máscara de distância antes da convolução e o Soften desfoque o resultado após a convolução.
Matt M.

4

O Bevel and Emboss do Photoshop funciona previsivelmente:

1) Calcule uma transformação de distância em uma imagem temporária de canal único de 8 bits

  • O cinzel usa a transformação de distância euclidiana com uma métrica de chanfro (3x3, 5x5 ou 7x7, dependendo do tamanho). Você pode usar uma transformação de distância euclidiana exata, se preferir, a de Meijster, pois ela pode ser feita com anti-alias ("Algoritmo geral para calcular transformações de distância em tempo linear", MEIJSTER).

  • O chanfro suave usa uma transformação de distância de chanfro 5-7-11 seguida de duas aplicações de um desfoque de caixa, para produzir o mapa de relevo.

2) Aplique o mapeamento de relevo à imagem de transformação de distância intermediária. A técnica original de Blinn é adequada.

3) Para amolecer, você pode realizar uma convolução nas normais da superfície ou filtrá-las usando um kernel.

4) Usando o mapa de relevo, as normais da superfície são combinadas com a fonte de luz global para calcular a intensidade da iluminação como um valor de -1 a 1, onde valores negativos são sombras, valores positivos são realces e o valor absoluto é a magnitude da luz. fonte.

5) Duas imagens temporárias de canal único de 8 bits são calculadas, uma das intensidades de destaque e a outra das sombras. A partir daí, é trivial usar cada máscara para colorir a camada usando uma cor, modo de mesclagem e opacidade - uma máscara para os realces e a outra para as sombras.

O código fonte do Visual Basic para implementar parte disso pode ser encontrado aqui:

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

Visite meu projeto de código aberto LayerEffects para saber mais:

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

Espero que isso ajude alguém.


Obrigado, estou muito interessado na transformação de distância gaussiana que você mencionou, conhece algum código disponível? Não consigo ler bem as fórmulas. :(
Shedokan

Não encontrei nada sobre o GDT, além das informações que já publiquei.
Vinnie Falco

O que você quer dizer com "2) Aplicar o mapeamento de relevo à imagem de transformação à distância"? A transformação de distância fornece distâncias (1 número para cada pixel), enquanto o mapeamento Bump exige normais (2 números para cada pixel) ... Você tem certeza de que sabe do que está falando?
Ivan Kuckir

@IvanKuckir Eu deveria ter sido mais claro - uma superfície normal pode ser calculada tratando a transformação de distância como um mapa de altura e calculando dx / dy a partir dos valores verticais e horizontais vizinhos. Esses dois números fornecem o normal necessário para o mapeamento de bump.
Vinnie Falco
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.