Merge pull request #769 from roboflow/feature/color_and_color_palette_updates

`feature/color_and_color_palette_updates`
This commit is contained in:
Piotr Skalski authored and GitHub committed 2024-01-23 17:21:15 +01:00
commit 4fedb87f97
4 files changed
+246 -75

No files matched your search

+14 -14
View File
@@ -21,7 +21,7 @@ class BoundingBoxAnnotator(BaseAnnotator):
def __init__(
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
color: Union[Color, ColorPalette] = ColorPalette.DEFAULT,
thickness: int = 2,
color_lookup: ColorLookup = ColorLookup.CLASS,
):
@@ -103,7 +103,7 @@ class MaskAnnotator(BaseAnnotator):
def __init__(
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
color: Union[Color, ColorPalette] = ColorPalette.DEFAULT,
opacity: float = 0.5,
color_lookup: ColorLookup = ColorLookup.CLASS,
):
@@ -186,7 +186,7 @@ class PolygonAnnotator(BaseAnnotator):
def __init__(
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
color: Union[Color, ColorPalette] = ColorPalette.DEFAULT,
thickness: int = 2,
color_lookup: ColorLookup = ColorLookup.CLASS,
):
@@ -268,7 +268,7 @@ class ColorAnnotator(BaseAnnotator):
def __init__(
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
color: Union[Color, ColorPalette] = ColorPalette.DEFAULT,
opacity: float = 0.5,
color_lookup: ColorLookup = ColorLookup.CLASS,
):
@@ -354,7 +354,7 @@ class HaloAnnotator(BaseAnnotator):
def __init__(
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
color: Union[Color, ColorPalette] = ColorPalette.DEFAULT,
opacity: float = 0.8,
kernel_size: int = 40,
color_lookup: ColorLookup = ColorLookup.CLASS,
@@ -446,7 +446,7 @@ class EllipseAnnotator(BaseAnnotator):
def __init__(
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
color: Union[Color, ColorPalette] = ColorPalette.DEFAULT,
thickness: int = 2,
start_angle: int = -45,
end_angle: int = 235,
@@ -536,7 +536,7 @@ class BoxCornerAnnotator(BaseAnnotator):
def __init__(
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
color: Union[Color, ColorPalette] = ColorPalette.DEFAULT,
thickness: int = 4,
corner_length: int = 15,
color_lookup: ColorLookup = ColorLookup.CLASS,
@@ -622,7 +622,7 @@ class CircleAnnotator(BaseAnnotator):
def __init__(
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
color: Union[Color, ColorPalette] = ColorPalette.DEFAULT,
thickness: int = 2,
color_lookup: ColorLookup = ColorLookup.CLASS,
):
@@ -706,7 +706,7 @@ class DotAnnotator(BaseAnnotator):
def __init__(
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
color: Union[Color, ColorPalette] = ColorPalette.DEFAULT,
radius: int = 4,
position: Position = Position.CENTER,
color_lookup: ColorLookup = ColorLookup.CLASS,
@@ -782,7 +782,7 @@ class LabelAnnotator:
def __init__(
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
color: Union[Color, ColorPalette] = ColorPalette.DEFAULT,
text_color: Color = Color.BLACK,
text_scale: float = 0.5,
text_thickness: int = 1,
@@ -1027,7 +1027,7 @@ class TraceAnnotator:
def __init__(
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
color: Union[Color, ColorPalette] = ColorPalette.DEFAULT,
position: Position = Position.CENTER,
trace_length: int = 30,
thickness: int = 2,
@@ -1288,7 +1288,7 @@ class TriangleAnnotator(BaseAnnotator):
def __init__(
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
color: Union[Color, ColorPalette] = ColorPalette.DEFAULT,
base: int = 10,
height: int = 10,
position: Position = Position.TOP_CENTER,
@@ -1378,7 +1378,7 @@ class RoundBoxAnnotator(BaseAnnotator):
def __init__(
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
color: Union[Color, ColorPalette] = ColorPalette.DEFAULT,
thickness: int = 2,
color_lookup: ColorLookup = ColorLookup.CLASS,
roundness: float = 0.6,
@@ -1507,7 +1507,7 @@ class PercentageBarAnnotator(BaseAnnotator):
self,
height: int = 16,
width: int = 80,
color: Union[Color, ColorPalette] = ColorPalette.default(),
color: Union[Color, ColorPalette] = ColorPalette.DEFAULT,
border_color: Color = Color.black(),
position: Position = Position.TOP_CENTER,
color_lookup: ColorLookup = ColorLookup.CLASS,
+1 -1
View File
@@ -26,7 +26,7 @@ class BoxAnnotator:
def __init__(
self,
color: Union[Color, ColorPalette] = ColorPalette.default(),
color: Union[Color, ColorPalette] = ColorPalette.DEFAULT,
thickness: int = 2,
text_color: Color = Color.BLACK,
text_scale: float = 0.5,
+205 -60
View File
@@ -3,28 +3,56 @@ from __future__ import annotations
from dataclasses import dataclass
from typing import List, Tuple
from supervision.utils.internal import deprecated
import matplotlib.pyplot as plt
from supervision.utils.internal import classproperty, deprecated
DEFAULT_COLOR_PALETTE = [
"#a351fb",
"#e6194b",
"#3cb44b",
"#ffe119",
"#0082c8",
"#f58231",
"#911eb4",
"#46f0f0",
"#f032e6",
"#d2f53c",
"#fabebe",
"#008080",
"#e6beff",
"#aa6e28",
"#fffac8",
"#800000",
"#aaffc3",
"A351FB",
"FF4040",
"FFA1A0",
"FF7633",
"FFB633",
"D1D435",
"4CFB12",
"94CF1A",
"40DE8A",
"1B9640",
"00D6C1",
"2E9CAA",
"00C4FF",
"364797",
"6675FF",
"0019EF",
"863AFF",
"530087",
"CD3AFF",
"FF97CA",
"FF39C9",
]
LEGACY_COLOR_PALETTE = [
"#A351FB",
"#E6194B",
"#3CB44B",
"#FFE119",
"#0082C8",
"#F58231",
"#911EB4",
"#46F0F0",
"#F032E6",
"#D2F53C",
"#FABEBE",
"#008080",
"#E6BEFF",
"#AA6E28",
"#FFFAC8",
"#800000",
"#AAFFC3",
]
ROBOFLOW_COLOR_PALETTE = ["C28DFC", "A351FB", "8315F9", "6706CE", "5905B3", "4D049A"]
def _validate_color_hex(color_hex: str):
color_hex = color_hex.lstrip("#")
@@ -39,10 +67,31 @@ class Color:
"""
Represents a color in RGB format.
This class provides methods to work with colors, including creating colors from hex
codes, converting colors to hex strings, RGB tuples, and BGR tuples.
Attributes:
r (int): Red channel.
g (int): Green channel.
b (int): Blue channel.
r (int): Red channel value (0-255).
g (int): Green channel value (0-255).
b (int): Blue channel value (0-255).
Example:
```python
import supervision as sv
sv.Color.WHITE
# Color(r=255, g=255, b=255)
```
| Constant | Hex Code | RGB |
|------------|------------|------------------|
| `WHITE` | `#FFFFFF` | `(255, 255, 255)`|
| `BLACK` | `#000000` | `(0, 0, 0)` |
| `RED` | `#FF0000` | `(255, 0, 0)` |
| `GREEN` | `#00FF00` | `(0, 255, 0)` |
| `BLUE` | `#0000FF` | `(0, 0, 255)` |
| `YELLOW` | `#FFFF00` | `(255, 255, 0)` |
| `ROBOFLOW` | `#A351FB` | `(163, 81, 251)` |
"""
r: int
@@ -61,9 +110,11 @@ class Color:
Color: Instance representing the color.
Example:
```
>>> Color.from_hex('#ff00ff')
Color(r=255, g=0, b=255)
```python
import supervision as sv
sv.Color.from_hex('#ff00ff')
# Color(r=255, g=0, b=255)
```
"""
_validate_color_hex(color_hex)
@@ -81,9 +132,11 @@ class Color:
str: The hexadecimal color string.
Example:
```
>>> Color(r=255, g=0, b=255).as_hex()
'#ff00ff'
```python
import supervision as sv
sv.Color(r=255, g=255, b=0).as_hex()
# '#ffff00'
```
"""
return f"#{self.r:02x}{self.g:02x}{self.b:02x}"
@@ -96,9 +149,11 @@ class Color:
Tuple[int, int, int]: RGB tuple.
Example:
```
>>> color.as_rgb()
(255, 0, 255)
```python
import supervision as sv
sv.Color(r=255, g=255, b=0).as_rgb()
# (255, 255, 0)
```
"""
return self.r, self.g, self.b
@@ -111,32 +166,42 @@ class Color:
Tuple[int, int, int]: BGR tuple.
Example:
```
>>> color.as_bgr()
(255, 0, 255)
```python
import supervision as sv
sv.Color(r=255, g=255, b=0).as_bgr()
# (0, 255, 255)
```
"""
return self.b, self.g, self.r
@property
@classproperty
def WHITE(cls):
return cls.from_hex("#ffffff")
return Color.from_hex("#FFFFFF")
@property
@classproperty
def BLACK(cls):
return cls.from_hex("#000000")
return Color.from_hex("#000000")
@property
@classproperty
def RED(cls):
return cls.from_hex("#ff0000")
return Color.from_hex("#FF0000")
@property
@classproperty
def GREEN(cls):
return cls.from_hex("#00ff00")
return Color.from_hex("#00FF00")
@property
@classproperty
def BLUE(cls):
return cls.from_hex("#0000ff")
return Color.from_hex("#0000FF")
@classproperty
def YELLOW(cls):
return Color.from_hex("#FFFF00")
@classproperty
def ROBOFLOW(cls):
return Color.from_hex("#A351FB")
@classmethod
@deprecated(
@@ -183,7 +248,57 @@ class Color:
class ColorPalette:
colors: List[Color]
@classproperty
def DEFAULT(cls) -> ColorPalette:
"""
Returns a default color palette.
Returns:
ColorPalette: A ColorPalette instance with default colors.
Example:
```python
import supervision as sv
sv.ColorPalette.DEFAULT
# ColorPalette(colors=[Color(r=255, g=64, b=64), Color(r=255, g=161, b=160), ...])
```
![default-color-palette](https://media.roboflow.com/
supervision-annotator-examples/default-color-palette.png)
""" # noqa: E501 // docs
return ColorPalette.from_hex(color_hex_list=DEFAULT_COLOR_PALETTE)
@classproperty
def ROBOFLOW(cls) -> ColorPalette:
"""
Returns a Roboflow color palette.
Returns:
ColorPalette: A ColorPalette instance with Roboflow colors.
Example:
```python
import supervision as sv
sv.ColorPalette.ROBOFLOW
# ColorPalette(colors=[Color(r=194, g=141, b=252), Color(r=163, g=81, b=251), ...])
```
![roboflow-color-palette](https://media.roboflow.com/
supervision-annotator-examples/roboflow-color-palette.png)
""" # noqa: E501 // docs
return ColorPalette.from_hex(color_hex_list=ROBOFLOW_COLOR_PALETTE)
@classproperty
def LEGACY(cls) -> ColorPalette:
return ColorPalette.from_hex(color_hex_list=LEGACY_COLOR_PALETTE)
@classmethod
@deprecated(
"`ColorPalette.default()` is deprecated and will be removed in "
"`supervision-0.20.0`. Use `Color.DEFAULT` instead."
)
def default(cls) -> ColorPalette:
"""
Returns a default color palette.
@@ -192,11 +307,13 @@ class ColorPalette:
ColorPalette: A ColorPalette instance with default colors.
Example:
```python
import supervision as sv
sv.ColorPalette.default()
# ColorPalette(colors=[Color(r=255, g=64, b=64), Color(r=255, g=161, b=160), ...])
```
>>> ColorPalette.default()
ColorPalette(colors=[Color(r=255, g=0, b=0), Color(r=0, g=255, b=0), ...])
```
"""
""" # noqa: E501 // docs
return ColorPalette.from_hex(color_hex_list=DEFAULT_COLOR_PALETTE)
@classmethod
@@ -211,14 +328,46 @@ class ColorPalette:
ColorPalette: A ColorPalette instance.
Example:
```
>>> ColorPalette.from_hex(['#ff0000', '#00ff00', '#0000ff'])
ColorPalette(colors=[Color(r=255, g=0, b=0), Color(r=0, g=255, b=0), ...])
```python
import supervision as sv
sv.ColorPalette.from_hex(['#ff0000', '#00ff00', '#0000ff'])
# ColorPalette(colors=[Color(r=255, g=0, b=0), Color(r=0, g=255, b=0), ...])
```
"""
colors = [Color.from_hex(color_hex) for color_hex in color_hex_list]
return cls(colors)
@classmethod
def from_matplotlib(cls, palette_name: str, color_count: int) -> ColorPalette:
"""
Create a ColorPalette instance from a Matplotlib color palette.
Args:
palette_name (str): Name of the Matplotlib palette.
color_count (int): Number of colors to sample from the palette.
Returns:
ColorPalette: A ColorPalette instance.
Example:
```python
import supervision as sv
sv.ColorPalette.from_matplotlib('viridis', 5)
# ColorPalette(colors=[Color(r=68, g=1, b=84), Color(r=59, g=82, b=139), ...])
```
![visualized_color_palette](https://media.roboflow.com/
supervision-annotator-examples/visualized_color_palette.png)
""" # noqa: E501 // docs
mpl_palette = plt.get_cmap(palette_name, color_count)
colors = [
Color(int(r * 255), int(g * 255), int(b * 255))
for r, g, b, _ in mpl_palette.colors
]
return cls(colors)
def by_idx(self, idx: int) -> Color:
"""
Return the color at a given index in the palette.
@@ -230,19 +379,15 @@ class ColorPalette:
Color: Color at the given index.
Example:
```
>>> color_palette.by_idx(1)
Color(r=0, g=255, b=0)
```python
import supervision as sv
color_palette = sv.ColorPalette.from_hex(['#ff0000', '#00ff00', '#0000ff'])
color_palette.by_idx(1)
# Color(r=0, g=255, b=0)
```
"""
if idx < 0:
raise ValueError("idx argument should not be negative")
idx = idx % len(self.colors)
return self.colors[idx]
Color.WHITE = Color.from_hex("#ffffff")
Color.BLACK = Color.from_hex("#000000")
Color.RED = Color.from_hex("#ff0000")
Color.GREEN = Color.from_hex("#00ff00")
Color.BLUE = Color.from_hex("#0000ff")
+26
View File
@@ -16,3 +16,29 @@ def deprecated(reason: str):
return wrapper
return decorator
class classproperty(property):
"""
A decorator that combines @classmethod and @property.
It allows a method to be accessed as a property of the class,
rather than an instance, similar to a classmethod.
Usage:
@classproperty
def my_method(cls):
...
"""
def __get__(self, owner_self: object, owner_cls: type) -> object:
"""
Override the __get__ method to return the result of the function call.
Args:
owner_self: The instance through which the attribute was accessed, or None.
owner_cls: The class through which the attribute was accessed.
Returns:
The result of calling the function stored in 'fget' with 'owner_cls'.
"""
return self.fget(owner_cls)