ingest.py 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. #!/usr/bin/env python3
  2. from collections import namedtuple
  3. import numpy as np
  4. from PIL import Image
  5. from colorspacious import cspace_convert
  6. def is_outline(r: int, g: int, b: int, a: int) -> bool:
  7. # returns true if a pixel is transparent or pure black
  8. return a == 0 or (r, g, b) == (0, 0, 0)
  9. def x_metric(pixels: np.array) -> float:
  10. # X metric - the mean squared Euclidean norm
  11. # computed as the sum of the squares of the components of the pixels,
  12. # normalized by the number of pixels
  13. return sum(sum(pixels ** 2)) / len(pixels)
  14. def y_metric(pixels: np.array) -> np.array:
  15. # Y metric - the mean pixel of the image
  16. return sum(pixels) / len(pixels)
  17. ImageInfo = namedtuple(
  18. "ImageInfo", ["name", "xrgb", "xjab", "yrgb", "yjab"]
  19. )
  20. def ingest_png(file_name: str) -> ImageInfo:
  21. print(f"Ingesting {file_name}")
  22. # image name - strip leading path and trailing extension
  23. name = file_name.rsplit("/", maxsplit=1)[1].split(".", maxsplit=1)[0]
  24. # read non-outline pixels of image
  25. rgb_pixels = np.array([
  26. (r, g, b)
  27. for r, g, b, a in Image.open(file_name).convert("RGBA").getdata()
  28. if not is_outline(r, g, b, a)
  29. ])
  30. # convert RGB pixels to CAM02 values
  31. jab_pixels = cspace_convert(rgb_pixels, "sRGB255", "CAM02-UCS")
  32. # compute and return metrics
  33. return ImageInfo(
  34. name=name,
  35. xrgb=x_metric(rgb_pixels),
  36. xjab=x_metric(jab_pixels),
  37. yrgb=y_metric(rgb_pixels),
  38. yjab=y_metric(jab_pixels),
  39. )
  40. if __name__ == "__main__":
  41. import csv
  42. import os
  43. import sys
  44. dir = "pngs" if len(sys.argv) < 2 else sys.argv[1]
  45. data = [
  46. ingest_png(dir + "/" + fn)
  47. for f in os.listdir(dir)
  48. if (fn := os.fsdecode(f)).endswith(".png")
  49. ]
  50. with open("database.csv", "w") as outfile:
  51. writer = csv.writer(outfile, delimiter=",", quotechar="'")
  52. writer.writerows([d.name, d.xrgb, *d.yrgb] for d in data)
  53. with open("database-cam02.csv", "w") as outfile:
  54. writer = csv.writer(outfile, delimiter=",", quotechar="'")
  55. writer.writerows([d.name, d.xjab, *d.yjab] for d in data)
  56. with open("database.js", "w") as outfile:
  57. outfile.write("const database = [\n")
  58. for info in data:
  59. fields = ", ".join(
  60. (
  61. f'name: "{info.name}"',
  62. f"xRGB: {info.xrgb}",
  63. f"xJAB: {info.xjab}",
  64. f"yRGB: [ {', '.join(str(c) for c in info.yrgb)} ]",
  65. f"yJAB: [ {', '.join(str(c) for c in info.yjab)} ]",
  66. )
  67. )
  68. outfile.write(f" {{ {fields} }},\n")
  69. outfile.write("];\n")