Documentation

Color Analysis

Extract dominant colors and search images by color properties

Automatic on Upload

Color extraction runs automatically whenever you upload images — no extra call needed. Use client.colors.get() to retrieve colors after upload. The extract() method is only needed to re-run extraction with different settings (e.g., fewer colors or force refresh).

Get Image Colors

Retrieve colors from an uploaded image

python
async with Scopix(api_key="scopix_...") as client:
# Upload an image (colors extracted automatically)
upload = await client.files.upload("furniture.jpg")
# Get the extracted colors
result = await client.colors.get(upload.image_id)
if result.is_completed:
for color in result.color_analysis.dominant_colors:
print(f"{color.name}: {color.hex} ({color.percentage:.1f}%)")
print(f" Family: {color.family}")
print(f" RGB: ({color.rgb.r}, {color.rgb.g}, {color.rgb.b})")

Re-extraction (Optional)

Colors are extracted automatically on upload with up to 16 colors. Use extract() only if you need to re-run with different settings.

python
# Re-extract with fewer colors (3-16 range)
result = await client.colors.extract(
image_id,
n_colors=6
)
# Force re-extraction even if colors already exist
result = await client.colors.extract(
image_id,
force=True,
n_colors=8
)

Color Analysis Structure

Understanding the color analysis response

python
result = await client.colors.get(image_id)
if result.is_completed:
analysis = result.color_analysis
# Dominant colors (ordered by percentage)
for color in analysis.dominant_colors:
print(f"{color.rank}. {color.name} ({color.hex})")
print(f" Coverage: {color.percentage:.1f}%")
print(f" Family: {color.family}")
# Multiple color spaces available
print(f" RGB: ({color.rgb.r}, {color.rgb.g}, {color.rgb.b})")
print(f" HSL: ({color.hsl.h:.0f}, {color.hsl.s:.0f}%, {color.hsl.l:.0f}%)")
print(f" LAB: ({color.lab.l:.1f}, {color.lab.a:.1f}, {color.lab.b:.1f})")
# Overall analytics
temp = analysis.analytics.temperature
print(f"Temperature: {temp.value} (score: {temp.score:.2f})")
brightness = analysis.analytics.brightness
print(f"Brightness: {brightness.category} (avg: {brightness.average:.0f})")
saturation = analysis.analytics.saturation
print(f"Saturation: {saturation.category} (avg: {saturation.average:.0f})")

Search by Color

Search by Hex Code

Find images matching a specific color with perceptual tolerance

python
# Search for walnut/brown colors
results = await client.colors.search(
hex_code="#8B4513",
delta_e_threshold=20.0, # Perceptual difference tolerance (0-100, default: 15.0)
min_percentage=10.0 # Minimum color coverage (default: 5.0)
)
print(f"Found {results.total_count} images")
for r in results.results:
print(f"Image {r.image_id}: score {r.match_score:.2f}")
if r.thumbnail_url:
print(f" Thumbnail: {r.thumbnail_url}")

Delta-E Color Matching

Understanding perceptual color difference

Delta-EPerceptionUse Case
0-5Imperceptible to slightExact color matching
5-15NoticeableSimilar color search
15-30Obvious differenceSame color family
30+Different colorsBroad category matching

Search by Color Family

Find images by semantic color category

python
# Find all earth-toned images
earth_tones = await client.colors.search(
color_family="earth_tone",
limit=100
)
# Find earth tones with significant presence
warm_earth = await client.colors.search(
color_family="earth_tone",
min_percentage=20.0 # Significant presence
)
# Find metallic colors
metallic = await client.colors.search(
color_family="metallic"
)

Search by Color Name

Search using semantic color names

python
# Find brass-colored materials
brass = await client.colors.search(color_name="brass")
# Find walnut-colored items
walnut = await client.colors.search(color_name="walnut")
# Find marble/white stone
marble = await client.colors.search(color_name="marble")

Paginated Search

Handle large result sets with pagination

python
# Paginate through all results
all_results = []
offset = 0
while True:
page = await client.colors.search(
color_family="neutral",
limit=50,
offset=offset
)
all_results.extend(page.results)
if not page.has_more:
break
offset += len(page.results)
print(f"Total: {len(all_results)} images")

Auto-Pagination

Use search_all() to automatically iterate through all pages

python
# Iterate through all matching results automatically
async for result in client.colors.search_all(color_family="earth_tone"):
print(f"Image {result.image_id}: {len(result.colors)} colors")

Color Families

List Available Families

Get all color families with descriptions

python
families = await client.colors.list_families()
for family in families:
print(f"{family.display_name}")
print(f" {family.description}")
print(f" Examples: {', '.join(family.example_colors[:3])}")

Available Color Families

FamilyDescription
neutralBlacks, whites, grays - versatile foundation colors
earth_toneWarm, natural colors inspired by earth and nature
warmReds, oranges, yellows - energizing and inviting
coolBlues, greens, purples - calming and sophisticated
metallicMetallic and shimmer colors — gold, silver, bronze, copper
pastelSoft, muted colors with white undertones
vibrantBold, highly saturated colors

Batch Operations

Batch Re-extraction (Optional)

Colors are extracted automatically on upload. Use batch re-extraction only to re-run with different settings across multiple images.

python
# Force re-extraction with different color count
result = await client.colors.batch_extract(
image_ids,
force=True, # Re-extract even if colors exist
n_colors=6 # Use fewer colors per image
)
print(f"Queued {result.queued_count} images")
# Check status of individual images later
for image_id in image_ids:
status = await client.colors.get(image_id)
print(f"{image_id}: {status.status}")

Checking Extraction Status

Status Properties

Check the state of color extraction

python
result = await client.colors.get(image_id)
# Check status using properties
if result.is_completed:
print("Colors ready!")
print(f"Extracted at: {result.extracted_at}")
elif result.is_pending:
print("Still processing...")
else:
print(f"Status: {result.status}")
# Access status as enum
from scopix.types.colors import ColorExtractionStatus
status_enum = result.status_enum
if status_enum == ColorExtractionStatus.COMPLETED:
# Process colors
pass
elif status_enum == ColorExtractionStatus.FAILED:
# Handle failure
pass

Extraction Status Values

StatusMeaning
pendingExtraction not yet started
queuedQueued for processing
processingCurrently being processed
completedColors extracted successfully
failedExtraction failed

Type Reference

ColorExtractionResult

Returned by client.colors.get() and client.colors.extract()

python
@dataclass(frozen=True)
class ColorExtractionResult:
image_id: str
status: str # pending | queued | processing | completed | failed
color_analysis: Optional[ColorAnalysis]
extracted_at: Optional[datetime]
# Properties
@property
def status_enum(self) -> Optional[ColorExtractionStatus]
@property
def is_completed(self) -> bool
@property
def is_pending(self) -> bool

ColorAnalysis

Complete color analysis for an image

python
@dataclass(frozen=True)
class ColorAnalysis:
version: str # Analysis algorithm version
dominant_colors: list[DominantColor] # Ordered by percentage
analytics: ColorAnalytics # Overall analytics
extracted_at: Optional[datetime]

DominantColor

A single dominant color

python
@dataclass(frozen=True)
class DominantColor:
rank: int # 1 = most dominant
percentage: float # Coverage percentage
rgb: RGB # RGB values
hsl: HSL # HSL values
lab: LAB # LAB values (for Delta-E)
hex: str # Hex code (e.g., "#C4A87C")
name: str # Semantic name (e.g., "Walnut")
family: str # Color family
@property
def family_enum(self) -> Optional[ColorFamily]

Color Space Types

Color values in different color spaces

python
@dataclass(frozen=True)
class RGB:
r: int # 0-255
g: int # 0-255
b: int # 0-255
@dataclass(frozen=True)
class HSL:
h: float # Hue (0-360)
s: float # Saturation (0-100)
l: float # Lightness (0-100)
@dataclass(frozen=True)
class LAB:
l: float # Lightness (0-100)
a: float # Green-Red (-128 to 127)
b: float # Blue-Yellow (-128 to 127)

ColorAnalytics

Overall image color analytics

python
@dataclass(frozen=True)
class ColorAnalytics:
temperature: ColorTemperature # warm | cool | neutral
brightness: ColorBrightness # dark | medium | light
saturation: ColorSaturation # muted | medium | vivid
@dataclass(frozen=True)
class ColorTemperature:
value: str # "warm", "cool", or "neutral"
score: float # Confidence (0-1)
@dataclass(frozen=True)
class ColorBrightness:
average: float # Average brightness (0-100)
category: str # "dark", "medium", or "light"
@dataclass(frozen=True)
class ColorSaturation:
average: float # Average saturation (0-100)
category: str # "muted", "medium", or "vivid"

ColorSearchResponse

Returned by client.colors.search()

python
@dataclass(frozen=True)
class ColorSearchResponse:
results: list[ColorSearchResult]
total_count: int
limit: int
offset: int
@property
def has_more(self) -> bool # More results available
@dataclass(frozen=True)
class ColorSearchResult:
image_id: str
match_score: float # Lower = better match
thumbnail_url: Optional[str]
color_analysis: Optional[ColorAnalysis]

ColorFamilyInfo

Returned by client.colors.list_families()

python
@dataclass(frozen=True)
class ColorFamilyInfo:
name: str # Internal name (e.g., "earth_tone")
display_name: str # Display name (e.g., "Earth Tones")
description: str # Description
example_colors: list[str] # Example hex codes
@property
def family_enum(self) -> Optional[ColorFamily]

BatchColorExtractionResult

Returned by client.colors.batch_extract()

python
@dataclass(frozen=True)
class BatchColorExtractionResult:
queued_count: int # Number of images queued
message: str # Status message

Enums

python
class ColorFamily(str, Enum):
NEUTRAL = "neutral"
EARTH_TONE = "earth_tone"
WARM = "warm"
COOL = "cool"
METALLIC = "metallic"
PASTEL = "pastel"
VIBRANT = "vibrant"
class ColorExtractionStatus(str, Enum):
PENDING = "pending"
QUEUED = "queued"
PROCESSING = "processing"
COMPLETED = "completed"
FAILED = "failed"