Perfectly Clear SDK Documentation  10.0.1.537
Examples (C Sharp)

Sample code C# projects are provided along with the SDK. The examples below demonstrate the general usage of the Perfectly Clear SDK (class PerfectlyClear ).

Setting up License Protection

If you have been provided with a license protected SDK, then there are two ways that you can activate this license in your code. It is always safe to use the multi-threading approach, though it does take slightly more code. The scenarios below on the sections below show the single-threaded method, as it's simpler and our sample code is all single-threaded.

Single-Threaded

This method requires fewer calls to our SDK, but isn't intended for multithreaded applications where many concurrent calls will be made at once. The process is to setup the protection path when calling the class constructor.

// Instantiate class object with the path to your sdk_license folder:
PerfectlyClearAdapter.PerfectlyClear PfC = new PerfectlyClearAdapter.PerfectlyClear("C:\\PerfectlyClear\\sdk_license");
// then, just load your Presets or parameters, load the image, and apply the corrections
// this part is documented below, so it it omitted here
// ...
//
// After all processing is complete, the class destructor takes care of releasing the resources allocated by the constructor.

Multi-Threaded

// Set the protection path at application startup:
PerfectlyClearAdapter.PerfectlyClear.SetProtectionPath("C:\\PerfectlyClear\\sdk_license");
// Then, the threaded portion of the code, looping over images:
for (int i = 0; i < images.count; i++) {
// Call the constructor once per image, omitting the constructor parameters
// then, load the correction parameters and images, correct and save the results
// details of this is omitted here, see below for options on this
// ...
// Dispose of the class once done:
PfC.Dispose()
}
// Last, release the resources from the protection step:

Simple AI Sample - Using Scene Detection

This is the simplest way to use Perfectly Clear AI.

  1. Load image to correct:
    Bitmap bm = new Bitmap(inname);
    // Check if image opened successfully.
    if (bm == null)
    {
    Console.WriteLine("Unable to open image.");
    return;
    }
  2. Initialize the AI Engines
    // Use AI-enabled PFCENGINE to do scene detection and apply a scene preset
    // IMPORTANT: initialization of AI engine takes time.
    // Load AI engine (assuming all dlls and models are in exe folder):
    string execPath = AppDomain.CurrentDomain.BaseDirectory;
    int aistatus = Pfc.LoadAiEngine(PFCAIFEATURE.AI_SCENE_DETECTION | PFCAIFEATURE.AI_CORRECTIONS, execPath);
    if (((PFCAIFEATURE)aistatus & PFCAIFEATURE.AI_SCENE_DETECTION) != PFCAIFEATURE.AI_SCENE_DETECTION) {
    Console.WriteLine("Cannot load AI SD engine. Make sure the pnn file and PFCAI libraries are in the executable directory or change binPath.");
    return;
    }
    if (((PFCAIFEATURE)aistatus & PFCAIFEATURE.AI_CORRECTIONS) != PFCAIFEATURE.AI_CORRECTIONS) {
    Console.WriteLine("Cannot load AI corrections engine. Make sure the pnn file and PFCAI libraries are in the executable directory or change binPath.");
    return;
    }
  3. Perform full correction using the auto function:
    // Enhance image.
    int aret = Pfc.AutoCorrect(ref bm);
    // Optionally show return code of the process.
    if (bVerbose)
    {
    // Check if there's any warning
    if (aret == (int)PerfectlyClearAdapter.PFCAPPLYSTATUS.APPLY_SUCCESS)
    {
    Console.WriteLine("Image processed successfully.");
    }
    else if (aret > 0)
    {
    // In case of error, query LastStatus for individual return code
    Console.WriteLine("Noise removal return code: " + Pfc.LastStatus.NR_Status.ToString());
    Console.WriteLine("Perfectly Clear core return code: " + Pfc.LastStatus.CORE_Status.ToString());
    Console.WriteLine("Face beautification return code: " + Pfc.LastStatus.FB_Status.ToString());
    Console.WriteLine("Red eye removal return code: " + Pfc.LastStatus.RE_Status.ToString());
    }
    else if (aret < 0)
    {
    // In case of general process error (negative return code)
    Console.WriteLine("Perfectly Clear return code: " + aret.ToString());
    }
    }
  4. Save the corrected image
    // Save processed image.
    bm.Save(outname);

Detailed AI Sample - Using Scene Detection

To extend the example shown above, you can load custom AI Presets to apply, instead of using the default presets provided by this SDK:

// You can change the presets from a custom preset file with LoadScenePresets but it
// must have same group and presets uids as embedded preset.
//
// By default when loading a AI_SCEE_DECTECTION we load the embeded presets immediately afterwards.
// You can return back to default presets embedded into the model (.pnn) with presetPath = null.
if(presetfile != "") {
int retLoadPresets = Pfc.LoadScenePresets(presetfile);
if (0 != retLoadPresets) {
Console.WriteLine("Cannot load scene presets file '{0}' error '{1}'.", presetfile, retLoadPresets);
return;
}
}

And you can determine the scene ID and label:

// After detectionn the scene id and model version can be optained through PFC_GetScene/
// The specific meaning depends on the model loaded.
int version = 0;
int detectedScene = Pfc.GetScene(&version);
Console.WriteLine("Model '{0}' assigned scene '{1}' to the image.\n", version, detectedScene);

AI Image Correction without Scene Detection

You can correct photos without scene detection, but still using the AI Image corrections that are new in this V10 SDK:

  1. load the correction parameters to apply from a .preset file
    // Optionally, you can import process parameters from a preset file
    if (presetfile != "")
    {
    int rc = Pfc.ReadPresets(presetfile);
    if (bVerbose)
    {
    Console.WriteLine("ReadPresets returns " + rc.ToString());
    }
    }
  2. then use these parameters when correcting the image
    // Enhance image.
    PerfectlyClearAdapter.PFCAPPLYSTATUS aret = Pfc.Apply(ref bm, 100);
    // Optionally show return code of the process.
    if (bVerbose)
    {
    // Check if there's any warning
    if (aret == PerfectlyClearAdapter.PFCAPPLYSTATUS.APPLY_SUCCESS)
    {
    Console.WriteLine("Image processed successfully.");
    }
    else if (aret > 0)
    {
    // In case of error, query LastStatus for individual return code
    Console.WriteLine("Noise removal return code: " + Pfc.LastStatus.NR_Status.ToString());
    Console.WriteLine("Perfectly Clear core return code: " + Pfc.LastStatus.CORE_Status.ToString());
    Console.WriteLine("Face beautification return code: " + Pfc.LastStatus.FB_Status.ToString());
    Console.WriteLine("Red eye removal return code: " + Pfc.LastStatus.RE_Status.ToString());
    }
    else if (aret < 0)
    {
    // In case of general process error (negative return code)
    Console.WriteLine("Perfectly Clear return code: " + aret.ToString());
    }
    }

Using MemoryStreams

We have introduced the ability to read and write image data using .NET native MemoryStreams. If the application you are working on already has image file data loaded into MemoryStreams, this method allows you to use those directly, instead of needing to write image files to disk.

// create a PFCImageFile called 'file' we will load into below
// Read input file to a MemoryStream and check if image opened successfully
// Typically, the MemoryStream would already exist in the application you are developing
MemoryStream inMemoryCopy = new MemoryStream();
using (FileStream fs = File.OpenRead(inname))
{
fs.CopyTo(inMemoryCopy);
}
// remember to set the right position to begin reading
inMemoryCopy.Position = 0;
// Call ExpandImageBuffer to read the MemoryStream and load into the 'file' PFCImageFile
if (file.ExpandImageBuffer(inMemoryCopy, PFCImageFile.PFC_FILETYPE.PFC_JPEG, true, "") != PFCImageFile.PFC_FILE_LOAD_STATUS.LOAD_OK)
{
Console.WriteLine("Unable to open image.");
ShowHelp();
return;
}

Now, you can process the PFCImageFile like in the other samples, the most simple way would be:

Pfc.AutoCorrect(ref file, "my_preset.preset");

Now, the 'file' object has been corrected, so to get the corrected image data back into a MemoryStream:

// Read from the corrected 'file' PFCImageFile and write contents to a MemoryStream
// Perform JPEG compression, color management, and embed EXIF metadata from the original file
using (MemoryStream outStream = file.CompressImageBuffer(PFCImageFile.PFC_FILETYPE.PFC_JPEG, 90, false, true))
{
// seek to the beginning, then write to a file, or pass along to further operations
// within your application
outStream.Seek(0, SeekOrigin.Begin);
FileStream outFile = File.Create(outname);
outStream.CopyTo(outFile);
}

Loading From Bitmaps or with PfCImageFile

You can either load image data using our PFCImageFile class, or you can use standard Windows bitmaps. SimpleAiSample shows the bitmap method. If you are incorporating Perfectly Clear into an application that already is using Bitmaps, then this method will make it easy to incorporate Perfectly Clear into this.

Bitmap bm = new Bitmap(input_image_file_name);

In DotNetCore_PFCImageFile, we use the PfCImageFile class instead, shown in a simplified form here:

PfCImageFile class will handle color space conversion and metadata management automatically.

.NET Core Version Issues

In the .NET Core examples, there are PreBuildEvent steps to copy the required libraries into the proper build location. For example:

<PropertyGroup>
<PreBuildEvent>
xcopy /C /E /Y /R ..\..\..\..\..\bin\x64\PerfectlyClearPro.dll .\PerfectlyClearPro.dll*
xcopy /C /E /Y /R ..\..\..\..\..\bin\x64\PerfectlyClearAdapter.dll .
xcopy /C /E /Y /R ..\..\..\..\..\bin\x64\PFCImageFile.dll .
xcopy /C /E /Y /R ..\..\..\..\..\bin\x64\exiv2.dll .
</PreBuildEvent>
</PropertyGroup>

Depending on which version of Visual Studio and .NET Core version you are using, these steps might cause errors when you build. This is due to an extra folder level that Visual Studio builds in some cases. The solution is to remove one set of "..\" from these steps, like this:

<PropertyGroup>
<PreBuildEvent>
xcopy /C /E /Y /R ..\..\..\..\bin\x64\PerfectlyClearPro.dll .\PerfectlyClearPro.dll*
xcopy /C /E /Y /R ..\..\..\..\bin\x64\PerfectlyClearAdapter.dll .
xcopy /C /E /Y /R ..\..\..\..\bin\x64\PFCImageFile.dll .
xcopy /C /E /Y /R ..\..\..\..\bin\x64\exiv2.dll .
</PreBuildEvent>
</PropertyGroup>
PFCAIFEATURE
PFCAIFEATURE
Flags defining type of model(s) to load with PFC_LoadAIEngine().
Definition: PerfectlyClearPro.h:1032
PerfectlyClearAdapter.PerfectlyClear.SetProtectionPath
static int SetProtectionPath(string path, string licenseCode)
Set path to location of SDK License files This enables license protection and allows activation using...
Definition: PerfectlyClearAdapter.cs:728
PerfectlyClearAdapter.PFCImageFile.LoadImage
PFC_FILE_LOAD_STATUS LoadImage(string filename, bool bConvertToSRGB=false, string iccFolderPath=null)
Load JPEG from file on disk.
Definition: PerfectlyClearAdapter.cs:2415
PFCImageFile::PFC_FILETYPE
PFC_FILETYPE
Type for compressing/decomrpessing a buffer.
Definition: PFCImageFile.h:73
PerfectlyClearAdapter.PerfectlyClear.ReleaseProtectionPath
static void ReleaseProtectionPath()
Releases resources from SetProtectionPath.
Definition: PerfectlyClearAdapter.cs:767
PFCImageFile
PFCImageFile Class to encapsulate file handling.
Definition: PFCImageFile.h:69
PerfectlyClearAdapter.PFCImageFile
PFCImageFile Class to encapsulate file handling.
Definition: PerfectlyClearAdapter.cs:2357
PerfectlyClearAdapter.PerfectlyClear
Definition: PerfectlyClearAdapter.cs:633
PerfectlyClearAdapter
Definition: PerfectlyClearAdapter.cs:16