HueEqualiser.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. import cv2
  2. import numpy
  3. import Tool
  4. class HueEqualiser(Tool.Tool):
  5. def on_init(self):
  6. self.id = "hueequaliser"
  7. self.name = "Hue Equaliser"
  8. self.icon_path = "ui/PF2_Icons/HueEqualiser.png"
  9. self.properties = [
  10. Tool.Property("header", "Hue Equaliser", "Header", None, has_toggle=False, has_button=False),
  11. Tool.Property("bleed", "Hue Bleed", "Slider", 0.5, max=2.0, min=0.01),
  12. Tool.Property("neighbour_bleed", "Neighbour Bleed", "Slider", 0.25, max=2.0, min=0.0),
  13. # Red
  14. Tool.Property("header_red", "Red", "Header", None, has_toggle=False, has_button=False),
  15. Tool.Property("red_value", "Value", "Slider", 0, max=50, min=-50),
  16. Tool.Property("red_saturation", "Saturation", "Slider", 0, max=50, min=-50),
  17. # Yellow
  18. Tool.Property("header_yellow", "Yellow", "Header", None, has_toggle=False, has_button=False),
  19. Tool.Property("yellow_value", "Value", "Slider", 0, max=50, min=-50),
  20. Tool.Property("yellow_saturation", "Saturation", "Slider", 0, max=50, min=-50),
  21. # Green
  22. Tool.Property("header_green", "Green", "Header", None, has_toggle=False, has_button=False),
  23. Tool.Property("green_value", "Value", "Slider", 0, max=50, min=-50),
  24. Tool.Property("green_saturation", "Saturation", "Slider", 0, max=50, min=-50),
  25. # Cyan
  26. Tool.Property("header_cyan", "Cyan", "Header", None, has_toggle=False, has_button=False),
  27. Tool.Property("cyan_value", "Value", "Slider", 0, max=50, min=-50),
  28. Tool.Property("cyan_saturation", "Saturation", "Slider", 0, max=50, min=-50),
  29. # Blue
  30. Tool.Property("header_blue", "Blue", "Header", None, has_toggle=False, has_button=False),
  31. Tool.Property("blue_value", "Value", "Slider", 0, max=50, min=-50),
  32. Tool.Property("blue_saturation", "Saturation", "Slider", 0, max=50, min=-50),
  33. # Violet
  34. Tool.Property("header_violet", "Violet", "Header", None, has_toggle=False, has_button=False),
  35. Tool.Property("violet_value", "Value", "Slider", 0, max=50, min=-50),
  36. Tool.Property("violet_saturation", "Saturation", "Slider", 0, max=50, min=-50),
  37. ]
  38. def on_update(self, image):
  39. hues = {
  40. "red": 0,
  41. "yellow": 60,
  42. "green": 120,
  43. "cyan": 180,
  44. "blue": 240,
  45. "violet": 300,
  46. "_red": 360,
  47. }
  48. out = image
  49. if(not self.is_default()):
  50. bleed = self.props["bleed"].get_value()
  51. neighbour_bleed = self.props["neighbour_bleed"].get_value()
  52. out = out.astype(numpy.float32)
  53. # Convert to HSV colorspace
  54. out = cv2.cvtColor(out, cv2.COLOR_BGR2HSV)
  55. # Bits per pixel
  56. bpp = float(str(image.dtype).replace("uint", "").replace("float", ""))
  57. # Pixel value range
  58. np = float(2 ** bpp - 1)
  59. imhue = out[0:, 0:, 0]
  60. imsat = out[0:, 0:, 1]
  61. imval = out[0:, 0:, 2]
  62. for hue in hues:
  63. hsat = self.props["%s_saturation" % hue.replace('_', '')].get_value()
  64. hval = self.props["%s_value" % hue.replace('_', '')].get_value()
  65. isHue = self._is_hue(imhue, hues[hue], (3.5/bleed))
  66. isHue = self._neighbour_bleed(isHue, neighbour_bleed)
  67. imsat = imsat + ((hsat / 10000) * 255) * isHue
  68. imval = imval + ((hval / 1000) * np) * isHue
  69. # Clip any values out of bounds
  70. imval[imval < 0.0] = 0.0
  71. imval[imval > np] = np
  72. imsat[imsat < 0.0] = 0.0
  73. imsat[imsat > 1.0] = 1.0
  74. out[0:, 0:, 1] = imsat
  75. out[0:, 0:, 2] = imval
  76. # Convert back to BGR colorspace
  77. out = cv2.cvtColor(out, cv2.COLOR_HSV2BGR)
  78. out = out.astype(image.dtype)
  79. return out
  80. def _is_hue(self, image, hue_value, bleed_value = 3.5):
  81. mif = hue_value - 30
  82. mir = hue_value + 30
  83. if (mir > 360):
  84. mir = 360
  85. if (mif < 0):
  86. mif = 0
  87. bleed = float(360 / bleed_value)
  88. icopy = image.copy()
  89. print(bleed, mif, mir)
  90. if(mif != 0):
  91. icopy[icopy < mif - bleed] = 0.0
  92. icopy[icopy > mir + bleed] = 0.0
  93. icopy[(icopy < mif) * (icopy != 0.0)] = (((mif - (icopy[(icopy < mif) * (icopy != 0.0)]))/360.0) / (bleed/360.0)) * -1 + 1
  94. icopy[(icopy > mir) * (icopy != 0.0)] = ((((icopy[(icopy > mir) * (icopy != 0.0)]) - mir)/360.0) / (bleed/360.0)) * -1 + 1
  95. icopy[(icopy >= mif) * (icopy <= mir)] = 1.0
  96. if(mif == 0):
  97. icopy[icopy > mir + bleed] = 0.0
  98. icopy[(icopy > mir) * (icopy != 0.0)] = ((((icopy[(icopy > mir) * (icopy != 0.0)]) - mir) / 360.0) / (bleed/360.0)) * -1 + 1
  99. return icopy
  100. def _neighbour_bleed(self, map, bleed):
  101. strength = bleed*30
  102. if (strength > 0):
  103. height, width = map.shape[:2]
  104. size = (height * width)
  105. mul = numpy.math.sqrt(size) / 1064.416 # numpy.math.sqrt(1132982.0)
  106. map = map*255
  107. blur_size = 2 * round((round(strength * mul) + 1) / 2) - 1
  108. im = cv2.blur(map, (int(blur_size), int(blur_size)))
  109. return im/255.0
  110. return map