Implement Windows Beauty
On Windows, the Facebetter SDK is accessed through its C++ interface. This guide follows the C++ Desktop Demo as a reference for the complete integration flow.
Include Headers
#include <facebetter/beauty_effect_engine.h>
#include <facebetter/beauty_params.h>
#include <facebetter/image_frame.h>
#include <facebetter/type_defines.h>
using namespace facebetter;
using namespace facebetter::beauty_params;Integration Overview
Configure logging → Create engine → Enable beauty types → Set params → Process frames → Render result1. Configure Logging (optional)
Call this before creating the engine so that initialization log messages are captured.
LogConfig log_cfg;
log_cfg.console_enabled = true; // print to console
log_cfg.file_enabled = false; // no log file
log_cfg.level = LogLevel::Info;
BeautyEffectEngine::SetLogConfig(log_cfg);Log levels (ascending): Trace / Debug / Info / Warn / Error / Critical.
2. Create the Engine
EngineConfig eng_cfg;
eng_cfg.app_id = "your_app_id";
eng_cfg.app_key = "your_app_key";
eng_cfg.resource_path = "resource/resource.fbd"; // relative or absolute path
eng_cfg.external_context = false; // SDK manages its own OpenGL context
std::shared_ptr<BeautyEffectEngine> engine = BeautyEffectEngine::Create(eng_cfg);
if (!engine) {
// Check app_id / app_key / resource_path
return -1;
}
resource_pathmust point to theresource.fbdfile shipped with the SDK, which contains AI models and filter assets.
3. Enable Beauty Types
All beauty types are disabled by default and must be explicitly enabled:
engine->SetBeautyTypeEnabled(BeautyType::Basic, true); // skin beauty
engine->SetBeautyTypeEnabled(BeautyType::Reshape, true); // face reshaping
engine->SetBeautyTypeEnabled(BeautyType::Makeup, true); // makeup
engine->SetBeautyTypeEnabled(BeautyType::Sticker, true); // stickers4. Set Beauty Parameters
All parameter values are in the range [0.0, 1.0]. A value of 0 disables the effect.
Basic Beauty
engine->SetBeautyParam(Basic::Smoothing, 0.5f); // smoothing
engine->SetBeautyParam(Basic::Whitening, 0.3f); // whitening
engine->SetBeautyParam(Basic::Rosiness, 0.2f); // rosy tone
engine->SetBeautyParam(Basic::Sharpening, 0.4f); // sharpeningSkin-Only Beauty
Use SetSkinOnlyBeauty to set whether beauty effects are applied only to skin regions. When enabled, beauty effects (smoothing, whitening, etc.) will only be applied to detected skin areas, leaving non-skin areas unchanged.
// Enable skin-only beauty
engine->SetSkinOnlyBeauty(true);
// Disable skin-only beauty (apply to entire image)
engine->SetSkinOnlyBeauty(false);TIP
After enabling skin-only beauty, even with high beauty parameter values, non-skin areas (such as background, clothing, etc.) will not be affected.
Face Reshape
engine->SetBeautyParam(Reshape::FaceThin, 0.4f); // face slimming
engine->SetBeautyParam(Reshape::FaceVShape, 0.3f); // V-face
engine->SetBeautyParam(Reshape::FaceNarrow, 0.2f); // narrow face
engine->SetBeautyParam(Reshape::FaceShort, 0.2f); // short face
engine->SetBeautyParam(Reshape::Cheekbone, 0.3f); // cheekbone slimming
engine->SetBeautyParam(Reshape::Jawbone, 0.2f); // jaw slimming
engine->SetBeautyParam(Reshape::Chin, 0.2f); // chin slimming
engine->SetBeautyParam(Reshape::NoseSlim, 0.3f); // nose bridge slimming
engine->SetBeautyParam(Reshape::EyeSize, 0.4f); // eye enlarging
engine->SetBeautyParam(Reshape::EyeDistance, 0.1f); // eye distanceMakeup
engine->SetBeautyParam(Makeup::Lipstick, 0.6f); // lipstick
engine->SetBeautyParam(Makeup::Blush, 0.4f); // blushStickers
Pass a sticker ID string to activate; pass an empty string to disable. Built-in sticker IDs are bundled in resource.fbd:
engine->SetSticker("rabbit"); // enable the "rabbit" sticker
engine->SetSticker(""); // disable stickerFilters (LUT)
engine->SetFilter("chuxin"); // apply filter
engine->SetFilterIntensity(0.8f); // filter intensity
engine->SetFilter(""); // disable filter5. Process Frames
Typical per-frame processing:
// Create an input frame from in-memory RGBA data (video stream)
auto input_frame = ImageFrame::CreateWithRGBA(
rgba_data, width, height, stride);
// Set frame type: Video (live stream) or Image (single photo)
input_frame->type = FrameType::Video;
// Process
auto output_frame = engine->ProcessImage(input_frame);
if (output_frame && output_frame->Data()) {
int w = output_frame->Width();
int h = output_frame->Height();
const uint8_t* p = output_frame->Data(); // RGBA, same format as input
}Load from file (single-image mode):
auto input_frame = ImageFrame::CreateWithFile("input.jpg");
input_frame->type = FrameType::Image;
auto output_frame = engine->ProcessImage(input_frame);Convert output format if needed:
auto bgra_frame = output_frame->Convert(Format::BGRA);
auto i420_frame = output_frame->Convert(Format::I420);6. OpenGL Integration (render preview)
Upload the processed RGBA data to an OpenGL texture:
// Create texture (once)
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Upload per frame
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
output_frame->Width(), output_frame->Height(),
0, GL_RGBA, GL_UNSIGNED_BYTE, output_frame->Data());
// Render with ImGui or a custom quad
ImGui::Image(
static_cast<ImTextureID>(static_cast<intptr_t>(tex)),
ImVec2(img_w, img_h));7. Full Example (real-time processing loop)
The snippet below is drawn directly from the demo and shows the complete processing loop with frame-rate limiting:
#include <facebetter/beauty_effect_engine.h>
#include <facebetter/beauty_params.h>
#include <facebetter/image_frame.h>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
using namespace facebetter;
using namespace facebetter::beauty_params;
// --- Initialization ---
LogConfig log_cfg;
log_cfg.console_enabled = true;
log_cfg.level = LogLevel::Info;
BeautyEffectEngine::SetLogConfig(log_cfg);
EngineConfig eng_cfg;
eng_cfg.app_id = "your_app_id";
eng_cfg.app_key = "your_app_key";
eng_cfg.resource_path = "resource/resource.fbd";
eng_cfg.external_context = false;
auto engine = BeautyEffectEngine::Create(eng_cfg);
engine->SetBeautyTypeEnabled(BeautyType::Basic, true);
engine->SetBeautyTypeEnabled(BeautyType::Reshape, true);
engine->SetBeautyTypeEnabled(BeautyType::Makeup, true);
engine->SetBeautyTypeEnabled(BeautyType::Sticker, true);
engine->SetBeautyParam(Basic::Smoothing, 0.5f);
engine->SetBeautyParam(Reshape::FaceThin, 0.4f);
engine->SetBeautyParam(Makeup::Lipstick, 0.6f);
// --- Processing loop (~30 fps) ---
double last_time = 0.0;
const double kInterval = 1.0 / 30.0;
GLuint preview_tex = 0;
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
double now = glfwGetTime();
if (now - last_time >= kInterval) {
auto input = ImageFrame::CreateWithRGBA(
rgba_buffer, width, height, stride);
input->type = FrameType::Video;
auto output = engine->ProcessImage(input);
if (output && output->Data()) {
if (preview_tex == 0) {
glGenTextures(1, &preview_tex);
glBindTexture(GL_TEXTURE_2D, preview_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
glBindTexture(GL_TEXTURE_2D, preview_tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
output->Width(), output->Height(),
0, GL_RGBA, GL_UNSIGNED_BYTE, output->Data());
}
last_time = now;
}
// ... ImGui render ...
}
// --- Cleanup ---
if (preview_tex) glDeleteTextures(1, &preview_tex);
engine.reset();Quick Reference
BeautyType
| Value | Description |
|---|---|
BeautyType::Basic | Skin beauty |
BeautyType::Reshape | Face reshaping |
BeautyType::Makeup | Makeup |
BeautyType::Sticker | Stickers |
Basic Parameters
| Parameter | Description |
|---|---|
Basic::Smoothing | Skin smoothing |
Basic::Whitening | Skin whitening |
Basic::Rosiness | Rosy tone |
Basic::Sharpening | Sharpening |
Skin-Only Beauty
| Method | Description |
|---|---|
SetSkinOnlyBeauty(true) | Enable skin-only beauty |
SetSkinOnlyBeauty(false) | Disable skin-only beauty |
Reshape Parameters
| Parameter | Description |
|---|---|
Reshape::FaceThin | Face slimming |
Reshape::FaceVShape | V-face |
Reshape::FaceNarrow | Narrow face |
Reshape::FaceShort | Short face |
Reshape::Cheekbone | Cheekbone slimming |
Reshape::Jawbone | Jaw slimming |
Reshape::Chin | Chin slimming |
Reshape::NoseSlim | Nose bridge slimming |
Reshape::EyeSize | Eye enlarging |
Reshape::EyeDistance | Eye distance |
Makeup Parameters
| Parameter | Description |
|---|---|
Makeup::Lipstick | Lipstick |
Makeup::Blush | Blush |
ImageFrame Factory Methods
| Method | Description |
|---|---|
ImageFrame::CreateWithFile(path) | Load from file (JPEG/PNG/BMP) |
ImageFrame::CreateWithRGBA(data, w, h, stride) | Create from in-memory RGBA data |
ImageFrame::CreateWithBGRA(data, w, h, stride) | Create from in-memory BGRA data |
ImageFrame::CreateWithRGB(data, w, h, stride) | Create from in-memory RGB data |
ImageFrame::CreateWithI420(w, h, y, sy, u, su, v, sv) | Create from I420 YUV data |
ImageFrame::CreateWithNV12(w, h, y, sy, uv, suv) | Create from NV12 data |
frame->Convert(Format::RGBA) | Convert to another format (returns new frame) |

