Skip to content

Persistence

Save selections to JSON and reload them. Useful when you pick a zone once and reuse it across runs — common in production pipelines that run against the same camera feed.

Save

Every selection type has a .save() method: Box, Multibox, Polygon, MultiPolygon, Line, MultiLine, Point and MultiPoint.

region = pixpick.box("frame.jpg")
region.save("selections/entry_zone.json")

zone = pixpick.polygon("frame.jpg")
zone.save("selections/count_zone.json")

line = pixpick.line("frame.jpg")
line.save("selections/line_zone.json")

picks = pixpick.point("frame.jpg")
picks.save("selections/sam_prompt.json")

Load

pixpick.load() reads the "type" field from the JSON and returns the correct object — you don't need to know what was saved.

selection = pixpick.load("selections/entry_zone.json")
"type" in JSON Returned object
box Box
multibox Multibox
polygon Polygon
multipolygon MultiPolygon
line Line
multiline MultiLine
point Point
multipoint MultiPoint

If you know the type, you can load directly from the class:

from pixpick import Box, Polygon, Line, MultiPoint

region = Box.load("entry_zone.json")
zone   = Polygon.load("count_zone.json")
line   = Line.load("line_zone.json")
picks  = MultiPoint.load("sam_prompt.json")

Loading a file whose "type" does not match the class raises ValueError.

JSON schema

Box

{
  "type": "box",
  "image_size": [1920, 1080],
  "coordinates": {
    "xyxy":       [120, 80, 640, 480],
    "xywh":       [120, 80, 520, 400],
    "normalized": [0.0625, 0.074, 0.333, 0.444]
  }
}

Multibox

{
  "type": "multibox",
  "image_size": [1920, 1080],
  "coordinates": {
    "boxes":      [[120, 80, 640, 480], [700, 200, 900, 500]],
    "normalized": [[0.0625, 0.074, 0.333, 0.444], [0.364, 0.185, 0.468, 0.463]]
  }
}

Polygon

{
  "type": "polygon",
  "image_size": [1920, 1080],
  "coordinates": {
    "points":     [[100, 50], [400, 50], [400, 300], [100, 300]],
    "normalized": [[0.052, 0.046], [0.208, 0.046], [0.208, 0.278], [0.052, 0.278]]
  }
}

MultiPolygon

{
  "type": "multipolygon",
  "image_size": [1920, 1080],
  "coordinates": {
    "polygons":   [[[100, 50], [400, 50], [400, 300]]],
    "normalized": [[[0.052, 0.046], [0.208, 0.046], [0.208, 0.278]]]
  }
}

Line

{
  "type": "line",
  "image_size": [1920, 1080],
  "coordinates": {
    "points":     [[100, 50], [400, 300]],
    "normalized": [[0.052, 0.046], [0.208, 0.278]]
  }
}

MultiLine

{
  "type": "multiline",
  "image_size": [1920, 1080],
  "coordinates": {
    "lines":      [[[100, 50], [400, 300]], [[500, 200], [800, 600]]],
    "normalized": [[[0.052, 0.046], [0.208, 0.278]], [[0.260, 0.185], [0.417, 0.556]]]
  }
}

Point

{
  "type": "point",
  "image_size": [1920, 1080],
  "coordinates": {
    "xy":         [100, 50],
    "label":      1,
    "normalized": [0.052, 0.046]
  }
}

MultiPoint

{
  "type": "multipoint",
  "image_size": [1920, 1080],
  "coordinates": {
    "points":     [[100, 50], [400, 300]],
    "labels":     [1, 0],
    "normalized": [[0.052, 0.046], [0.208, 0.278]]
  }
}

Typical production pattern

Pick once interactively, save, then load on every subsequent run.

import pixpick
from pathlib import Path

ZONE_FILE = "config/count_zone.json"

if Path(ZONE_FILE).exists():
    zone = pixpick.load(ZONE_FILE)
    print("Loaded saved zone.")
else:
    zone = pixpick.polygon("reference_frame.jpg")
    zone.save(ZONE_FILE)
    print("Zone saved.")