Processing Block
Requirements
- Added links to the library FacerecCSharpWrapper.dlland OpenCvSharp4
Create a processing block
The ProcessingBlock object is used for face detection and image quality assessment.
Block type
Modification  
The sequence of actions when using the ProcessingBlock object:
- Create a ProcessingBlockobject.
ProcessingBlock processingBlock = service.CreateProcessingBlock
(
    new()
    {
        { "unit_type", "<Block type>" },
        { "modification", "<Modification>" },
        { "version", <Version> }
    }
);
- Read an image from a file.
byte[] imageData = File.ReadAllBytes(imagePath);
- Create Context
Context data = service.CreateContextFromImage(imageData);
- Call Invokemethod ofProcessingBlock
processingBlock.Invoke(data);
- Output data is in data["objects"]
Data usage example
Getting the coordinates of the top left and bottom right bbox points
for (int i = 0; i < (int)objects.Length(); i++)
{
      Context obj = objects[i];
      Context bbox = obj["bbox"];
      // Top left bbox point
      double x1 = bbox[0].GetDouble() * <image width>;
      double y1 = bbox[1].GetDouble() * <image height>;
      
      // Bottom right bbox point
      double x2 = bbox[2].GetDouble() * <image width>;
      double y2 = bbox[3].GetDouble() * <image height>;
}
1. Create a ProcessingBlock FaceDetector
FaceDetector is used to detect faces in an image.
ProcessingBlock faceDetector = service.CreateProcessingBlock
(
      new()
      {
            { "unit_type", "FACE_DETECTOR" },
            { "modification", "uld" },
            { "precision_level", 3 }
      }
);
2. Create a ProcessingBlock FaceFitter
FaceFitter is used to find key points of faces in an image
For some ProcessingBlocks to work, you need to use the combination FaceDetector + FaceFitter
ProcessingBlock fitter = service.CreateProcessingBlock
(
      new()
      {
            { "unit_type", "FACE_FITTER" },
            { "modification", "tddfa" }
      }
);
3. Verification (1:1)
FaceTemplateExtractor is used to extract the face template
VerificationModule is used for 1:1 verification
static Context ExtractTemplates(string imagePath, FacerecService service, List<ProcessingBlock> pipeline)
{
    byte[] imageData = File.ReadAllBytes(imagePath);
    Context data = service.CreateContextFromImage(imageData);
    foreach (ProcessingBlock processingBlock in pipeline)
    {
        processingBlock.Invoke(data);
    }
    return data;
}
static void Main(string[] args)
{
    FacerecService service = FacerecService.createService
    (
        "<Path to /conf/facerec>",
        "<Path to /license>"
    );
    string firstImagePath = "<Path to first image>";
    string secondImagePath = "<Path to second image>";
    ProcessingBlock faceDetector = service.CreateProcessingBlock
    (
        new()
        {
            { "unit_type", "FACE_DETECTOR" },
            { "modification", "uld" },
            { "precision_level", 3 }
        }
    );
    ProcessingBlock faceFitter = service.CreateProcessingBlock
    (
        new()
        {
            { "unit_type", "FACE_FITTER" },
            { "modification", "tddfa" }
        }
    );
    ProcessingBlock faceTemplateExtractor = service.CreateProcessingBlock
    (
        new()
        {
            { "unit_type", "FACE_TEMPLATE_EXTRACTOR" },
            { "modification", "1000" }
        }
    );
    ProcessingBlock verificationModule = service.CreateProcessingBlock
    (
        new()
        {
            { "unit_type", "VERIFICATION_MODULE" },
            { "modification", "1000" }
        }
    );
    List<ProcessingBlock> pipeline = [
        faceDetector,
        faceFitter,
        faceTemplateExtractor
    ];
    Context first = ExtractTemplates(firstImagePath, service, pipeline);
    Context second = ExtractTemplates(secondImagePath, service, pipeline);
    Context verificationData = service.CreateContext
    (
        new Dictionary<object, object>
        {
            { "template1", first["objects"][0]["template"] },
            { "template2", second["objects"][0]["template"] }
        }
    );
    verificationModule.Invoke(verificationData);
    double distance = verificationData["result"]["distance"].GetDouble();
    double score = verificationData["result"]["score"].GetDouble();
    double far = verificationData["result"]["far"].GetDouble();
    double frr = verificationData["result"]["frr"].GetDouble();
    Console.WriteLine($"Verification result\ndistance: {distance}\nscore: {score}\nfar: {far}\nfrr: {frr}");
}
4. Identification (1:N)
FaceTemplateExtractor is used to extract the face template.
TemplateIndex is used to search for templates.
MatcherModule is used for 1:N identification.
static Context ExtractTemplates(string imagePath, FacerecService service, List<ProcessingBlock> pipeline)
{
    byte[] imageData = File.ReadAllBytes(imagePath);
    Context data = service.CreateContextFromImage(imageData);
    foreach (ProcessingBlock processingBlock in pipeline)
    {
        processingBlock.Invoke(data);
    }
    return data;
}
static void Main(string[] args)
{
    FacerecService service = FacerecService.createService
    (
        "<Path to /conf/facerec>",
        "<Path to /license>"
    );
    string firstImagePath = "<Path to first image>";
    string secondImagePath = "<Path to second image>";
    ProcessingBlock faceDetector = service.CreateProcessingBlock
    (
        new()
        {
            { "unit_type", "FACE_DETECTOR" },
            { "modification", "uld" },
            { "precision_level", 3 }
        }
    );
    ProcessingBlock faceFitter = service.CreateProcessingBlock
    (
        new()
        {
            { "unit_type", "FACE_FITTER" },
            { "modification", "tddfa" }
        }
    );
    ProcessingBlock faceTemplateExtractor = service.CreateProcessingBlock
    (
        new()
        {
            { "unit_type", "FACE_TEMPLATE_EXTRACTOR" },
            { "modification", "1000" }
        }
    );
    ProcessingBlock templateIndex = service.CreateProcessingBlock
    (
        new()
        {
            { "unit_type", "TEMPLATE_INDEX" },
            { "modification", "1000" }
        }
    );
    ProcessingBlock matcherModule = service.CreateProcessingBlock
    (
        new()
        {
            { "unit_type", "MATCHER_MODULE" },
            { "modification", "1000" }
        }
    );
    Context templates = service.CreateContext(new());
    List<ProcessingBlock> pipeline = [
        faceDetector,
        faceFitter,
        faceTemplateExtractor
    ];
    Context first = ExtractTemplates(firstImagePath, service, pipeline);
    Context second = ExtractTemplates(secondImagePath, service, pipeline);
    for (int i = 0; i < (int)second["objects"].Length(); i++)
    {
        templates.PushBack(second["objects"][i]["template"]);
    }
    second["templates"] = templates;
    templateIndex.Invoke(second);
    Context matcherData = service.CreateContext
    (
        new Dictionary<object, object>
        {
            { "knn", 1 },
            { "template_index", second["template_index"] },
            { "queries", new List<object> { first["objects"][0] } }
        }
    );
    matcherModule.Invoke(matcherData);
    long findIndex = matcherData["results"][0]["index"].GetLong();
    double distance = matcherData["results"][0]["distance"].GetDouble();
    double score = matcherData["results"][0]["score"].GetDouble();
    Console.WriteLine($"Identify result\ndistance: {distance}\nscore: {score}\nindex: {findIndex}");
}