ingest.py 2.9 KB

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