Tonemap.py 2.6 KB

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