What Is TTS and How Is It Implemented in Apps - Huawei Developers

{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Does the following routine sound familiar? In the morning, your voice assistant gives you today's weather forecast. And then, on your way to work, a navigation app gives you real-time traffic updates, and in the evening, a cooking app helps you cook up dinner with audible steps.
In such a routine, machine-generated voice plays an integral part, creating an engaging, personalized experience. The technology that powers this is called text-to-speech, or TTS for short. It is a kind of assistive technology reading aloud digital text, which therefore is also known as read-aloud technology.
With a single tap or click on a button, TTS can convert characters into audio, which is invaluable to people like me, who are readers on the go. I'm a huge fan of both reading and running, so with the help of the TTS function, my phone transforms my e-books into audio books, and I can listen to them while I'm on a run.
There are two things, however, that I'm not satisfied with the TTS function. First, when the text contains both Chinese and English, the function will fail to distinguish one from another and consequently say something that is incomprehensible. Second, the audio speed of the function cannot be adjusted, meaning I cannot listen to things slowly and carefully when it's necessary.
I made up my mind to develop a TTS function that overcomes such disadvantages. After some research, I was disappointed to find out that creating a speech synthesizer from scratch meant that I had to study linguistics (which enables TTS to recognize how text is pronounced by a human), audio signal processing (which paves the way for TTS to be able to generate new speech), and deep learning (which enables TTS to handle a large amount of data for generating high-quality speech).
That sounds intimidating. Therefore, instead of creating a TTS function from nothing, I decided to turn to some solutions that are already available on the market for implementing the function. One such a solution I found is the TTS from HMS Core ML Kit. Let's now dive deeper into it.
Capability Introduction​The TTS capability adopts the deep neural network (DNN) synthesis mode and can be quickly integrated through the on-device SDK to generate audio data in real time. Thanks to the DNN, the generated speech sounds natural and expressive.
The capability comes with many timbres to choose from and supports as many as 12 languages (Arabic, English, French, German, Italian, Malay, Mandarin Chinese, Polish, Russian, Spanish, Thai, and Turkish). When the text contains both Chinese and English, the capability can differ one from another properly.
On top of these, the speech speed, pitch, and volume can be adjusted, making the capability customizable and thereby better meet requirements in different scenarios.
Developing the TTS Function​Making Preparations​1. Prepare the development environment, which has requirements on both software and hardware:
Software requirements:
JDK version: 1.8.211 or later
Android Studio version: 3.X or later
minSdkVersion: 19 or later (mandatory)
targetSdkVersion: 31 (recommended)
compileSdkVersion: 31 (recommended)
Gradle version: 4.6 or later (recommended)
Hardware requirements: A mobile phone running Android 4.4 or later or EMUI 5.0 or later.
2. Create a developer account.
3. Configure the app information in AppGallery Connect, including project and app creation, as well as configuration of the data processing location.
4. Enable ML Kit in AppGallery Connect.
5. Integrate the SDK of the kit. This step involves several tasks. The one I want to mention in special is adding build dependencies. This is because capabilities of the kit have different build dependencies, and those for the TTS capability are as follows:
Code:
dependencies{
implementation 'com.huawei.hms:ml-computer-voice-tts:3.11.0.301'
}
6. Configure obfuscation scripts.
7. Apply for the following permission in the AndroidManifest.xml file: INTERNET. (This is because TTS is an on-cloud capability, which requires a network connection. I noticed that the kit also provides the on-device version of the capability. After downloading its models, the on-device capability can be used without network connectivity.)
Implementing the TTS Capability Using Kotlin​1. Set the authentication information for the app.
2. Create a TTS engine by using the MLTtsConfig class for engine parameter configuration.
Code:
// Use custom parameter settings to create a TTS engine.
val mlTtsConfig = MLTtsConfig() // Set the language of the text to be converted to Chinese.
.setLanguage(TTS_ZH_HANS) // Set the Chinese timbre.
.setPerson(MLTtsConstants.TTS_SPEAKER_FEMALE_ZH) // Set the speech speed. The range is (0, 5.0]. 1.0 indicates a normal speed.
.setSpeed(1.0f) // Set the volume. The range is (0, 2). 1.0 indicates a normal volume.
.setVolume(1.0f)
val mlTtsEngine = MLTtsEngine(mlTtsConfig)
// Set the volume of the built-in player, in dBs. The value range is [0, 100].
mlTtsEngine.setPlayerVolume(20)
// Update the configuration when the engine is running.
mlTtsEngine.updateConfig(mlTtsConfig)
3. Create a callback to process the text-to-speech conversion result.
Code:
val callback: MLTtsCallback = object : MLTtsCallback {
override fun onError(taskId: String, err: MLTtsError) {
// Processing logic for TTS failure.
}
override fun onWarn(taskId: String, warn: MLTtsWarn) {
// Alarm handling without affecting the service logic.
}
// Return the mapping between the currently played segment and text. start: start position of the audio segment in the input text; end (excluded): end position of the audio segment in the input text.
override fun onRangeStart(taskId: String, start: Int, end: Int) {
// Process the mapping between the currently played segment and text.
}
// taskId: ID of an audio synthesis task.
// audioFragment: audio data.
// offset: offset of the audio segment to be transmitted in the queue. One audio synthesis task corresponds to an audio synthesis queue.
// range: text area where the audio segment to be transmitted is located; range.first (included): start position; range.second (excluded): end position.
override fun onAudioAvailable(taskId: String, audioFragment: MLTtsAudioFragment, offset: Int, range: Pair<Int, Int>,
bundle: Bundle) {
// Audio stream callback API, which is used to return the synthesized audio data to the app.
}
override fun onEvent(taskId: String, eventId: Int, bundle: Bundle) {
// Callback method of a TTS event. eventId indicates the event ID.
when (eventId) {
MLTtsConstants.EVENT_PLAY_START -> {
}
MLTtsConstants.EVENT_PLAY_STOP -> { // Called when playback stops.
var isInterrupted: Boolean = bundle.getBoolean(MLTtsConstants.EVENT_PLAY_STOP_INTERRUPTED)
}
MLTtsConstants.EVENT_PLAY_RESUME -> {
}
MLTtsConstants.EVENT_PLAY_PAUSE -> {
}
MLTtsConstants.EVENT_SYNTHESIS_START -> {
}
MLTtsConstants.EVENT_SYNTHESIS_END -> {
}
MLTtsConstants.EVENT_SYNTHESIS_COMPLETE -> { // Audio synthesis is complete. All synthesized audio streams are passed to the app.
var isInterrupted
: Boolean = bundle.getBoolean(MLTtsConstants.EVENT_SYNTHESIS_INTERRUPTED)
}
else -> {
}
}
}
}
4. Pass the callback just created to the TTS engine created in step 2 to convert text to speech.
Code:
mlTtsEngine.setTtsCallback(callback)
/**
* The first parameter sourceText indicates the text information to be synthesized. The value can contain a maximum of 500 characters.
* The second parameter indicates the synthesis mode. The format is configA | configB | configC.
* configA:
* MLTtsEngine.QUEUE_APPEND: After a TTS task is generated, this task is processed as follows: If playback is going on, the task is added to the queue for execution in sequence; if playback pauses, the task is resumed, and the task is added to the queue for execution in sequence; if there is no playback, the TTS task is executed immediately.
* MLTtsEngine.QUEUE_FLUSH: The ongoing TTS task and playback are stopped immediately, and all TTS tasks in the queue are cleared. The ongoing TTS task is executed immediately, and the generated speech is played.
* configB:
* MLTtsEngine.OPEN_STREAM: The synthesized audio data is output through onAudioAvailable.
* configC:
* MLTtsEngine.EXTERNAL_PLAYBACK means the external playback mode. The player provided by the SDK is not used. You need to process the audio output by the onAudioAvailable callback API. In this case, the playback-related APIs in the callback APIs become invalid, and only the callback APIs related to audio synthesis can be listened to.
*/
// Use the built-in player of the SDK to play speech in queuing mode.
val sourceText: String? = null
val id = mlTtsEngine.speak(sourceText, MLTtsEngine.QUEUE_APPEND)
// In queuing mode, the synthesized audio stream is output through onAudioAvailable. In this case, the built-in player of the SDK is used to play the speech.
// String id = mlTtsEngine.speak(sourceText, MLTtsEngine.QUEUE_APPEND | MLTtsEngine.OPEN_STREAM);
// In queuing mode, the synthesized audio stream is output through onAudioAvailable, and the audio stream is not played automatically, but controlled by you.
// String id = mlTtsEngine.speak(sourceText, MLTtsEngine.QUEUE_APPEND | MLTtsEngine.OPEN_STREAM | MLTtsEngine.EXTERNAL_PLAYBACK);
5. Pause or resume speech playback.
Code:
// Pause speech playback.
mlTtsEngine.pause()
// Resume speech playback.
mlTtsEngine.resume()
6. Stop the ongoing TTS task and clear all TTS tasks to be processed.
Code:
mlTtsEngine.stop()
7. Release resources occupied by the TTS engine, when the TTS task ends.
Code:
if (mlTtsEngine != null) {
mlTtsEngine.shutdown()
}
These steps explain how the TTS capability is used to develop a TTS function using the Kotlin language. The capability also supports Java, but the functions developed using either of the languages are the same — Just choose the language you are more familiar with or want to try out.
Besides audio books, the TTS function is also helpful in a bunch of other scenarios. For example, when someone has had enough of staring at the screen for too long, they can turn to TTS for help. Or, when a parent is too tired to finish off a bedtime story, they can use the TTS function to read the rest of the story for their children. Voice content creators can turn to TTS for dubbing videos and providing voiceovers.
The list goes on. I look forward to hearing how you use the TTS function for other cases in the comments section below.
Takeaway​Machine-generated voice brings an even greater level of convenience to ordinary, day-to-day tasks, allowing us to absorb content while doing other things at the same time.
The technology that powers voice generation is known as TTS, which is relatively simple to use. A worthy solution to implement this technology into mobile apps is a capability of the same name from HMS Core ML Kit. It supports multiple languages and works well with bilingual text of Chinese and English. The capability provides a range of timbres that all sound surprisingly natural, thanks to its adoption of the DNN technology. The capability is customizable, in terms of its configurable parameters including the speech speed, volume, and pitch. With this capability, building a mobile text reader is a breeze.

Related

Machine Learning made Easy: Text To Speech using Kotlin and Huawei ML Kit

Introduction
Have you ever met a situation like this before? A novel is too long to read, it will spare you much time if the app can automatically read the novel for you. So a tool to transfer text into speech is urgently required. HUAWEI ML kit (machine learning) has the function of TTS, which can help your app quickly achieve text to speech function.
Text to Speech can convert text into human voice. This can be achieved by default methods also but they don’t provide natural or realistic sounds.
This service uses Deep Neural Networks in order to process the text and create a natural sound, rich timbres are also supported in order to enhance the result. This service is available globally.
As this service uses cloud service hence there is a limit of 500 characters. These characters are encoded using UTF-8
Below are the format supported currently.
· English – Male voice
· English – Female voice
· Mandarin Chinese – Male voice
· Mandarin Chinese – Female voice
· English + Chinese – Male voice
· English + Chinese – Female voice
Article Takeaway
Below is the final result which we will be going to achieve after implementing this Kit.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Steps to Integrate
Step 1: Create a new project in Android Studio
Step 2: Add the below dependencies into app.gradle file
implementation 'com.huawei.hms:ml-computer-voice-tts:1.0.4.300'
Step 3: Add agc plugin in the top of app.gradle file
apply plugin: 'com.huawei.agconnect'
Step 4: Create a callback in your activity
var callback: MLTtsCallback = object : MLTtsCallback {
override fun onError(taskId: String, err: MLTtsError) {
}
override fun onWarn(taskId: String, warn: MLTtsWarn) {
}
override fun onRangeStart(taskId: String, start: Int, end: Int) {
}
override fun onEvent(taskId: String, eventName: Int, bundle: Bundle?) {
if (eventName == MLTtsConstants.EVENT_PLAY_STOP) {
val isStop = bundle?.getBoolean(MLTtsConstants.EVENT_PLAY_STOP_INTERRUPTED)
}
}
}
Let us discuss this in detail.
4 callback methods are provided. Below are the details.
· OnError() - In case of any error the control will flow here, you can use this to notify user what error occurred and send the analytics data by HMS Analytics to console for further verification.
· OnWarn() - In case of warning like insufficient bandwidth the callback comes here.
· OnRangeStart() - It returns the mapping between the currently played segment and text
· OnEvent() - Whenever a new event occurs this method is called, example – In case of audio paused we will get EVENT_PLAY_STOP_INTERRUPTED parameter in bundle.
o If MLTtsConstants.EVENT_PLAY_STOP is false then whole audio is played without issue.
o If MLTtsConstants.EVENT_PLAY_STOP is true then there is some interruption.
Step 5: Object Initialization
mlConfigs = MLTtsConfig()
.setLanguage(MLTtsConstants.TTS_EN_US)
.setPerson(MLTtsConstants.TTS_SPEAKER_FEMALE_EN)
.setSpeed(1.0f)
.setVolume(1.0f)
mlTtsEngine = MLTtsEngine(mlConfigs)
mlTtsEngine.setTtsCallback(callback)
Let us discuss this in detail.
There are 2 ways by which we can create TTS Engine.
We will be using custom TTSEnigne by MLTtsConfig object.
· Language set to English by MLTtsConstants.TTS_EN_US
o You can set language by MLTtsConstants.TTS_ZH_HANS for Chinese.
· Set person voice by MLTtsConstants.TTS_SPEAKER_FEMALE_EN
o English Male – MLTtsConstants .TTS_SPEAKER_MALE_EN
o Chinese Female – MLTtsConstants .TTS_SPEAKER_FEMALE_ZH
o Chinese Male – MLTtsConstants .TTS_SPEAKER_MALE_ZH
· Set the speech speed. Range: 0.2–1.8. 1.0 indicates 1x speed.
· Set the volume. Range: 0.2–1.8. 1.0 indicates 1x volume.
· Create the object of MLTtsEngine and provide above MLTtsConfig object.
· Set the above created callback object into MLTtsEngine
Step 6: Add the below method in your activity and call it on click of a button
private fun startTtsService() {
val id = mlTtsEngine.speak(sourceText,MLTtsEngine.QUEUE_APPEND)
}
Let us discuss this in detail.
sourceText is the text entered by user.
· MLTtsEngine.QUEUE_APPENDED is used when we want queue system. Once first operation of TTS will complete then next will start.
· In case you want a functionality where you want to only process current operation then use MLTtsEngine. QUEUE_FLUSH
· In onPause() you can stop the MLTtsEngine by
override fun onPause() {
super.onPause()
mlTtsEngine.stop()
}
In onDestroy() you can release the resources occupied by MLTtsEngine.
override fun onDestroy() {
super.onDestroy()
mlTtsEngine.shutdown()
}
FAQ
Q: Is TTS only available on huawei devices?
A: Yes.
Q: Do you need internet access in order to use TTS service?
A: Yes, this is a cloud based service hence internet is required.
Conclusion
We have merely scratched the surface. The text-to-speech function provided by HUAWEI ML Kit is also applicable to the following scenarios: News reading, audio novels, stock information broadcast, voice navigation, and video dubbing.
Above are some areas which needs TTS as a main service. I hope you liked this article. I would love to hear your ideas on how you can use this kit in your Applications.
Below is the Github link where you can download the source code.
Github Link: https://github.com/HMS-Core/hms-ml-demo/tree/master/TTSSampleKotlin

How I Created a Smart Video Clip Extractor

{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Travel and life vlogs are popular among app users: Those videos are telling, covering all the most attractive parts in a journey or a day. To create such a video first requires great editing efforts to cut out the trivial and meaningless segments in the original video, which used to be a thing of video editing pros.
This is no longer the case. Now we have an array of intelligent mobile apps that can help us automatically extract highlights from a video, so we can focus more on spicing up the video by adding special effects, for example. I opted to use the highlight capability from HMS Core Video Editor Kit to create my own vlog editor.
How It Works​This capability assesses how appealing video frames are and then extracts the most suitable ones. To this end, it is said that the capability takes into consideration the video properties most concerned by users, a conclusion that is drawn from survey and experience assessment from users. On the basis of this, the highlight capability develops a comprehensive frame assessment scheme that covers various aspects. For example:
Aesthetics evaluation. This aspect is a data set built upon composition, lighting, color, and more, which is the essential part of the capability.
Tags and facial expressions. They represent the frames that are detected and likely to be extracted by the highlight capability, such as frames that contain people, animals, and laughter.
Frame quality and camera movement mode. The capability discards low-quality frames that are blurry, out-of-focus, overexposed, or shaky, to ensure such frames will not impact the quality of the finished video. Amazingly, despite all of these, the highlight capability is able to complete the extraction process in just 2 seconds.
See for yourself how the finished video by the highlight capability compares with the original video.
Backing Technology​The highlight capability stands out from the crowd by adopting models and a frame assessment scheme that are iteratively optimized. Technically and specifically speaking:
The capability introduces AMediaCodec for hardware decoding and Open Graphics Library (OpenGL) for rendering frames and automatically adjusting the frame dimensions according to the screen dimensions. The capability algorithm uses multiple neural network models. In this way, the capability checks the device model where it runs and then automatically chooses to run on NPU, CPU, or GPU. Consequently, the capability delivers a higher running performance.
To provide the extraction result more quickly, the highlight capability uses the two-stage algorithm of sparse sampling to dense sampling, checks how content distributed among numerous videos, and adopts the frame buffer. All these contribute to a higher efficiency of determining the most attractive video frames. To ensure high performance of the algorithm, the capability adopts the thread pool scheduling and producer-consumer model, to ensure that the video decoder and models can run at the same time.
During the sparse sampling stage, the capability decodes and processes some (up to 15) key frames in a video. The interval between the key frames is no less than 2 seconds. During the dense sampling stage, the algorithm picks out the best key frame and then extracts frames before and after to further analyze the highlighted part of the video.
The extraction result is closely related to the key frame position. The processing result of the highlight capability will not be ideal when the sampling points are not dense enough because, for example, the video does not have enough key frames or the duration is too long (greater than 1 minute). For the capability to deliver optimal performance, it recommends that the duration of the input video be less than 60 seconds.
Let's now move on to how this capability can be integrated.
Integration Process​Preparations​Make necessary preparations before moving on to the next part. Required steps include:
Configure the app information in AppGallery Connect.
Integrate the SDK of HMS Core.
Configure obfuscation scripts.
Declare necessary permissions.
Setting up the Video Editing Project​1. Configure the app authentication information by using either an access token or API key.
Method 1: Call setAccessToken to set an access token, which is required only once during app startup.
Code:
MediaApplication.getInstance().setAccessToken("your access token");
Method 2: Call setApiKey to set an API key, which is required only once during app startup.
Code:
MediaApplication.getInstance().setApiKey("your ApiKey");
2. Set a License ID.
This ID is used to manage the usage quotas of Video Editor Kit and must be unique.
Code:
MediaApplication.getInstance().setLicenseId("License ID");
Initialize the runtime environment of HuaweiVideoEditor.
When creating a video editing project, we first need to create an instance of HuaweiVideoEditor and initialize its runtime environment. When you exit the project, the instance shall be released.
Create an instance of HuaweiVideoEditor.
Code:
HuaweiVideoEditor editor = HuaweiVideoEditor.create(getApplicationContext());
Determine the layout of the preview area.
Such an area renders video images, and this is implemented by SurfaceView within the fundamental capability SDK. Before the area is created, we need to specify its layout.
Code:
<LinearLayout
android:id="@+id/video_content_layout"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@color/video_edit_main_bg_color"
android:gravity="center"
android:orientation="vertical" />
// Specify a preview area.
LinearLayout mSdkPreviewContainer = view.findViewById(R.id.video_content_layout);
// Design the layout of the area.
editor.setDisplay(mSdkPreviewContainer);
Initialize the runtime environment. If the license verification fails, LicenseException will be thrown.
After the HuaweiVideoEditor instance is created, it will not use any system resources, and we need to manually set the initialization time for the runtime environment. Then, the fundamental capability SDK will internally create necessary threads and timers.
Code:
try {
editor.initEnvironment();
} catch (LicenseException error) {
SmartLog.e(TAG, "initEnvironment failed: " + error.getErrorMsg());
finish();
return;
}
Integrating the Highlight Capability​
Code:
// Create an object that will be processed by the highlight capability.
HVEVideoSelection hveVideoSelection = new HVEVideoSelection();
// Initialize the engine of the highlight capability.
hveVideoSelection.initVideoSelectionEngine(new HVEAIInitialCallback() {
@Override
public void onProgress(int progress) {
// Callback when the initialization progress is received.
}
@Override
public void onSuccess() {
// Callback when the initialization is successful.
}
@Override
public void onError(int errorCode, String errorMessage) {
// Callback when the initialization failed.
}
});
// After the initialization is successful, extract the highlighted video. filePath indicates the video file path, and duration indicates the desired duration for the highlighted video.
hveVideoSelection.getHighLight(filePath, duration, new HVEVideoSelectionCallback() {
@Override
public void onResult(long start) {
// The highlighted video is successfully extracted.
}
});
// Release the highlight engine.
hveVideoSelection.releaseVideoSelectionEngine();
Conclusion​The vlog has been playing a vital part in this we-media era since its appearance. In the past, there were just a handful of people who could create a vlog, because the process of picking out the most interesting part from the original video could be so demanding.
Thanks to smart mobile app technology, even video editing amateurs can now create a vlog because much of the process can be completed automatically by an app with the function of highlighted video extraction.
The highlight capability from the Video Editor Kit is one such function. This capability introduces a set of features to deliver incredible results, such as AMediaCodec, OpenGL, neural networks, a two-stage algorithm (sparse sampling to dense sampling), and more. This capability can help create either a highlighted video extractor or build a highlighted video extraction feature in an app.

Streamlining 3D Animation Creation via Rigging

{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
I dare say there are two types of people in this world: people who love Toy Story and people who have not watched it.
Well, this is just the opinion of a huge fan of the animation film. When I was a child, I always dreamed of having toys that could move and play with me, like my own Buzz Lightyear. Thanks to a fancy technique called rigging, I can now bring my toys to life, albeit I'm probably too old for them now.
What Is Rigging in 3D Animation and Why Do We Need It?​Put simply, rigging is a process whereby a skeleton is created for a 3D model to make it move. In other words, rigging creates a set of connected virtual bones that are used to control a 3D model.
It paves the way for animation because it enables a model to be deformed, making it moveable, which is the very reason that rigging is necessary for 3D animation.
What Is Auto Rigging​3D animation has been adopted by mobile apps in a number of fields (gaming, e-commerce, video, and more), to achieve more realistic animations than 2D.
However, this graphic technique has daunted many developers (like me) because rigging, one of its major prerequisites, is difficult and time-consuming for people who are unfamiliar with modeling. Specifically speaking, most high-performing rigging solutions have many requirements. An example of this is that the input model should be in a standard position, seven or eight key skeletal points should be added, as well as inverse kinematics which must be added to the bones, and more.
Luckily, there are solutions that can automatically complete rigging, such as the auto rigging solution from HMS Core 3D Modeling Kit.
This capability delivers a wholly automated rigging process, requiring just a biped humanoid model that is generated using images taken from a mobile phone camera. After the model is input, auto rigging uses AI algorithms for limb rigging and generates the model skeleton and skin weights (which determine the degree to which a bone can influence a part of the mesh). Then, the capability changes the orientation and position of the skeleton so that the model can perform a range of preset actions, like walking, running, and jumping. Besides, the rigged model can also be moved according to an action generated by using motion capture technology, or be imported into major 3D engines for animation.
Lower requirements do not compromise rigging accuracy. Auto rigging is built upon hundreds of thousands of 3D model rigging data records. Thanks to some fine-tuned data records, the capability delivers ideal algorithm accuracy and generalization.
I know that words alone are no proof, so check out the animated model I've created using the capability.
Movement is smooth, making the cute panda move almost like a real one. Now I'd like to show you how I created this model and how I integrated auto rigging into my demo app.
Integration Procedure​Preparations​Before moving on to the real integration work, make necessary preparations, which include:
Configure app information in AppGallery Connect.
Integrate the HMS Core SDK with the app project, which includes Maven repository address configuration.
Configure obfuscation scripts.
Declare necessary permissions.
Capability Integration​1. Set an access token or API key — which can be found in agconnect-services.json — during app initialization for app authentication.
Using the access token: Call setAccessToken to set an access token. This task is required only once during app initialization.
Code:
ReconstructApplication.getInstance().setAccessToken("your AccessToken");
Using the API key: Call setApiKey to set an API key. This key does not need to be set again.
Code:
ReconstructApplication.getInstance().setApiKey("your api_key");
The access token is recommended. And if you prefer the API key, it is assigned to the app when it is created in AppGallery Connect.
2. Create a 3D object reconstruction engine and initialize it. Then, create an auto rigging configurator.
Code:
// Create a 3D object reconstruction engine.
Modeling3dReconstructEngine modeling3dReconstructEngine = Modeling3dReconstructEngine.getInstance(context);
// Create an auto rigging configurator.
Modeling3dReconstructSetting setting = new Modeling3dReconstructSetting.Factory()
// Set the working mode of the engine to PICTURE.
.setReconstructMode(Modeling3dReconstructConstants.ReconstructMode.PICTURE)
// Set the task type to auto rigging.
.setTaskType(Modeling3dReconstructConstants.TaskType.AUTO_RIGGING)
.create();
3. Create a listener for the result of uploading images of an object.
Code:
private Modeling3dReconstructUploadListener uploadListener = new Modeling3dReconstructUploadListener() {
@Override
public void onUploadProgress(String taskId, double progress, Object ext) {
// Callback when the upload progress is received.
}
@Override
public void onResult(String taskId, Modeling3dReconstructUploadResult result, Object ext) {
// Callback when the upload is successful.
}
@Override
public void onError(String taskId, int errorCode, String message) {
// Callback when the upload failed.
}
};
4. Use a 3D object reconstruction configurator to initialize the task, set an upload listener for the engine created in step 1, and upload images.
Code:
// Use the configurator to initialize the task, which should be done in a sub-thread.
Modeling3dReconstructInitResult modeling3dReconstructInitResult = modeling3dReconstructEngine.initTask(setting);
String taskId = modeling3dReconstructInitResult.getTaskId();
// Set an upload listener.
modeling3dReconstructEngine.setReconstructUploadListener(uploadListener);
// Call the uploadFile API of the 3D object reconstruction engine to upload images.
modeling3dReconstructEngine.uploadFile(taskId, filePath);
5. Query the status of the auto rigging task.
Code:
// Initialize the task processing class.
Modeling3dReconstructTaskUtils modeling3dReconstructTaskUtils = Modeling3dReconstructTaskUtils.getInstance(context);
// Call queryTask in a sub-thread to query the task status.
Modeling3dReconstructQueryResult queryResult = modeling3dReconstructTaskUtils.queryTask(taskId);
// Obtain the task status.
int status = queryResult.getStatus();
6. Create a listener for the result of model file download.
Code:
private Modeling3dReconstructDownloadListener modeling3dReconstructDownloadListener = new Modeling3dReconstructDownloadListener() {
@Override
public void onDownloadProgress(String taskId, double progress, Object ext) {
// Callback when download progress is received.
}
@Override
public void onResult(String taskId, Modeling3dReconstructDownloadResult result, Object ext) {
// Callback when download is successful.
}
@Override
public void onError(String taskId, int errorCode, String message) {
// Callback when download failed.
}
};
7. Pass the download listener to the 3D object reconstruction engine, to download the rigged model.
Code:
// Set download configurations.
Modeling3dReconstructDownloadConfig downloadConfig = new Modeling3dReconstructDownloadConfig.Factory()
// Set the model file format to OBJ or glTF.
.setModelFormat(Modeling3dReconstructConstants.ModelFormat.OBJ)
// Set the texture map mode to normal mode or PBR mode.
.setTextureMode(Modeling3dReconstructConstants.TextureMode.PBR)
.create();
// Set the download listener.
modeling3dReconstructEngine.setReconstructDownloadListener(modeling3dReconstructDownloadListener);
// Call downloadModelWithConfig, passing the task ID, path to which the downloaded file will be saved, and download configurations, to download the rigged model.
modeling3dReconstructEngine.downloadModelWithConfig(taskId, fileSavePath, downloadConfig);
Where to Use​Auto rigging is used in many scenarios, for example:
Gaming. The most direct way of using auto rigging is to create moveable characters in a 3D game. Or, I think we can combine it with AR to create animated models that can appear in the camera display of a mobile device, which will interact with users.
Online education. We can use auto rigging to animate 3D models of popular toys, and liven them up with dance moves, voice-overs, and nursery rhymes to create educational videos. These models can be used in educational videos to appeal to kids more.
E-commerce. Anime figurines look rather plain compared to how they behave in animes. To spice up the figurines, we can use auto rigging to animate 3D models that will look more engaging and dynamic.
Conclusion​3D animation is widely used in mobile apps, because it presents objects in a more fun and interactive way.
A key technique for creating great 3D animations is rigging. Conventional rigging requires modeling know-how and expertise, which puts off many amateur modelers.
Auto rigging is the perfect solution to this challenge because its full-automated rigging process can produce highly accurate rigged models that can be easily animated using major engines available on the market. Auto rigging not only lowers the costs and requirements of 3D model generation and animation, but also helps 3D models look more appealing.

Create an HD Video Player with HDR Tech

{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
​What Is HDR and Why Does It Matter​Streaming technology has improved significantly, giving rise to higher and higher video resolutions from those at or below 480p (which are known as standard definition or SD for short) to those at or above 720p (high definition, or HD for short).
The video resolution is vital for all apps. A research that I recently came across backs this up: 62% of people are more likely to negatively perceive a brand that provides a poor-quality video experience, while 57% of people are less likely to share a poor-quality video. With this in mind, it's no wonder that there are so many emerging solutions to enhance video resolution.
One solution is HDR — high dynamic range. It is a post-processing method used in imaging and photography, which mimics what a human eye can see by giving more details to dark areas and improving the contrast. When used in a video player, HDR can deliver richer videos with a higher resolution.
Many HDR solutions, however, are let down by annoying restrictions. These can include a lack of unified technical specifications, high level of difficulty for implementing them, and a requirement for videos in ultra-high definition. I tried to look for a solution without such restrictions and luckily, I found one. That's the HDR Vivid SDK from HMS Core Video Kit. This solution is packed with image-processing features like the opto-electronic transfer function (OETF), tone mapping, and HDR2SDR. With these features, the SDK can equip a video player with richer colors, higher level of detail, and more.
I used the SDK together with the HDR Ability SDK (which can also be used independently) to try the latter's brightness adjustment feature, and found that they could deliver an even better HDR video playback experience. And on that note, I'd like to share how I used these two SDKs to create a video player.
Before Development​1. Configure the app information as needed in AppGallery Connect.
2. Integrate the HMS Core SDK.
For Android Studio, the SDK can be integrated via the Maven repository. Before the development procedure, the SDK needs to be integrated into the Android Studio project.
3. Configure the obfuscation scripts.
4. Add permissions, including those for accessing the Internet, for obtaining the network status, for accessing the Wi-Fi network, for writing data into the external storage, for reading data from the external storage, for reading device information, for checking whether a device is rooted, and obtaining the wake lock. (The last three permissions are optional.)
App Development​Preparations​1. Check whether the device is capable of decoding an HDR Vivid video. If the device has such a capability, the following function will return true.
Code:
public boolean isSupportDecode() {
// Check whether the device supports MediaCodec.
MediaCodecList mcList = new MediaCodecList(MediaCodecList.ALL_CODECS);
MediaCodecInfo[] mcInfos = mcList.getCodecInfos();
for (MediaCodecInfo mci : mcInfos) {
// Filter out the encoder.
if (mci.isEncoder()) {
continue;
}
String[] types = mci.getSupportedTypes();
String typesArr = Arrays.toString(types);
// Filter out the non-HEVC decoder.
if (!typesArr.contains("hevc")) {
continue;
}
for (String type : types) {
// Check whether 10-bit HEVC decoding is supported.
MediaCodecInfo.CodecCapabilities codecCapabilities = mci.getCapabilitiesForType(type);
for (MediaCodecInfo.CodecProfileLevel codecProfileLevel : codecCapabilities.profileLevels) {
if (codecProfileLevel.profile == HEVCProfileMain10
|| codecProfileLevel.profile == HEVCProfileMain10HDR10
|| codecProfileLevel.profile == HEVCProfileMain10HDR10Plus) {
// true means supported.
return true;
}
}
}
}
// false means unsupported.
return false;
}
2. Parse a video to obtain information about its resolution, OETF, color space, and color format. Then save the information in a custom variable. In the example below, the variable is named as VideoInfo.
Code:
public class VideoInfo {
private int width;
private int height;
private int tf;
private int colorSpace;
private int colorFormat;
private long durationUs;
}
3. Create a SurfaceView object that will be used by the SDK to process the rendered images.
Code:
// surface_view is defined in a layout file.
SurfaceView surfaceView = (SurfaceView) view.findViewById(R.id.surface_view);
4. Create a thread to parse video streams from a video.
Rendering and Transcoding a Video​1. Create and then initialize an instance of HdrVividRender.
Code:
HdrVividRender hdrVividRender = new HdrVividRender();
hdrVividRender.init();
2. Configure the OETF and resolution for the video source.
Code:
// Configure the OETF.
hdrVividRender.setTransFunc(2);
// Configure the resolution.
hdrVividRender.setInputVideoSize(3840, 2160);
When the SDK is used on an Android device, only the rendering mode for input is supported.
3. Configure the brightness for the output. This step is optional.
Code:
hdrVividRender.setBrightness(700);
4. Create a Surface object, which will serve as the input. This method is called when HdrVividRender works in rendering mode, and the created Surface object is passed as the inputSurface parameter of configure to the SDK.
Code:
Surface inputSurface = hdrVividRender.createInputSurface();
5. Configure the output parameters.
Set the dimensions of the rendered Surface object. This step is necessary in the rendering mode for output.
Code:
// surfaceView is the video playback window.
hdrVividRender.setOutputSurfaceSize(surfaceView.getWidth(), surfaceView.getHeight());
Set the color space for the buffered output video, which can be set in the transcoding mode for output. This step is optional. However, when no color space is set, BT.709 is used by default.
Code:
hdrVividRender.setColorSpace(HdrVividRender.COLORSPACE_P3);
Set the color format for the buffered output video, which can be set in the transcoding mode for output. This step is optional. However, when no color format is specified, R8G8B8A8 is used by default.
Code:
hdrVividRender.setColorFormat(HdrVividRender.COLORFORMAT_R8G8B8A8);
6. When the rendering mode is used as the output mode, the following APIs are required.
Code:
hdrVividRender.configure(inputSurface, new HdrVividRender.InputCallback() {
@Override
public int onGetDynamicMetaData(HdrVividRender hdrVividRender, long pts) {
// Set the static metadata, which needs to be obtained from the video source.
HdrVividRender.StaticMetaData lastStaticMetaData = new HdrVividRender.StaticMetaData();
hdrVividRender.setStaticMetaData(lastStaticMetaData);
// Set the dynamic metadata, which also needs to be obtained from the video source.
ByteBuffer dynamicMetaData = ByteBuffer.allocateDirect(10);
hdrVividRender.setDynamicMetaData(20000, dynamicMetaData);
return 0;
}
}, surfaceView.getHolder().getSurface(), null);
7. When the transcoding mode is used as the output mode, call the following APIs.
Code:
hdrVividRender.configure(inputSurface, new HdrVividRender.InputCallback() {
@Override
public int onGetDynamicMetaData(HdrVividRender hdrVividRender, long pts) {
// Set the static metadata, which needs to be obtained from the video source.
HdrVividRender.StaticMetaData lastStaticMetaData = new HdrVividRender.StaticMetaData();
hdrVividRender.setStaticMetaData(lastStaticMetaData);
// Set the dynamic metadata, which also needs to be obtained from the video source.
ByteBuffer dynamicMetaData = ByteBuffer.allocateDirect(10);
hdrVividRender.setDynamicMetaData(20000, dynamicMetaData);
return 0;
}
}, null, new HdrVividRender.OutputCallback() {
@Override
public void onOutputBufferAvailable(HdrVividRender hdrVividRender, ByteBuffer byteBuffer,
HdrVividRender.BufferInfo bufferInfo) {
// Process the buffered data.
}
});
new HdrVividRender.OutputCallback() is used for asynchronously processing the returned buffered data. If this method is not used, the read method can be used instead. For example:
Code:
hdrVividRender.read(new BufferInfo(), 10); // 10 is a timestamp, which is determined by your app.
8. Start the processing flow.
Code:
hdrVividRender.start();
9. Stop the processing flow.
Code:
hdrVividRender.stop();
10. Release the resources that have been occupied.
Code:
hdrVividRender.release();
hdrVividRender = null;
During the above steps, I noticed that when the dimensions of Surface change, setOutputSurfaceSize has to be called to re-configure the dimensions of the Surface output.
Besides, in the rendering mode for output, when WisePlayer is switched from the background to the foreground or vice versa, the Surface object will be destroyed and then re-created. In this case, there is a possibility that the HdrVividRender instance is not destroyed. If so, the setOutputSurface API needs to be called so that a new Surface output can be set.
Setting Up HDR Capabilities​HDR capabilities are provided in the class HdrAbility. It can be used to adjust brightness when the HDR Vivid SDK is rendering or transcoding an HDR Vivid video.
1. Initialize the function of brightness adjustment.
Code:
HdrAbility.init(getApplicationContext())
2. Enable the HDR feature on the device. Then, the maximum brightness of the device screen will increase.
Code:
HdrAbility.setHdrAbility(true);
3. Configure the alternative maximum brightness of white points in the output video image data.
Code:
HdrAbility.setBrightness(600);
4. Make the video layer highlighted.
Code:
HdrAbility.setHdrLayer(surfaceView, true);
5. Configure the feature of highlighting the subtitle layer or the bullet comment layer.
Code:
HdrAbility.setCaptionsLayer(captionView, 1.5f);
Summary​Video resolution is an important influencer of user experience for mobile apps. HDR is often used to post-process video, but it is held back by a number of restrictions, which are resolved by the HDR Vivid SDK from Video Kit.
This SDK is loaded with features for image processing such as the OETF, tone mapping, and HDR2SDR, so that it can mimic what human eyes can see to deliver immersive videos that can be enhanced even further with the help of the HDR Ability SDK from the same kit. The functionality and straightforward integration process of these SDKs make them ideal for implementing the HDR feature into a mobile app.

Must-Have Tool for Anonymous Virtual Livestreams

Influencers have become increasingly important, as more and more consumers choose to purchase items online – whether on Amazon, Taobao, or one of the many other prominent e-commerce platforms. Brands and merchants have spent a lot of money finding influencers to promote their products through live streams and consumer interactions, and many purchases are made on the recommendation of a trusted influencer.
However, employing a public-facing influencer can be costly and risky. Many brands and merchants have opted instead to host live streams with their own virtual characters. This gives them more freedom to showcase their products, and widens the pool of potential on camera talent. For consumers, virtual characters can add fun and whimsy to the shopping experience.
E-commerce platforms have begun to accommodate the preference for anonymous livestreaming, by offering a range of important capabilities, such as those that allow for automatic identification, skeleton point-based motion tracking in real time (as shown in the gif), facial expression and gesture identification, copying of traits to virtual characters, a range of virtual character models for users to choose from, and natural real-world interactions.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Building these capabilities comes with its share of challenges. For example, after finally building a model that is able to translate the person's every gesture, expression, and movement into real-time parameters and then applying them to the virtual character, you can find out that the virtual character can't be blocked by real bodies during the livestream, which gives it a fake, ghost-like form. This is a problem I encountered when I developed my own e-commerce app, and it occurred because I did not occlude the bodies that appeared behind and in front of the virtual character. Fortunately I was able to find an SDK that helped me solve this problem — HMS Core AR Engine.
This toolkit provides a range of capabilities that make it easy to incorporate AR-powered features into apps. From hit testing and movement tracking, to environment mesh, and image tracking, it's got just about everything you need. The human body occlusion capability was exactly what I needed at the time.
Now I'll show you how I integrated this toolkit into my app, and how helpful it's been for.
First I registered for an account on the HUAWEI Developers website, downloaded the AR Engine SDK, and followed the step-by-step development guide to integrate the SDK. The integration process was quite simple and did not take too long. Once the integration was successful, I ran the demo on a test phone, and was amazed to see how well it worked. During livestreams my app was able to recognize and track the areas where I was located within the image, with an accuracy of up to 90%, and provided depth-related information about the area. Better yet, it was able to identify and track the profile of up to two people, and output the occlusion information and skeleton points corresponding to the body profiles in real time. With this capability, I was able to implement a lot of engaging features, for example, changing backgrounds, hiding virtual characters behind real people, and even a feature that allows the audience to interact with the virtual character through special effects. All of these features have made my app more immersive and interactive, which makes it more attractive to potential shoppers.
Demo​As shown in the gif below, the person blocks the virtual panda when walking in front of it.
How to Develop​Preparations​Registering as a developer​Before getting started, you will need to register as a Huawei developer and complete identity verification on HUAWEI Developers. You can click here to find out the detailed registration and identity verification procedure.
Creating an app​Create a project and create an app under the project. Pay attention to the following parameter settings:
Platform: Select Android.
Device: Select Mobile phone.
App category: Select App or Game.
Integrating the AR Engine SDK​Before development, integrate the AR Engine SDK via the Maven repository into your development environment.
Configuring the Maven repository address for the AR Engine SDK​The procedure for configuring the Maven repository address in Android Studio is different for Gradle plugin earlier than 7.0, Gradle plugin 7.0, and Gradle plugin 7.1 or later. You need to configure it according to the specific Gradle plugin version.
Adding build dependencies​Open the build.gradle file in the app directory of your project.
Add a build dependency in the dependencies block.
Code:
dependencies {
implementation 'com.huawei.hms:arenginesdk:{version}'
}
Open the modified build.gradle file again. You will find a Sync Now link in the upper right corner of the page. Click Sync Now and wait until synchronization is complete.
Developing Your App​Checking the Availability​Check whether AR Engine has been installed on the current device. If so, the app can run properly. If not, the app prompts the user to install AR Engine, for example, by redirecting the user to AppGallery. The code is as follows:
Code:
boolean isInstallArEngineApk = AREnginesApk.isAREngineApkReady(this);
if (!isInstallArEngineApk) {
// ConnectAppMarketActivity.class is the activity for redirecting users to AppGallery.
startActivity(new Intent(this, com.huawei.arengine.demos.common.ConnectAppMarketActivity.class));
isRemindInstall = true;
}
Create a BodyActivity object to display body bones and output human body features, for AR Engine to recognize human body.
Code:
Public class BodyActivity extends BaseActivity{
Private BodyRendererManager mBodyRendererManager;
Protected void onCreate(){
// Initialize surfaceView.
mSurfaceView = findViewById();
// Context for keeping the OpenGL ES running.
mSurfaceView.setPreserveEGLContextOnPause(true);
// Set the OpenGL ES version.
mSurfaceView.setEGLContextClientVersion(2);
// Set the EGL configuration chooser, including for the number of bits of the color buffer and the number of depth bits.
mSurfaceView.setEGLConfigChooser(……);
mBodyRendererManager = new BodyRendererManager(this);
mSurfaceView.setRenderer(mBodyRendererManager);
mSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
}
Protected void onResume(){
// Initialize ARSession to manage the entire running status of AR Engine.
If(mArSession == null){
mArSession = new ARSession(this.getApplicationContext());
mArConfigBase = new ARBodyTrackingConfig(mArSession);
mArConfigBase.setEnableItem(ARConfigBase.ENABLE_DEPTH | ARConfigBase.ENABLE_MASK);
mArConfigBase.setFocusMode(ARConfigBase.FocusMode.AUTO_FOCUS
mArSession.configure(mArConfigBase);
}
// Pass the required parameters to setBodyMask.
mBodyRendererManager.setBodyMask(((mArConfigBase.getEnableItem() & ARConfigBase.ENABLE_MASK) != 0) && mIsBodyMaskEnable);
sessionResume(mBodyRendererManager);
}
}
Create a BodyRendererManager object to render the personal data obtained by AR Engine.
Code:
Public class BodyRendererManager extends BaseRendererManager{
Public void drawFrame(){
// Obtain the set of all traceable objects of the specified type.
Collection<ARBody> bodies = mSession.getAllTrackables(ARBody.class);
for (ARBody body : bodies) {
if (body.getTrackingState() != ARTrackable.TrackingState.TRACKING){
continue;
}
mBody = body;
hasBodyTracking = true;
}
// Update the body recognition information displayed on the screen.
StringBuilder sb = new StringBuilder();
updateMessageData(sb, mBody);
Size textureSize = mSession.getCameraConfig().getTextureDimensions();
if (mIsWithMaskData && hasBodyTracking && mBackgroundDisplay instanceof BodyMaskDisplay) {
((BodyMaskDisplay) mBackgroundDisplay).onDrawFrame(mArFrame, mBody.getMaskConfidence(),
textureSize.getWidth(), textureSize.getHeight());
}
// Display the updated body information on the screen.
mTextDisplay.onDrawFrame(sb.toString());
for (BodyRelatedDisplay bodyRelatedDisplay : mBodyRelatedDisplays) {
bodyRelatedDisplay.onDrawFrame(bodies, mProjectionMatrix);
} catch (ArDemoRuntimeException e) {
LogUtil.error(TAG, "Exception on the ArDemoRuntimeException!");
} catch (ARFatalException | IllegalArgumentException | ARDeadlineExceededException |
ARUnavailableServiceApkTooOldException t) {
Log(…);
}
}
// Update gesture-related data for display.
Private void updateMessageData(){
if (body == null) {
return;
}
float fpsResult = doFpsCalculate();
sb.append("FPS=").append(fpsResult).append(System.lineSeparator());
int bodyAction = body.getBodyAction();
sb.append("bodyAction=").append(bodyAction).append(System.lineSeparator());
}
}
Customize the camera preview class, which is used to implement human body drawing based on certain confidence.
Code:
Public class BodyMaskDisplay implements BaseBackGroundDisplay{}
Obtain skeleton data and pass the data to the OpenGL ES, which renders the data and displays it on the screen.
Code:
public class BodySkeletonDisplay implements BodyRelatedDisplay {
Obtain skeleton point connection data and pass it to OpenGL ES for rendering the data and display it on the screen.
Code:
public class BodySkeletonLineDisplay implements BodyRelatedDisplay {}
Conclusion​True-to-life AR live-streaming is now an essential feature in e-commerce apps, but developing this capability from scratch can be costly and time-consuming. AR Engine SDK is the best and most convenient SDK I've encountered, and it's done wonders for my app, by recognizing individuals within images with accuracy as high as 90%, and providing the detailed information required to support immersive, real-world interactions. Try it out on your own app to add powerful and interactive features that will have your users clamoring to shop more!
References​AR Engine Development Guide
Sample Code
API Reference

Categories

Resources