from functools import partial
from colour.algebra import spow
from colour.models import Iab_to_XYZ, XYZ_to_Iab
# Define the matrices and functions for OKLAB conversion
MATRIX_1_XYZ_TO_LMS = np.array([
[0.8189330101, 0.3618667424, -0.1288597137],
[0.0329845436, 0.9293118715, 0.0361456387],
[0.0482003018, 0.2643662691, 0.6338517070]
MATRIX_2_LMS_TO_LAB = np.array([
[0.2104542553, 0.7936177850, -0.0040720468],
[1.9779984951, -2.4285922050, 0.4505937099],
[0.0259040371, 0.7827717662, -0.8086757660]
rgb[mask] = ((rgb[mask] + 0.055) / 1.055) ** 2.4
transform_matrix = np.array([
[0.4124564, 0.3575761, 0.1804375],
[0.2126729, 0.7151522, 0.0721750],
[0.0193339, 0.1191920, 0.9503041]
return np.dot(rgb, transform_matrix.T)
# Convert an entire image from RGB to OKLAB
def image_to_oklab(image):
oklab_image = np.zeros((h, w, 3))
xyz = rgb_to_xyz(image[i, j])
oklab_image[i, j] = XYZ_to_Oklab(xyz)
def __init__(self, x, y, w, h, color):
QuadTreeNode(self.x, self.y, hw, hh, self.color),
QuadTreeNode(self.x + hw, self.y, hw, hh, self.color),
QuadTreeNode(self.x, self.y + hh, hw, hh, self.color),
QuadTreeNode(self.x + hw, self.y + hh, hw, hh, self.color),
def __init__(self, image, threshold=0.1, max_depth=10):
self.threshold = threshold
self.max_depth = max_depth
self.root = self.build_tree(0, 0, image.shape[1], image.shape[0], 0)
def build_tree(self, x, y, w, h, depth):
if depth >= self.max_depth:
return QuadTreeNode(x, y, w, h, self.average_color(x, y, w, h))
avg_color = self.average_color(x, y, w, h)
if self.color_variation(x, y, w, h) < self.threshold:
return QuadTreeNode(x, y, w, h, avg_color)
node = QuadTreeNode(x, y, w, h, avg_color)
self.build_tree(node.children[0].x, node.children[0].y, node.children[0].w, node.children[0].h, depth + 1),
self.build_tree(node.children[1].x, node.children[1].y, node.children[1].w, node.children[1].h, depth + 1),
self.build_tree(node.children[2].x, node.children[2].y, node.children[2].w, node.children[2].h, depth + 1),
self.build_tree(node.children[3].x, node.children[3].y, node.children[3].w, node.children[3].h, depth + 1),
def average_color(self, x, y, w, h):
region = self.image[y:y+h, x:x+w]
avg_color = np.mean(region, axis=(0, 1))
def color_variation(self, x, y, w, h):
region = self.image[y:y+h, x:x+w]
variation = np.std(region, axis=(0, 1))
return np.mean(variation)
def print_tree(self, node, depth=0):
print(' ' * depth * 2, f'Quad: x={node.x}, y={node.y}, w={node.w}, h={node.h}, color={node.color}')
for child in node.children:
self.print_tree(child, depth + 1)
if __name__ == "__main__":
image_path = os.path.join(os.path.expanduser("~"), "Desktop", "your_image.jpg")
image = Image.open(image_path).convert('RGB') # Convert to RGB to remove alpha channel
oklab_image = image_to_oklab(image)
quadtree = QuadTree(oklab_image, threshold=0.05, max_depth=5)
quadtree.print_tree(quadtree.root)