123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778 |
- #!/usr/bin/env python3
- import csv
- import math
- import random
- from argparse import ArgumentParser
- def norm(r, g, b):
- return math.sqrt(r * r + g * g + b * b)
- parser = ArgumentParser()
- parser.add_argument(
- "color", nargs="?", default=None, help="Target color, randomized if not provided"
- )
- parser.add_argument(
- "-n", "--number", default=1, type=int, help="Number of Pokemon to find"
- )
- parser.add_argument(
- "-c", "--closeness", default=2, type=int, help="Closeness coefficient"
- )
- parser.add_argument("-d", "--database", default="database.csv", help="Database file")
- parser.add_argument("-x", "--exclude-x", action="store_true", help="Exclude X")
- parser.add_argument("-z", "--normalize", action="store_true", help="Normalize q and Y")
- parser.add_argument(
- "-j",
- "--convert-cam02",
- action="store_true",
- help="Convert input color to CIECAM02-UCS before calculation",
- )
- parser.add_argument("-v", "--verbose", action="store_true", help="Print raw scores")
- args = parser.parse_args()
- if args.number <= 0:
- raise ValueError("Must request a number greater than 0")
- if args.color is not None:
- cleaned_color = args.color.strip("#")
- if len(cleaned_color) != 6:
- raise ValueError("Color must be a 6 digit hex")
- color = (
- int(cleaned_color[0:2], base=16),
- int(cleaned_color[2:4], base=16),
- int(cleaned_color[4:6], base=16),
- )
- else:
- color = tuple(int(random.random() * 255) for _ in range(3))
- print(f"Generated random color: #{''.join(hex(c)[2:] for c in color)} / {color}")
- if args.convert_cam02:
- from colorspacious import cspace_convert
- color = list(cspace_convert(color, "sRGB255", "CAM02-UCS"))
- yfactor = args.closeness
- if args.normalize:
- yfactor /= norm(*color)
- results = []
- with open(args.database) as infile:
- for name, x, *y in csv.reader(infile, delimiter=",", quotechar="'"):
- xval = 0 if args.exclude_x else float(x)
- yvec = [float(y_c) for y_c in y]
- yval = sum(y_c * c for y_c, c in zip(yvec, color))
- if args.normalize:
- yval /= norm(*yvec)
- score = xval - yfactor * yval
- results.append((score, name))
- if args.number > 1:
- for i, (score, name) in enumerate(sorted(results)[:args.number]):
- print(f"{i+1}:\t{name}")
- if args.verbose:
- print(f"\t\t\t{score=}")
- else:
- best_score, best_name = min(results)
- print(f"Best match: {best_name}")
- if args.verbose:
- print(f"{best_score=}")
|