Algoritmo bismap alpha bevel?


14

Sto cercando di creare un algoritmo che aggiunge un effetto smussato a una bitmap usando la sua alfa come una mappa di rilievo.

Come potrei fare qualcosa del genere? Ho provato l'illuminazione speculare ma ottengo solo l'evidenziazione e non l'ombra.

Ecco l'effetto di cui sto parlando (realizzato con Photoshop): inserisci qui la descrizione dell'immagine

Tutti questi sono stati fatti usando size: 30px(La profondità della smussatura dal contorno della bitmap),angle 130 , altitude 50.

Da sinistra a destra, dall'alto verso il basso:

  1. Scalpello Smusso duro
  2. Scalpello smusso morbido
  3. Smussatura liscia
  4. Scalpello duro con soften: 16px- uno smusso sfocato?

Sto cercando di creare ciascuno di questi effetti, come potrei fare per creare lo smusso di base? e di cosa ho bisogno per arrivare a ciascuno di questi da quel bisello

Risposte:


10

Ciò può essere realizzato con una convoluzione della trasformazione della distanza.

Utilizzare una trasformazione di distanza sul bordo della maschera. Quindi soglia questa trasformata di distanza per rimuovere valori oltre una certa distanza. Penso che il segreto per ottenere l'ombreggiatura sia convolgere il risultato della trasformazione della distanza con un kernel simile a questo:

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

Questo dovrebbe farti iniziare nella giusta direzione:

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

inserisci qui la descrizione dell'immagine

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

inserisci qui la descrizione dell'immagine

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

inserisci qui la descrizione dell'immagine

    waitKey(0);
}

Sono fantastici! Quello con ammorbidito sembra una sfocatura, ma come potrei andare a fare il "Smooth Bevel" da loro?
Shedokan,

Credo che Smooth Bevel offuschi la maschera di distanza prima della convoluzione e Soften offuschi il risultato dopo la convoluzione.
Matt M.

4

Bevel and Emboss di Photoshop funziona in modo prevedibile:

1) Calcola una trasformazione di distanza in un'immagine temporanea a canale singolo a 8 bit

  • Lo scalpello utilizza la trasformazione della distanza euclidea con una metrica di smusso (3x3, 5x5 o 7x7 a seconda delle dimensioni). Se lo desideri, puoi utilizzare un'esatta trasformazione della distanza euclidea, preferisco quella di Meijster poiché può essere anti-aliasing ("Un algoritmo generale per il calcolo delle trasformazioni di distanza in tempo lineare", MEIJSTER).

  • Smooth Bevel utilizza una trasformazione di distanza 5-7-11 di smusso seguita da due applicazioni di sfocatura di un riquadro, per produrre la mappa di rilievo.

2) Applicare il bump mapping all'immagine di trasformazione della distanza intermedia. La tecnica originale di Blinn è adatta.

3) Per ammorbidire è possibile eseguire una convoluzione sulle normali di superficie oppure filtrarle usando un kernel.

4) Utilizzando la bump map le normali alla superficie vengono combinate con la sorgente di luce globale per calcolare l'intensità della luce come un valore compreso tra -1 e 1 dove i valori negativi sono ombre, i valori positivi sono luci e il valore assoluto è l'entità della luce fonte.

5) Vengono calcolate due immagini temporanee a canale singolo a 8 bit, una dalle intensità di evidenziazione e l'altra dalle ombre. Da lì è banale usare ogni maschera per tingere il livello usando un colore, un metodo di fusione e un'opacità: una maschera per le luci e l'altra per le ombre.

Il codice sorgente di Visual Basic per l'implementazione di alcuni di questi può essere trovato qui:

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

Per ulteriori informazioni, visitare il mio progetto LayerEffects open source:

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

Spero che questo aiuti qualcuno.


Grazie, sono molto interessato alla trasformazione della distanza gaussiana di cui hai parlato, sei a conoscenza di qualche codice disponibile? Non sono in grado di leggere bene le formule. :(
Shedokan,

Non ho trovato nulla sulla GDT, tranne le informazioni che ho già pubblicato.
Vinnie Falco,

Cosa intendi con "2) Applica la mappatura di rilievo all'immagine di trasformazione della distanza"? La trasformazione della distanza fornisce le distanze (1 numero per ogni pixel), mentre la mappatura di Bump richiede normali (2 numeri per ogni pixel) ... Sei sicuro di sapere di cosa stai parlando?
Ivan Kuckir,

@IvanKuckir Avrei dovuto essere più chiaro: una normale di superficie può essere calcolata trattando la trasformazione della distanza come una mappa di altezza e calcolando dx / dy dai valori verticali e orizzontali vicini. Questi due numeri forniscono il normale richiesto per il bump mapping.
Vinnie Falco,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.