Tonemap.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import cv2
  2. import numpy
  3. import Tool
  4. class Tonemap(Tool.Tool):
  5. def on_init(self):
  6. self.id = "tonemap"
  7. self.name = "Tone Mapping"
  8. self.icon_path = "ui/PF2_Icons/Tonemap.png"
  9. self.properties = [
  10. Tool.Property("enabled", "Tone Mapping", "Header", False, has_toggle=True, has_button=False),
  11. Tool.Property("strength", "Strength", "Slider", 90, max=100, min=0),
  12. Tool.Property("bleed", "Sharpness", "Slider", 10, max=100, min=0),
  13. Tool.Property("contrast", "Contrast", "Slider", 25, max=100, min=0),
  14. Tool.Property("two_pass", "Two Pass", "Toggle", False)
  15. ]
  16. def on_update(self, image):
  17. if(self.props["enabled"].get_value()):
  18. blur = self.props["bleed"].get_value()
  19. first_opacity = (self.props["contrast"].get_value() * -1) + 100
  20. second_opacity = self.props["strength"].get_value()
  21. two_pass = self.props["two_pass"].get_value()
  22. im = image
  23. iterations = 1
  24. if(two_pass):
  25. iterations = 2
  26. for i in range(iterations):
  27. # Convert to Grayscale
  28. gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
  29. # Invert Grayscale Image
  30. inverted = cv2.UMat(self._invert(gray))
  31. # Blur
  32. if(blur > 0):
  33. height, width = image.shape[:2]
  34. size = (height * width)
  35. mul = numpy.math.sqrt(size) / 1064.416 # numpy.math.sqrt(1132982.0)
  36. blur_size = abs(2 * round((round((blur/10.0) * mul) + 1) / 2) - 1)
  37. print(height, width, mul, blur_size)
  38. blurred = cv2.GaussianBlur(inverted, (int(blur_size), int(blur_size)), 0)
  39. else:
  40. # Or, don't blur
  41. blurred = inverted
  42. # First round of Blending
  43. colour = cv2.cvtColor(blurred, cv2.COLOR_GRAY2BGR)
  44. colouredMap = cv2.addWeighted(colour, (first_opacity / 100), im, 1 - (first_opacity / 100), 0).get()
  45. # Overlay
  46. bpp = int(str(im.dtype).replace("uint", "").replace("float", ""))
  47. blended = self._overlay(colouredMap, im, float((2 ** bpp) - 1), im.dtype)
  48. # Second round of Blending
  49. im = cv2.addWeighted(blended, (second_opacity / 100), im, 1 - (second_opacity / 100), 0)
  50. return im
  51. else:
  52. return image
  53. def _invert(self, image):
  54. return image.max() - image
  55. def _overlay(self, B, A, bpp, utype):
  56. a = A / bpp
  57. b = B / bpp
  58. merged = (1 - 2 * b) * a ** 2 + 2 * a * b
  59. return (merged * bpp).astype(utype)