分享方式:


使用 viseme 取得臉部位置

注意

若要探索viseme標識碼和混合圖形支援的地區設定,請參閱 所有支援的地區設定清單。 僅 en-US 地區設定支援可調整向量圖形 (SVG)。

Viseme 能夠以視覺方式呈現出口說語言的音素。 Viseme 會在有人說話時定義臉部和嘴巴的位置。 每個 Viseme 都能為一組特定音素描繪出關鍵臉部姿勢。

您可以使用 visemes 來控制 2D 和 3D 虛擬人偶模型的移動,讓臉部位置與綜合語音能以最佳效果對齊。 例如,您可以:

  • 為智慧型資訊亭建立動畫虛擬語音助理,為您的顧客建立多模式的整合服務。
  • 透過自然臉部和嘴部的移動,打造出沉浸性新聞廣播並提升觀眾體驗。
  • 產生更多互動式遊戲虛擬人偶和卡通人物,這些人物可以說出動態內容。
  • 製作更有效的語言教學影片,協助語言學習者們瞭解每個單字和音素的正確嘴部動作。
  • 聽障人士也可以透過視覺方式得悉聲音,在動畫的臉部上顯示發音嘴型,以「讀唇」方式理解語音內容。

如需 visemes 的詳細資訊,請檢視此簡介影片

使用語音產生 viseme 的整體工作流程

類神經文字轉換語音 (類神經 TTS) 會將輸入文字或 SSML (語音合成標記語言) 轉換成逼真的合成語音。 語音音訊輸出可以伴隨 viseme 識別碼、可變式向量圖形 (SVG) 或混合圖形。 搭配使用 2D 或3D 轉譯引擎,您可以利用這些 Viseme 事件來為您的虛擬人偶製作動畫。

下列流程圖說明 Viseme 的整體工作流程:

viseme 整體工作流程的圖表。

Viseme 識別碼

Viseme 識別碼是指定 viseme 的整數。 我們提供 22 種不同的 Visemes,分別描述特定一組音素的口部位置。 Viseme 與音素之間並沒有一對一的對應關係。 通常,數個音素會對應至單一 viseme,因為它們在產生時在說話者的臉上看起來相同,例如 sz。 如需特定詳細資訊,請參閱將將音素對應至 Viseme 識別碼的資料表。

語音音訊輸出會伴隨著 Viseme 識別碼及 Audio offsetAudio offset 表示每個 viseme 開始時間的位移時間戳記,以刻度為單位 (100 奈秒)。

將音素對應至 Viseme

Visemes 會依語言和地區設定而有所不同。 每種地區設定都有一組對應到特定音素的 Viseme。 SSML 音標文件會將 viseme 識別碼對應至相對應的國際音標 (IPA) 音素。 本節中的表格顯示 viseme 標識符與嘴部位置之間的對應關聯性,列出每個 viseme 標識碼的一般 IPA 音素。

Viseme 識別碼 IPA 口部位置
0 靜音 viseme ID 為 0 時的嘴部位置
1 æ、 、 əʌ viseme ID 為 1 時的嘴部位置
2 ɑ viseme ID 為 2 時的嘴部位置
3 ɔ viseme ID 為 3 時的嘴部位置
4 ɛ, ʊ viseme標識碼為 4 時的嘴部位置
5 ɝ viseme標識碼為5時的嘴部位置
6 j、 、 iɪ viseme ID 為 6 時的嘴部位置
7 w, u viseme標識碼為 7 時的嘴部位置
8 o viseme ID 為 8 時的嘴部位置
9 viseme ID 為 9 時的嘴部位置
10 ɔɪ viseme標識碼為 10 時的嘴部位置
11 viseme ID 為 11 時的嘴部位置
12 h viseme標識碼為 12 時的嘴部位置
13 ɹ viseme ID 為 13 時的嘴部位置
14 l viseme標識碼為 14 時的嘴部位置
15 s, z viseme標識碼為 15 時的嘴部位置
16 ʃ、 、 ʒ viseme標識碼為16時的嘴部位置
17 ð viseme標識碼為 17 時的嘴部位置
18 f, v viseme ID 為 18 時的嘴部位置
19 d、 、 tnθ viseme ID 為 19 時的嘴部位置
20 k、 、 gŋ viseme標識碼為 20 時的嘴部位置
21 p、 、 bm viseme ID 為 21 時的嘴部位置

2D SVG 動畫

針對 2D 角色,您可以設計符合您使用情境的角色,並針對每個 Viseme 識別碼使用可調整向量圖形 (SVG),藉此取得以時間為基礎的臉部位置。

透過viseme事件中提供的時態標記,這些設計良好的SVG會以流暢的修改來處理,並提供強固的動畫給使用者。 例如,下圖顯示專為語言學習設計的紅色小寫字元。

此螢幕快照顯示四個紅唇嘴的 2D 轉譯範例,分別代表對應至音素的不同 viseme 標識符。

3D 混合圖形動畫

您可以使用混合圖形來驅動您設計的 3D 字元臉部移動。

混合圖形 JSON 字串會以 2 維矩陣表示。 每一列代表一個畫面格。 每個畫面格 (在 60 FPS 中) 包含 55 個臉部位置的陣列。

以語音 SDK 取得 Viseme 事件

若要為您的合成語音取得 viseme,請訂閱語音 SDK 中的 VisemeReceived 事件。

注意

若要要求 SVG 或混合圖形輸出,您應該使用 SSML 中的 mstts:viseme 元素。 如需詳細資訊,請參閱如何在 SSML 中使用 viseme 元素

下列程式碼片段展示了如何訂閱 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}.");

        // `Animation` is an xml string for SVG or a json string for blend shapes
        var animation = e.Animation;
    };

    // If VisemeID is the only thing you want, you can also use `SpeakTextAsync()`
    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;

    // `Animation` is an xml string for SVG or a json string for blend shapes
    auto animation = e.Animation;
};

// If VisemeID is the only thing you want, you can also use `SpeakTextAsync()`
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() + ".");

    // `Animation` is an xml string for SVG or a json string for blend shapes
    String animation = e.getAnimation();
});

// If VisemeID is the only thing you want, you can also use `SpeakTextAsync()`
SpeechSynthesisResult result = synthesizer.SpeakSsmlAsync(ssml).get();
speech_synthesizer = speechsdk.SpeechSynthesizer(speech_config=speech_config, audio_config=audio_config)

def viseme_cb(evt):
    print("Viseme event received: audio offset: {}ms, viseme id: {}.".format(
        evt.audio_offset / 10000, evt.viseme_id))

    # `Animation` is an xml string for SVG or a json string for blend shapes
    animation = evt.animation

# Subscribes to viseme received event
speech_synthesizer.viseme_received.connect(viseme_cb)

# If VisemeID is the only thing you want, you can also use `speak_text_async()`
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);

    // `Animation` is an xml string for SVG or a json string for blend shapes
    var animation = e.animation;
}

// If VisemeID is the only thing you want, you can also use `speakTextAsync()`
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);

    // `Animation` is an xml string for SVG or a json string for blend shapes
    NSString *animation = eventArgs.Animation;
}];

// If VisemeID is the only thing you want, you can also use `SpeakText`
[synthesizer speakSsml:ssml];

以下是 Viseme 輸出的範例。

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

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

……

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

取得 Viseme 輸出之後,您可以使用這些事件來為角色繪製動畫。 您可以建立自己的角色,並自動為這些角色建立動畫。

下一步