madoo.image-faces/v1
Madoo image faces — Where the faces of an image are (Face Detect): score, box and six points (eyes, nose tip, mouth, ears) of each face, and the crop region framed around the selected one. Locates faces, never identifies anyone.
| Reference | madoo.image-faces/v1 |
| Schema id | urn:madoo:schema:image-faces:v1 |
| Version | 1.0.0 |
| Served at | GET /api/v1/json-schemas/madoo.image-faces/v1 · MCP get_json_schema |
Where it appears
Section titled “Where it appears”- Produced by:
image/face_detect→faces
Fields
Section titled “Fields”| Field | Type | Required | Rules | Description |
|---|---|---|---|---|
schema |
"madoo.image-faces/v1" |
yes | ||
algorithm_version |
string | yes | ||
image |
object | yes | ||
image.width |
integer | yes | ≥ 1 | After EXIF orientation. |
image.height |
integer | yes | ≥ 1 | |
image.orientation_applied |
boolean | yes | True when the EXIF orientation rotated or mirrored the image. | |
color |
object | yes | ||
color.working_space |
"srgb-8" |
yes | ||
color.profile_policy |
one of "srgb", "converted", "assumed_srgb" |
yes | srgb: the file is sRGB; converted: its ICC profile was converted to sRGB; assumed_srgb: an RGB image without a profile, read as sRGB. | |
color.source_depth |
integer or null | yes | Bits per channel of the file. | |
color.analysis_depth |
8 |
yes | ||
warnings |
array of string | yes | Facts that limit how the numbers may be read: a JPEG source (compression can contaminate detail measurements), several frames or pages (the first was measured), a source deeper than 8 bits (measured at 8 bits). | |
model |
object | yes | ||
model.name |
string | yes | ||
model.version |
string | yes | ||
model.sha256 |
string | yes | pattern “^[0-9a-f]{64}$” | |
model.input_size |
integer | yes | Side of the square the image is letterboxed into for the model, in pixels. | |
model.runtime |
string | yes | For example onnxruntime 1.30.0 cpu. | |
settings |
object | yes | ||
settings.score_threshold |
number | yes | ||
settings.max_faces |
integer | yes | ||
settings.select |
one of "largest", "highest_score" |
yes | ||
settings.framing |
one of "face", "head", "head_and_shoulders" |
yes | ||
settings.aspect |
one of "none", "1:1", "4:5", "3:4", "2:3", "9:16", "5:4", "4:3", "3:2", "16:9" |
yes | ||
settings.region |
object or null | yes | ||
faces |
array of objects | yes | Sorted by score (descending), then box area, then y, x. | |
faces[].id |
integer | yes | ≥ 1 | Stable within this run only. |
faces[].score |
number | yes | ≥ 0; ≤ 1 | |
faces[].bbox |
object | yes | Pixels of the oriented image, origin top left; covers columns x..x+width-1 and rows y..y+height-1. | |
faces[].bbox.x |
integer | yes | ≥ 0 | |
faces[].bbox.y |
integer | yes | ≥ 0 | |
faces[].bbox.width |
integer | yes | ≥ 1 | |
faces[].bbox.height |
integer | yes | ≥ 1 | |
faces[].keypoints |
object | yes | The person’s right and left: for a face turned to the camera, the right eye is on the left of the picture. The ear points are the tragions, in front of the ears. | |
faces[].keypoints.right_eye |
object | yes | Pixels of the oriented image, kept inside it. | |
faces[].keypoints.right_eye.x |
number | yes | ||
faces[].keypoints.right_eye.y |
number | yes | ||
faces[].keypoints.left_eye |
object | yes | Pixels of the oriented image, kept inside it. | |
faces[].keypoints.left_eye.x |
number | yes | ||
faces[].keypoints.left_eye.y |
number | yes | ||
faces[].keypoints.nose_tip |
object | yes | Pixels of the oriented image, kept inside it. | |
faces[].keypoints.nose_tip.x |
number | yes | ||
faces[].keypoints.nose_tip.y |
number | yes | ||
faces[].keypoints.mouth |
object | yes | Pixels of the oriented image, kept inside it. | |
faces[].keypoints.mouth.x |
number | yes | ||
faces[].keypoints.mouth.y |
number | yes | ||
faces[].keypoints.right_ear |
object | yes | Pixels of the oriented image, kept inside it. | |
faces[].keypoints.right_ear.x |
number | yes | ||
faces[].keypoints.right_ear.y |
number | yes | ||
faces[].keypoints.left_ear |
object | yes | Pixels of the oriented image, kept inside it. | |
faces[].keypoints.left_ear.x |
number | yes | ||
faces[].keypoints.left_ear.y |
number | yes | ||
faces[].size_share |
number | yes | ≥ 0 | Longer side of the box over the shorter side of the image. |
faces[].touches_border |
object | yes | Edges of the searched area (the image, or the region) the box reaches: the face may be cut there. | |
faces[].touches_border.top |
boolean | yes | ||
faces[].touches_border.right |
boolean | yes | ||
faces[].touches_border.bottom |
boolean | yes | ||
faces[].touches_border.left |
boolean | yes | ||
faces[].selected |
boolean | yes | True for the face the crop region is framed around. | |
crop_region |
object or null | yes |
The complete schema
Section titled “The complete schema”madoo.image-faces/v1 (JSON Schema)
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "urn:madoo:schema:image-faces:v1", "title": "Madoo image faces", "description": "What Face Detect (image/face_detect) found: where the faces of a picture are, each with score, box and six points in pixels of the oriented image, and the crop region framed around the selected face. A prediction, not a measurement; scores are not calibrated probabilities. It locates faces and identifies no one.", "type": "object", "required": [ "schema", "algorithm_version", "image", "color", "warnings", "model", "settings", "faces", "crop_region" ], "properties": { "schema": { "const": "madoo.image-faces/v1" }, "algorithm_version": { "type": "string" }, "image": { "$ref": "#/$defs/image" }, "color": { "$ref": "#/$defs/color" }, "warnings": { "$ref": "#/$defs/warnings" }, "model": { "type": "object", "required": [ "name", "version", "sha256", "input_size", "runtime" ], "properties": { "name": { "type": "string" }, "version": { "type": "string" }, "sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" }, "input_size": { "type": "integer", "description": "Side of the square the image is letterboxed into for the model, in pixels." }, "runtime": { "type": "string", "description": "For example onnxruntime 1.30.0 cpu." } } }, "settings": { "type": "object", "required": [ "score_threshold", "max_faces", "select", "framing", "aspect", "region" ], "properties": { "score_threshold": { "type": "number" }, "max_faces": { "type": "integer" }, "select": { "enum": [ "largest", "highest_score" ] }, "framing": { "enum": [ "face", "head", "head_and_shoulders" ] }, "aspect": { "enum": [ "none", "1:1", "4:5", "3:4", "2:3", "9:16", "5:4", "4:3", "3:2", "16:9" ] }, "region": { "oneOf": [ { "$ref": "#/$defs/rect" }, { "type": "null" } ] } } }, "faces": { "type": "array", "description": "Sorted by score (descending), then box area, then y, x.", "items": { "type": "object", "required": [ "id", "score", "bbox", "keypoints", "size_share", "touches_border", "selected" ], "properties": { "id": { "type": "integer", "minimum": 1, "description": "Stable within this run only." }, "score": { "type": "number", "minimum": 0, "maximum": 1 }, "bbox": { "$ref": "#/$defs/rect" }, "keypoints": { "type": "object", "description": "The person's right and left: for a face turned to the camera, the right eye is on the left of the picture. The ear points are the tragions, in front of the ears.", "required": [ "right_eye", "left_eye", "nose_tip", "mouth", "right_ear", "left_ear" ], "properties": { "right_eye": { "type": "object", "required": [ "x", "y" ], "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "description": "Pixels of the oriented image, kept inside it." }, "left_eye": { "type": "object", "required": [ "x", "y" ], "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "description": "Pixels of the oriented image, kept inside it." }, "nose_tip": { "type": "object", "required": [ "x", "y" ], "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "description": "Pixels of the oriented image, kept inside it." }, "mouth": { "type": "object", "required": [ "x", "y" ], "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "description": "Pixels of the oriented image, kept inside it." }, "right_ear": { "type": "object", "required": [ "x", "y" ], "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "description": "Pixels of the oriented image, kept inside it." }, "left_ear": { "type": "object", "required": [ "x", "y" ], "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "description": "Pixels of the oriented image, kept inside it." } } }, "size_share": { "type": "number", "minimum": 0, "description": "Longer side of the box over the shorter side of the image." }, "touches_border": { "type": "object", "description": "Edges of the searched area (the image, or the region) the box reaches: the face may be cut there.", "required": [ "top", "right", "bottom", "left" ], "properties": { "top": { "type": "boolean" }, "right": { "type": "boolean" }, "bottom": { "type": "boolean" }, "left": { "type": "boolean" } } }, "selected": { "type": "boolean", "description": "True for the face the crop region is framed around." } } } }, "crop_region": { "oneOf": [ { "type": "object", "required": [ "x", "y", "width", "height", "face_id", "framing", "aspect", "complete" ], "properties": { "x": { "type": "integer", "minimum": 0 }, "y": { "type": "integer", "minimum": 0 }, "width": { "type": "integer", "minimum": 1 }, "height": { "type": "integer", "minimum": 1 }, "face_id": { "type": "integer", "minimum": 1 }, "framing": { "enum": [ "face", "head", "head_and_shoulders" ] }, "aspect": { "type": "string" }, "complete": { "type": "boolean", "description": "False when the edges of the image cut the framing (no aspect) or reduced it (with an aspect)." } }, "description": "The region to crop, inside the image, in pixels of the whole image." }, { "type": "null" } ] } }, "$defs": { "rect": { "type": "object", "required": [ "x", "y", "width", "height" ], "properties": { "x": { "type": "integer", "minimum": 0 }, "y": { "type": "integer", "minimum": 0 }, "width": { "type": "integer", "minimum": 1 }, "height": { "type": "integer", "minimum": 1 } }, "description": "Pixels of the oriented image, origin top left; covers columns x..x+width-1 and rows y..y+height-1." }, "image": { "type": "object", "required": [ "width", "height", "orientation_applied" ], "properties": { "width": { "type": "integer", "minimum": 1, "description": "After EXIF orientation." }, "height": { "type": "integer", "minimum": 1 }, "orientation_applied": { "type": "boolean", "description": "True when the EXIF orientation rotated or mirrored the image." } } }, "color": { "type": "object", "required": [ "working_space", "profile_policy", "source_depth", "analysis_depth" ], "properties": { "working_space": { "const": "srgb-8" }, "profile_policy": { "enum": [ "srgb", "converted", "assumed_srgb" ], "description": "srgb: the file is sRGB; converted: its ICC profile was converted to sRGB; assumed_srgb: an RGB image without a profile, read as sRGB." }, "source_depth": { "type": [ "integer", "null" ], "description": "Bits per channel of the file." }, "analysis_depth": { "const": 8 } } }, "sampling": { "type": "object", "required": [ "method", "step", "eligible_pixels", "sampled_pixels" ], "properties": { "method": { "enum": [ "grid", "full" ] }, "step": { "type": "integer", "minimum": 1 }, "eligible_pixels": { "type": "integer", "minimum": 0, "description": "Pixels of the region that may be measured: opaque enough and inside the mask." }, "sampled_pixels": { "type": "integer", "minimum": 0 } } }, "warnings": { "type": "array", "items": { "type": "string" }, "description": "Facts that limit how the numbers may be read: a JPEG source (compression can contaminate detail measurements), several frames or pages (the first was measured), a source deeper than 8 bits (measured at 8 bits)." }, "status": { "enum": [ "ok", "not_observable" ], "description": "not_observable: the measurement is undefined here (see reason); its numbers are null. Zero is a valid measurement, never a stand-in for null." }, "reason": { "type": [ "string", "null" ], "enum": [ null, "no_eligible_pixels", "too_few_samples", "zero_variance", "no_eligible_patches", "mask_empty_in_region" ] } }}