Dieses Projekt dient der digitalen Umwandlung von Bildern in simulierte Darstellung aus Sicht eines rot-grün-blinden Menschen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Dyschromasie-Applikation.py 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. from PIL import Image, ImageTk
  2. import PIL
  3. import tkinter as tk
  4. from tkinter import filedialog, messagebox
  5. import cv2
  6. import numpy as np
  7. class Dyschromasie:
  8. global simGrad
  9. cb_image = np.array([]).astype('float64')
  10. sim_image = np.array([]).astype('uint8')
  11. def __init__(self, img_mat=np.array([]), rows=0, cols=0, kanaele=0):
  12. self.rows = rows
  13. self.cols = cols
  14. self.kanaele = kanaele
  15. self.img_mat = img_mat
  16. T = np.array([[0.31399022, 0.63951294, 0.04649755],
  17. [0.15537241, 0.75789446, 0.08670142],
  18. [0.01775239, 0.10944209, 0.87256922]])
  19. T_reversed = np.array([[5.47221206, -4.6419601, 0.16963708],
  20. [-1.1252419, 2.29317094, -0.1678952],
  21. [0.02980165, -0.19318073, 1.16364789]])
  22. def gammaCorrection(self, v):
  23. if v <= 0.04045 * 255:
  24. return float(((v / 255) / 12.92))
  25. elif v > 0.04045 * 255:
  26. return float((((v / 255) + 0.055) / 1.055) ** 2.4)
  27. def reverseGammaCorrection(self, v_reverse):
  28. if v_reverse <= 0.0031308:
  29. return int(255 * (12.92 * v_reverse))
  30. elif v_reverse > 0.0031308:
  31. return int(255 * (1.055 * v_reverse ** 0.41666 - 0.055))
  32. class Protanopie(Dyschromasie):
  33. sim_mat = np.array([[0, 1.05118294, -0.05116099],
  34. [0, 1, 0],
  35. [0, 0, 1]])
  36. def Simulate(self):
  37. # Gammakorrektur durchfuehren
  38. self.cb_image = np.copy(self.img_mat).astype('float64')
  39. for i in range(self.rows):
  40. for j in range(self.cols):
  41. for x in range(3):
  42. self.cb_image[i, j, x] = self.gammaCorrection(self.img_mat[i, j, x])
  43. # Einzelne Pixelwertberechnung
  44. for i in range(self.rows):
  45. for j in range(self.cols):
  46. self.cb_image[i, j] = np.flipud(
  47. self.T_reversed.dot(self.sim_mat).dot(self.T).dot(np.flipud(self.cb_image[i, j])))
  48. self.sim_image = np.copy(self.cb_image)
  49. self.sim_image = self.sim_image.astype('uint8')
  50. # Rücktransformation der Gammawerte
  51. for i in range(self.rows):
  52. for j in range(self.cols):
  53. for x in range(3):
  54. self.sim_image[i, j, x] = self.reverseGammaCorrection(self.cb_image[i, j, x])
  55. # Anpassung fuer den Slider
  56. if(simGrad.get() != 0):
  57. for i in range(rows):
  58. for j in range(cols):
  59. for x in range(3):
  60. if self.sim_image[i, j, x] > img[i, j, x]:
  61. self.sim_image[i, j, x] = img[i, j, x] + abs(self.sim_image[i, j, x] - img[i, j, x])* (simGrad.get()/100)
  62. elif self.sim_image[i, j, x] < img[i, j, x]:
  63. self.sim_image[i, j, x] = self.sim_image[i, j, x] + abs(img[i, j, x] - self.sim_image[i, j, x])* (simGrad.get()/100)
  64. return self.sim_image
  65. class Deuteranopie(Dyschromasie):
  66. sim_mat = np.array([[1, 0, 0],
  67. [0.9513092, 0, 0.04866992],
  68. [0, 0, 1]])
  69. def Simulate(self):
  70. # Gammakorrektur durchfuehren
  71. self.cb_image = np.copy(self.img_mat).astype('float64')
  72. for i in range(self.rows):
  73. for j in range(self.cols):
  74. for x in range(3):
  75. self.cb_image[i, j, x] = self.gammaCorrection(self.img_mat[i, j, x])
  76. # Einzelne Pixelwertberechnung
  77. for i in range(self.rows):
  78. for j in range(self.cols):
  79. self.cb_image[i, j] = np.flipud(
  80. self.T_reversed.dot(self.sim_mat).dot(self.T).dot(np.flipud(self.cb_image[i, j])))
  81. self.sim_image = np.copy(self.cb_image)
  82. self.sim_image = self.sim_image.astype('uint8')
  83. # Rücktransformation der Gammawerte
  84. for i in range(self.rows):
  85. for j in range(self.cols):
  86. for x in range(3):
  87. self.sim_image[i, j, x] = self.reverseGammaCorrection(self.cb_image[i, j, x])
  88. # Anpassung fuer den Slider
  89. if (simGrad.get() != 0):
  90. for i in range(rows):
  91. for j in range(cols):
  92. for x in range(3):
  93. if self.sim_image[i, j, x] > img[i, j, x]:
  94. self.sim_image[i, j, x] = img[i, j, x] + abs(self.sim_image[i, j, x] - img[i, j, x]) * (simGrad.get() / 100)
  95. elif self.sim_image[i, j, x] < img[i, j, x]:
  96. self.sim_image[i, j, x] = self.sim_image[i, j, x] + abs(img[i, j, x] - self.sim_image[i, j, x]) * (simGrad.get() / 100)
  97. return self.sim_image
  98. class Tritanopie(Dyschromasie):
  99. sim_mat = np.array([[1, 0, 0],
  100. [0, 1, 0],
  101. [-0.86744736, 1.86727089, 0]])
  102. def Simulate(self):
  103. # Gammakorrektur durchfuehren
  104. self.cb_image = np.copy(self.img_mat).astype('float64')
  105. for i in range(self.rows):
  106. for j in range(self.cols):
  107. for x in range(3):
  108. self.cb_image[i, j, x] = self.gammaCorrection(self.img_mat[i, j, x])
  109. # Einzelne Pixelwertberechnung
  110. for i in range(self.rows):
  111. for j in range(self.cols):
  112. self.cb_image[i, j] = np.flipud(
  113. self.T_reversed.dot(self.sim_mat).dot(self.T).dot(np.flipud(self.cb_image[i, j])))
  114. self.sim_image = np.copy(self.cb_image)
  115. self.sim_image = self.sim_image.astype('uint8')
  116. # Rücktransformation der Gammawerte
  117. for i in range(self.rows):
  118. for j in range(self.cols):
  119. for x in range(3):
  120. self.sim_image[i, j, x] = self.reverseGammaCorrection(self.cb_image[i, j, x])
  121. # Anpassung fuer den Slider
  122. if (simGrad.get() != 0):
  123. for i in range(rows):
  124. for j in range(cols):
  125. for x in range(3):
  126. if self.sim_image[i, j, x] > img[i, j, x]:
  127. self.sim_image[i, j, x] = img[i, j, x] + abs(self.sim_image[i, j, x] - img[i, j, x]) * (simGrad.get() / 100)
  128. elif self.sim_image[i, j, x] < img[i, j, x]:
  129. self.sim_image[i, j, x] = self.sim_image[i, j, x] + abs(img[i, j, x] - self.sim_image[i, j, x]) * (simGrad.get() / 100)
  130. return self.sim_image
  131. class AutoScrollbar(tk.Scrollbar):
  132. # A scrollbar that hides itself if it's not needed.
  133. # Only works if you use the grid geometry manager!
  134. def set(self, lo, hi):
  135. if float(lo) <= 0.0 and float(hi) >= 1.0:
  136. # grid_remove is currently missing from Tkinter!
  137. self.tk.call("grid", "remove", self)
  138. else:
  139. self.grid()
  140. tk.Scrollbar.set(self, lo, hi)
  141. def pack(self, **kw):
  142. raise TclError("cannot use pack with this widget")
  143. def place(self, **kw):
  144. raise TclError("cannot use place with this widget")
  145. class ScrollFrame:
  146. def __init__(self, master):
  147. self.vscrollbar = AutoScrollbar(master)
  148. self.vscrollbar.grid(row=0, column=1, sticky='ns')
  149. self.hscrollbar = AutoScrollbar(master, orient='horizontal')
  150. self.hscrollbar.grid(row=1, column=0, sticky='ew')
  151. self.canvas = tk.Canvas(master, yscrollcommand=self.vscrollbar.set,
  152. xscrollcommand=self.hscrollbar.set)
  153. self.canvas.grid(row=0, column=0, sticky='nsew')
  154. self.vscrollbar.config(command=self.canvas.yview)
  155. self.hscrollbar.config(command=self.canvas.xview)
  156. # make the canvas expandable
  157. master.grid_rowconfigure(0, weight=1)
  158. master.grid_columnconfigure(0, weight=1)
  159. # create frame inside canvas
  160. self.frame = tk.Frame(self.canvas)
  161. self.frame.rowconfigure(1, weight=1)
  162. self.frame.columnconfigure(1, weight=1)
  163. # update the frame
  164. self.frame.bind("<Configure>", self.reset_scrollregion)
  165. def reset_scrollregion(self, event):
  166. self.canvas.configure(scrollregion=self.canvas.bbox('all'))
  167. def update(self):
  168. self.canvas.create_window(0, 0, anchor='nw', window=self.frame)
  169. self.frame.update_idletasks()
  170. self.canvas.config(scrollregion=self.canvas.bbox("all"))
  171. if self.frame.winfo_reqwidth() != self.canvas.winfo_width():
  172. # update the canvas's width to fit the inner frame
  173. self.canvas.config(width = self.frame.winfo_reqwidth())
  174. if self.frame.winfo_reqheight() != self.canvas.winfo_height():
  175. # update the canvas's width to fit the inner frame
  176. self.canvas.config(height = self.frame.winfo_reqheight())
  177. root = tk.Tk()
  178. root.title("Projekt Dyschromasie")
  179. SB = ScrollFrame(root)
  180. img = np.array([])
  181. rows = 0
  182. cols = 0
  183. kanaele = 0
  184. sim_pro = tk.IntVar(root)
  185. sim_deut = tk.IntVar(root)
  186. sim_tri = tk.IntVar(root)
  187. simGrad = tk.IntVar(root)
  188. simulationsGradient = tk.Scale(SB.frame, from_=0, to_=100, variable=simGrad, orient='horizontal')
  189. simulationsGradient.grid(column= 0, row = 1, columnspan=10)
  190. def browse():
  191. # Auswahl des FilePaths
  192. try:
  193. path = tk.filedialog.askopenfilename(filetypes=[("Image File", '.jpg')])
  194. im = Image.open(path)
  195. except:
  196. tk.messagebox.showerror(title='Datenfehler', message='Kein Bild gefunden/ausgewählt')
  197. global simulateButton
  198. if len(path) > 0:
  199. simulateButton.config(state='active')
  200. # Anzeigen des Bildes
  201. tkimage = ImageTk.PhotoImage(im)
  202. myvar = tk.Label(SB.frame, image=tkimage)
  203. myvar.image = tkimage
  204. myvar.grid(columnspan=5)
  205. # Einspeichern der Path-Informationen
  206. global img, rows, cols, kanaele
  207. img = cv2.imread(path)
  208. rows, cols, kanaele = img.shape
  209. def simulate():
  210. global img, rows, cols, kanaele, sim_pro, sim_deut, sim_tri
  211. if sim_deut.get():
  212. d = Deuteranopie(img, rows, cols, kanaele)
  213. display_array_deut = cv2.cvtColor(np.copy(d.Simulate()), cv2.COLOR_BGR2RGB)
  214. T = tk.Text(SB.frame, height=1, width=15)
  215. T.grid(columnspan=5)
  216. T.insert('current', "Deutranopie:")
  217. conv_SimulationPic_deut = ImageTk.PhotoImage(image=PIL.Image.fromarray(display_array_deut))
  218. sim_pic_deut = tk.Label(SB.frame, image=conv_SimulationPic_deut)
  219. sim_pic_deut.Image = conv_SimulationPic_deut
  220. sim_pic_deut.grid(columnspan=5)
  221. elif sim_tri.get():
  222. t = Tritanopie(img, rows, cols, kanaele)
  223. display_array_tri = cv2.cvtColor(np.copy(t.Simulate()), cv2.COLOR_BGR2RGB)
  224. T = tk.Text(SB.frame, height=1, width=15)
  225. T.grid(columnspan=5)
  226. T.insert('current', "Tritanopie:")
  227. conv_SimulationPic_tri = ImageTk.PhotoImage(image=PIL.Image.fromarray(display_array_tri))
  228. sim_pic_tri = tk.Label(SB.frame, image=conv_SimulationPic_tri)
  229. sim_pic_tri.Image = conv_SimulationPic_tri
  230. sim_pic_tri.grid(columnspan=5)
  231. elif sim_pro.get():
  232. p = Protanopie(img, rows, cols, kanaele)
  233. display_array_pro = cv2.cvtColor(np.copy(p.Simulate()), cv2.COLOR_BGR2RGB)
  234. T = tk.Text(SB.frame, height=1, width=15)
  235. T.grid(columnspan=5)
  236. T.insert('current', "Protanopie:")
  237. conv_SimulationPic_pro = ImageTk.PhotoImage(image=PIL.Image.fromarray(display_array_pro))
  238. sim_pic_pro = tk.Label(SB.frame, image=conv_SimulationPic_pro)
  239. sim_pic_pro.Image = conv_SimulationPic_pro
  240. sim_pic_pro.grid(columnspan=5)
  241. btn = tk.Button(SB.frame, text="Browse", width=25, command=browse, bg='light blue')
  242. btn.grid(column=0, row=0, columnspan=2)
  243. simulateButton = tk.Button(SB.frame, text="Simulate", width=25, command=simulate, bg='light blue')
  244. simulateButton.grid(column=1, row=0, columnspan=2)
  245. simulateButton.config(state='disabled')
  246. checkButton_p = tk.Checkbutton(SB.frame, text="Protanop", variable=sim_pro, onvalue=1, offvalue=0, height=5, width=20)
  247. checkButton_d = tk.Checkbutton(SB.frame, text="Deutanop", variable=sim_deut, onvalue=1, offvalue=0, height=5, width=20)
  248. checkButton_t = tk.Checkbutton(SB.frame, text="Tritanop", variable=sim_tri, onvalue=1, offvalue=0, height=5, width=20)
  249. checkButton_p.grid(column=0, row=2)
  250. checkButton_d.grid(column=1, row=2)
  251. checkButton_t.grid(column=2, row=2)
  252. SB.update()
  253. root.mainloop()