Ottenere gli eventi di posizione facciale

Nota

Gli eventi Viseme sono attualmente disponibili solo per le en-US voci neurali Stati Uniti (inglese).

Un viseme è la descrizione visiva di un fonema nella lingua parlata. Definisce la posizione del viso e della parola durante la pronuncia di una parola. Ogni viseme illustra le posizioni facciali chiave per un set specifico di fonemi. Il viseme può essere usato per controllare il movimento dei modelli avatar 2D e 3D, abbinando perfettamente i movimenti della testa al parlato sintetico.

I visemi semplificano l'uso e il controllo degli avatar. Usando visemes, è possibile:

  • Creare un assistente vocale virtuale animato per chioschi multimediale intelligenti, creando servizi integrati multi-modalità per i clienti.
  • È possibile creare trasmissioni di notizie immersive e migliorare le esperienze del pubblico con movimenti naturali del viso e della persona.
  • Genera più avatar di gioco interattivi e caratteri di gioco in grado di parlare con contenuto dinamico.
  • Creare video di apprendimento linguistico più efficaci che consentono agli studenti di lingue di comprendere il comportamento di ogni parola e fonema.
  • Le persone con problemi udibili possono anche prelevare suoni visivamente e contenuti vocali "leggibili" che mostrano visemi su un viso animato.

Vedere il video introduttivo del viseme.

TTS neurale di Azure può produrre visemi con la voce

Una voce neurale trasforma il testo di input o SSML (Speech Synthesis Markup Language) in sintesi vocale. L'output audio vocale può essere accompagnato da ID di viseme e dai relativi timestamp di offset. Ogni ID di viseme specifica una posizione specifica nella voce osservata, ad esempio la posizione del fonema, della fonema e della testa durante la produzione di un fonema specifico. Usando un motore di rendering 2D o 3D, è possibile usare questi eventi viseme per animare l'avatar.

Il flusso di lavoro complessivo di viseme è illustrato nel diagramma di flusso seguente.

Flusso di lavoro complessivo di viseme

Parametro Descrizione
Viseme ID Numero intero che specifica un viseme. In inglese (Stati Uniti), sono disponibili 22 visemi diversi per rappresentare le forme della fonetica per un set specifico di fonemi. Non esiste una corrispondenza uno-a-uno tra visemi e fonemi. Spesso più fonemi corrispondono a un singolo viseme, in quanto diversi fonemi hanno lo stesso aspetto sul viso quando vengono prodotti, ad s esempio e z . Vedere la tabella di mapping tra ID Viseme e fonemi.
Offset audio Ora di inizio di ogni viseme, in tick (100 nanosecondi).

Ottenere eventi viseme con Speech SDK

Per ottenere il viseme con la sintesi vocale, sottoscrivere VisemeReceived l'evento in Speech SDK. Il frammento di codice seguente illustra come sottoscrivere l'evento viseme.

using (var synthesizer = new SpeechSynthesizer(speechConfig, audioConfig))
{
    // Subscribes to viseme received event
    synthesizer.VisemeReceived += (s, e) =>
    {
        Console.WriteLine($"Viseme event received. Audio offset: " +
            $"{e.AudioOffset / 10000}ms, viseme id: {e.VisemeId}.");
    };

    var result = await synthesizer.SpeakSsmlAsync(ssml));
}

auto synthesizer = SpeechSynthesizer::FromConfig(speechConfig, audioConfig);

// Subscribes to viseme received event
synthesizer->VisemeReceived += [](const SpeechSynthesisVisemeEventArgs& e)
{
    cout << "viseme event received. "
        // The unit of e.AudioOffset is tick (1 tick = 100 nanoseconds), divide by 10,000 to convert to milliseconds.
        << "Audio offset: " << e.AudioOffset / 10000 << "ms, "
        << "viseme id: " << e.VisemeId << "." << endl;
};

auto result = synthesizer->SpeakSsmlAsync(ssml).get();
SpeechSynthesizer synthesizer = new SpeechSynthesizer(speechConfig, audioConfig);

// Subscribes to viseme received event
synthesizer.VisemeReceived.addEventListener((o, e) -> {
    // The unit of e.AudioOffset is tick (1 tick = 100 nanoseconds), divide by 10,000 to convert to milliseconds.
    System.out.print("Viseme event received. Audio offset: " + e.getAudioOffset() / 10000 + "ms, ");
    System.out.println("viseme id: " + e.getVisemeId() + ".");
});

SpeechSynthesisResult result = synthesizer.SpeakSsmlAsync(ssml).get();
speech_synthesizer = speechsdk.SpeechSynthesizer(speech_config=speech_config, audio_config=audio_config)

# Subscribes to viseme received event
speech_synthesizer.viseme_received.connect(lambda evt: print(
    "Viseme event received: audio offset: {}ms, viseme id: {}.".format(evt.audio_offset / 10000, evt.viseme_id)))

result = speech_synthesizer.speak_ssml_async(ssml).get()
var synthesizer = new SpeechSDK.SpeechSynthesizer(speechConfig, audioConfig);

// Subscribes to viseme received event
synthesizer.visemeReceived = function (s, e) {
    window.console.log("(Viseme), Audio offset: " + e.audioOffset / 10000 + "ms. Viseme ID: " + e.visemeId);
}

synthesizer.speakSsmlAsync(ssml);
SPXSpeechSynthesizer *synthesizer =
    [[SPXSpeechSynthesizer alloc] initWithSpeechConfiguration:speechConfig
                                           audioConfiguration:audioConfig];

// Subscribes to viseme received event
[synthesizer addVisemeReceivedEventHandler: ^ (SPXSpeechSynthesizer *synthesizer, SPXSpeechSynthesisVisemeEventArgs *eventArgs) {
    NSLog(@"Viseme event received. Audio offset: %fms, viseme id: %lu.", eventArgs.audioOffset/10000., eventArgs.visemeId);
}];

[synthesizer speakSsml:ssml];

Di seguito è riportato un esempio dell'output viseme.

(Viseme), Viseme ID: 1, Audio offset: 200ms.

(Viseme), Viseme ID: 5, Audio offset: 850ms.

……

(Viseme), Viseme ID: 13, Audio offset: 2350ms.

Dopo aver ottenuto l'output del viseme, è possibile usare questi eventi per l'animazione dei caratteri. È possibile creare caratteri personalizzati e animare automaticamente i caratteri.

Per i caratteri 2D, è possibile progettare un carattere adatto allo scenario e usare SVG (Scalable Vector Graphics) per ogni ID viseme per ottenere una posizione del viso basata sul tempo. Con i tag temporali forniti nell'evento viseme, questi SVG ben progettati verranno elaborati con modifiche uniformi e offriranno un'animazione affidabile agli utenti. Ad esempio, la figura seguente mostra un carattere rosso bianco progettato per l'apprendimento del linguaggio.

Esempio di rendering 2D

Per i caratteri 3D, è possibile pensare ai caratteri come a puppet di stringa. Il master puppet estrae le stringhe da uno stato a un altro e le leggi della fisica fanno il resto e guidano il puppet a spostarsi fluidamente. L'output viseme funge da master puppet per fornire una sequenza temporale dell'azione. Il motore di animazione definisce le leggi fisiche dell'azione. Interpolando i fotogrammi con algoritmi di interpolazione, il motore può generare ulteriori animazioni di alta qualità.

Eseguire il mapping di fonemi a visemi

I visemi variano in base alla lingua. Ogni lingua ha un set di visemi che corrispondono ai fonemi specifici. La tabella seguente illustra la corrispondenza tra fonemi dell'alfabeto fonetico internazionale (IPA) e ID viseme per l'inglese (Stati Uniti).

Ipa Esempio Viseme ID
i ea t 6
ɪ i f 6
a te 4
ɛ e very 4
Æ un oggetto ctive 1
ɑ o bstinate 2
ɔ c au se 3
ʊ b oo k 4
o ld 8
u U ber 7
ʌ u ncle 1
i ce 11
ou t 9
ɔɪ oi l 10
Ju Yu ma [6, 7]
ə a go 1
ɪɹ orecchini [6, 13]
ɛɹ air plane [4, 13]
ʊɹ c il proprio e [4, 13]
aɪ(0)ɹ Terra di Ire [11, 13]
aʊ(0)ɹ hour s [9, 13]
ɔɹ o ange [3, 13]
ɑɹ ar tist [2, 13]
ɝ ear th [5, 13]
ɚ all er gy [1, 13]
w w ith, s ue de 7
j y ard, f e w 6
p p ut 21
b b ig 21
t t alk 19
d d ig 19
k c ut 20
g g o 20
m m at, s m ash 21
n n o, s n ow 19
ŋ li n k 20
f f ork 18
v v alue 18
θ th in 17
Ð th en 17
s s it 15
z z ap 15
ʃ sh e 16
ʒ J# 16
h h elp 12
ch in 16
j oy 16
l l id, g l ad 14
ɹ r ed, b r ing 13

Passaggi successivi