Compare commits

...
42 Commits
Author SHA1 Message Date
Max Sponsel 1be205389b Kleine Anpassungen 2020-09-21 10:58:20 +02:00
Max Sponsel a206147edf Dalt Algorithmus und Auslagern des Displays
Der Dalt Algorithmus wird nun von dem Dalt-Button ausgeführt. Gleichzeitig wurde die Funktion showImage geschrieben, um Code zu verschlanken und lediglich die Switchfunktionen simulate und daltonize für die Auswahl der Simulationsart zu nutzen.
PS: Mehrere Bilder zum Testen eingefügt
2020-09-19 10:44:07 +02:00
Max Sponsel 137ca981f2 Einfügen eines Dalt-Buttons in die GUI
Zum Aufrufen des Algorithmus in der GUI muss ein Button Objekt der tkinter Klasse erstellt werden. Dieses wird erst nach einem erfolgreich ausgewählten Bild aktiv! Als nächstes steht die Implementation der daltonize-Funktion an, die durch command='daltonize' ausgeführt wird.
2020-09-18 11:40:40 +02:00
Max Sponsel 8498500c68 Daltonization in die Klasse eingefügt
Funktion der Daltonization in die Klasse Dyschromasie eingefügt.
2020-09-18 10:58:28 +02:00
Max Sponsel 638fadeb28 Angepasster Daltonizationalgorithmus
https://github.com/indranilsinharoy/daltonization/blob/master/daltonize.py

Implementierung des gezeigten Algorithmus. Wichtig ist die Int64 Konvertierung , um Überläufe zu verhindern.
2020-09-17 12:23:02 +02:00
Max Sponsel b78f3c2908 Erster Daltonizationalgorithmus 2020-09-17 11:41:00 +02:00
Max Sponsel 804bc74885 Lookup-Table für die Entfrenung der Gamma Korrektur implementiert
Zur Besseren Performance wird eine Lookup Table benötigt. Diese gleicht dynamisch alles Werte ab anstatt bei jedem einzelnen Pixelwert die Berechnung durchzuführen.
2020-09-15 11:51:22 +02:00
Max Sponsel 105b6689b8 Gaussian Blur entfernt 2020-09-14 10:42:36 +02:00
Max Sponsel 250cf3fd32 Import angepasst 2020-09-14 10:22:52 +02:00
Max Sponsel fd0161e320 Genauere Berechnung der Oberen Werte
Änderung des Return-Wertes auf 255 - dem Delta zwischen Übersteuerung und dem Maximialwert zur besseren Farbdarstellung
2020-09-14 10:21:33 +02:00
Max Sponsel 1cc63c6a30 Entfernen der Print Befehle für's Debugging 2020-09-13 12:56:46 +02:00
Max Sponsel 0795db1f96 Merge remote-tracking branch 'origin/master' 2020-09-13 12:53:51 +02:00
Max Sponsel 31ed0825c3 Weitere Anpassungen für Tritanopie
Anders als bei den anderen Fehlsichtigkeiten ist ein Überlauf des Wertebereichs möglich. Somit werden Werte, die 255 überschreiten standardmäßig auf diesen Maximalwert gesetzt.
2020-09-13 12:53:35 +02:00
Max Sponsel ff420dc77c Weitere Anpassungen für Tritanopie
Anders als bei den anderen Fehlsichtigkeiten ist ein Überlauf des Wertebereichs möglich. Somit werden Werte, die 255 überschreiten standardmäßig auf diesen Maximalwert gesetzt.
2020-09-13 12:52:49 +02:00
Max Sponsel 9b76b10e32 Lösung des Aliasing Problems
Betrachtung des Pixels (40,152) im Fall Tree Bild ergab die Lösung für das Aliasing:
Bei negativen Werten in der Matrix T^1*sim_mat*T ergeben sich Überläufe. Lösung durch Anpassen der GammaKorrektur auf Abstände statt Absolutwerte.
2020-09-13 11:51:17 +02:00
Max Sponsel d5252ea2be Weiter CodeCleanup 2020-09-12 11:52:40 +02:00
Max Sponsel 30d0e61ca7 Auslagern der Scrollbar-Funktion und Einfügen von Beispielbildern 2020-09-12 11:45:49 +02:00
Max Sponsel f176685f0b Beispielbild aus Paper hinzugefügt 2020-09-11 17:35:34 +02:00
Max Sponsel 98e6b56bd3 CodeCleanup
Funktionen ausgelagert und drei Farbarten zu einer großen Klasse zusammengefasst
2020-09-10 14:44:29 +02:00
Max Sponsel 08881f47cf Vereinfachung des Codes mit cv2.cvtColor
Statt das Array doppelt mit der flipud Funktion zu spiegeln, wird es direkt im Einleseprozess von BGR(OpenCV) zu RGB(Pillow und Algorithmus) konvertiert.
2020-09-10 11:34:04 +02:00
Max Sponsel e62ea2a23e Anpassung des Print Befehls
Ausgabe des Bildes erfolgt nun auch mit der Stärke der Farbblindheitssimulation (von 0 bis 100%)
2020-09-07 10:47:17 +02:00
SponselMa71420 3b5798b143 Verschiedene Testreihen zur Abschwächung sowie die Grundidee mit Formelanpassung 2020-09-04 10:01:05 +00:00
Max Sponsel a1ebdb827c Abschwächung der Simulationsstärke
Durch Anpassungen in den Simulationsmatrizen ergeben sich Abschwächungsmuster. Somit können für verschiedene Probanden unterschiedliche Stärken der Sehschwäche simuliert werden.
2020-09-04 11:59:25 +02:00
Max Sponsel 9980f03bdd Dynamische vertikale und horizontale Scrollbar
Durch Hilfe von Stack Overflow wurde eine dynamische Scrollbar implementiert. Diese erscheint je nach Windowgröße dynamisch. 
(siehe hierzu: https://stackoverflow.com/questions/47008899/tkinter-dynamic-scrollbar-for-a-dynamic-gui-not-updating-with-gui)
2020-08-29 10:10:11 +02:00
Max Sponsel 62b16b4a96 Erste Tests mit Slider und Umwandlungsfunktion
Erste Funktionen in den Klassen implementiert; Erste Test gemacht. Ergebnisse noch nicht zufriedenstellend. Auch Implementierung einer Scrollbar nötig!!
2020-08-25 10:45:12 +02:00
Max Sponsel bbc3aafeb3 Merge remote-tracking branch 'origin/master' 2020-08-25 09:40:33 +02:00
Max Sponsel da88618ce6 Einfügen eines Sliders
Um den Grad der Faarbblindheit korrekt zu Simulieren, muss ein Widget eingebaut werden, welches den prozentualen Anteil der Differenz zwischen Simulation und echtem Wert vergleicht und mit dem ausgewählten Wert (z. B. 80%) neu gewichtet.
2020-08-25 09:40:27 +02:00
Max Sponsel f1348cfef2 Einfügen eines Sliders
Um den Grad der Faarbblindheit korrekt zu Simulieren, muss ein Widget eingebaut werden, welches den prozentualen Anteil der Differenz zwischen Simulation und echtem Wert vergleicht und mit dem ausgewählten Wert (z. B. 80%) neu gewichtet.
2020-08-25 09:40:16 +02:00
Max Sponsel d1cd073fde Merge remote-tracking branch 'origin/master' 2020-08-21 11:23:26 +02:00
SponselMa71420 3ee51d0be4 Applikation zur Simulation der verschiedenen Fehlsichtigkeiten
Nachdem nun die Theorie hinter der Simulation geklärt ist, wenden wir uns jetzt dem Applikationbau zu.
2020-08-21 09:23:03 +00:00
Max Sponsel 8c4760c75d Kommentar entfernt 2020-08-15 09:18:51 +02:00
Max Sponsel 28325c408e Algorithmusanpassung
Nutzung der Built-in Funktion der Farbkonvertierung von OpenCV statt ständiger, doppelter Drehung im Algorithmus. Effizienter und schneller!
2020-08-15 08:31:33 +02:00
Max Sponsel dad7554c71 Pillow Import
Einbauen des Imports von Pillow für das Graphical Interface. Installation über: pip install pillow
2020-08-14 18:03:43 +02:00
Max Sponsel 74759f92b5 Kommentar zur Berechnung eingefügt 2020-07-11 09:42:55 +02:00
Max Sponsel 12dd773020 Korrektur des Algorithmus
Durch die NumPy Funktion numpy.flipud konnte das RGB Array umgedreht, der Algorithmus des Papers angewendet und schließlich eine Rücktransformation der RGB Werte stattfinden. Die erhaltenen Bilder entsprechen nun den Erwartungen.
2020-07-11 09:40:29 +02:00
Max Sponsel 871715bbad Merge remote-tracking branch 'origin/master' 2020-07-09 16:06:51 +02:00
Max Sponsel 1165dc1e21 Fehler im Algorithmus gefunden
Anders als im Paper werden die RGB Werte nicht in der Reihenfolge Rot Grün Blau (RGB), sondern in OpenCV als Blau grün rot (BGR) abgespeichert.
Also ist ein e Funktion zum "Umdrehen" der Matrix nötig!
2020-07-09 16:06:27 +02:00
Max Sponsel e7eead37ee Fehler im Algorithmus gefunden
Anders als im Paper werden die RGB Werte nicht in der Reihenfolge Rot Grün Blau (RGB), sondern in OpenCV als Blau grün rot (BGR) abgespeichert.
Also ist ein e Funktion zum "Umdrehen" der Matrix nötig!
2020-07-09 16:06:12 +02:00
Max Sponsel 899580b119 Kleine Anpassungen an den Interpretierer 2020-07-04 10:54:05 +02:00
Max Sponsel d7cb8c293e Anpassung der Bildveränderung
Trotz Anpassungen sind noch einige Verbesserungen nötig: Grauanteile, wo keine sein sollten treten auf. Die Berechnungsalgorithmen müssen überprüft werden.
2020-06-27 11:24:07 +02:00
SponselMa71420 4d54aa9d3c Bild, welches im technical Paper verwendet wurde
---
2020-06-27 08:57:56 +00:00
Max Sponsel 2a4e394165 Erste Logik zur Bildänderung
Matrixmultiplikation und Gamma-Rücktransformation angewendet
2020-06-27 10:54:20 +02:00
25 changed files with 457 additions and 14 deletions

No files matched your search

+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 3.8 (2)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+6
View File
@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (2)" project-jdk-type="Python SDK" />
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/Projekt_Dyschromasie.iml" filepath="$PROJECT_DIR$/.idea/Projekt_Dyschromasie.iml" />
</modules>
</component>
</project>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
+105
View File
@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="7500fa3a-b013-4e17-984f-eefa85ecceed" name="Default Changelist" comment="" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="ProjectId" id="1e30iP9BsZRaeOrrN9JBEG6XvPT" />
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
<property name="WebServerToolWindowFactoryState" value="false" />
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
<property name="settings.editor.selected.configurable" value="com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable" />
</component>
<component name="RunManager">
<configuration name="Dyschromasie" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="Projekt_Dyschromasie" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/Code" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/Code/Dyschromasie.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<recent_temporary>
<list>
<item itemvalue="Python.Dyschromasie" />
</list>
</recent_temporary>
</component>
<component name="SvnConfiguration">
<configuration />
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="7500fa3a-b013-4e17-984f-eefa85ecceed" name="Default Changelist" comment="" />
<created>1593535095255</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1593535095255</updated>
<workItem from="1593535098710" duration="1145000" />
<workItem from="1593601045161" duration="890000" />
<workItem from="1593693652245" duration="183000" />
<workItem from="1593852460532" duration="308000" />
<workItem from="1594452919558" duration="449000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="2" />
</component>
<component name="WindowStateProjectService">
<state x="739" y="275" key="FileChooserDialogImpl" timestamp="1593535189103">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state x="739" y="275" key="FileChooserDialogImpl/0.0.1920.1040/-1920.109.1920.1040@0.0.1920.1040" timestamp="1593535189103" />
<state width="1877" height="282" key="GridCell.Tab.0.bottom" timestamp="1594453344568">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state width="1877" height="282" key="GridCell.Tab.0.bottom/0.0.1920.1040/-1920.109.1920.1040@0.0.1920.1040" timestamp="1594453344568" />
<state width="1877" height="282" key="GridCell.Tab.0.center" timestamp="1594453344568">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state width="1877" height="282" key="GridCell.Tab.0.center/0.0.1920.1040/-1920.109.1920.1040@0.0.1920.1040" timestamp="1594453344568" />
<state width="1877" height="282" key="GridCell.Tab.0.left" timestamp="1594453344567">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state width="1877" height="282" key="GridCell.Tab.0.left/0.0.1920.1040/-1920.109.1920.1040@0.0.1920.1040" timestamp="1594453344567" />
<state width="1877" height="282" key="GridCell.Tab.0.right" timestamp="1594453344568">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state width="1877" height="282" key="GridCell.Tab.0.right/0.0.1920.1040/-1920.109.1920.1040@0.0.1920.1040" timestamp="1594453344568" />
<state x="461" y="165" key="SettingsEditor" timestamp="1593535127245">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state x="461" y="165" key="SettingsEditor/0.0.1920.1040/-1920.109.1920.1040@0.0.1920.1040" timestamp="1593535127245" />
</component>
<component name="com.intellij.coverage.CoverageDataManagerImpl">
<SUITE FILE_PATH="coverage/Projekt_Dyschromasie$Dyschromasie.coverage" NAME="Dyschromasie Coverage Results" MODIFIED="1594453344546" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/Code" />
</component>
</project>
Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

+116
View File
@@ -0,0 +1,116 @@
from PIL import Image, ImageTk
import PIL
import tkinter as tk
import cv2
import numpy as np
from Farbaenderung import Dyschromasie
from Scrollbar import ScrollFrame
root = tk.Tk()
simGrad = tk.IntVar(root)
root.title("Projekt Dyschromasie")
SB = ScrollFrame(root)
img = np.array([])
rows = 0
cols = 0
kanaele = 0
sim_pro = tk.IntVar(root)
sim_deut = tk.IntVar(root)
sim_tri = tk.IntVar(root)
simulationsGradient = tk.Scale(SB.frame, from_=0, to_=100, variable=simGrad, orient='horizontal')
simulationsGradient.grid(column=0, row=1, columnspan=10)
def browse():
# Auswahl des FilePaths
try:
path = tk.filedialog.askopenfilename(filetypes=[("Image File", '.jpg'), ("Image File", '.png')])
im = Image.open(path)
except:
tk.messagebox.showerror(title='Datenfehler', message='Kein Bild gefunden/ausgewählt')
global simulateButton
if len(path) > 0:
simulateButton.config(state='active')
daltonButton.config(state='active')
# Anzeigen des Bildes
tkimage = ImageTk.PhotoImage(im)
myvar = tk.Label(SB.frame, image=tkimage)
myvar.image = tkimage
myvar.grid(columnspan=5)
# Einspeichern der Path-Informationen
global img, rows, cols, kanaele
img = cv2.imread(path)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
rows, cols, kanaele = img.shape
def showImage(img, rows, cols, kanaele, sim_faktor, sim_kind, sim_art):
color_blindness = Dyschromasie(img, rows, cols, kanaele, sim_faktor, sim_kind)
if sim_art == 'Sim':
color_blindness_mat = np.copy(color_blindness.Simulate()).astype('uint8')
else:
color_blindness_mat = np.copy(color_blindness.daltonize()).astype('uint8')
T = tk.Text(SB.frame, height=1, width=15)
T.grid(columnspan=5)
print_string = sim_kind + ' ' + str(round(color_blindness.sim_faktor * 100)) + "%"
T.insert('current', print_string)
conv_SimulationPic = ImageTk.PhotoImage(image=PIL.Image.fromarray(color_blindness_mat))
sim_pic = tk.Label(SB.frame, image=conv_SimulationPic)
sim_pic.Image = conv_SimulationPic
sim_pic.grid(columnspan=5)
def simulate():
global img, rows, cols, kanaele, sim_pro, sim_deut, sim_tri
if sim_deut.get():
showImage(img, rows, cols, kanaele, simGrad.get()/100, 'Deuteranop', 'Sim')
elif sim_tri.get():
showImage(img, rows, cols, kanaele, simGrad.get() / 100, 'Tritanop', 'Sim')
elif sim_pro.get():
showImage(img, rows, cols, kanaele, simGrad.get() / 100, 'Protanop', 'Sim')
def daltonize():
global img, rows, cols, kanaele, sim_pro, sim_deut, sim_tri
if sim_deut.get():
showImage(img, rows, cols, kanaele, simGrad.get()/100, 'Deuteranop', 'Dalt')
elif sim_tri.get():
showImage(img, rows, cols, kanaele, simGrad.get() / 100, 'Tritanop', 'Dalt')
elif sim_pro.get():
showImage(img, rows, cols, kanaele, simGrad.get() / 100, 'Protanop', 'Dalt')
browseButton = tk.Button(SB.frame, text="Browse", width=25, command=browse, bg='light blue')
browseButton.grid(column=0, row=0, columnspan=1)
simulateButton = tk.Button(SB.frame, text="Simulate", width=25, command=simulate, bg='light blue')
simulateButton.grid(column=1, row=0, columnspan=1)
simulateButton.config(state='disabled')
daltonButton = tk.Button(SB.frame, text="Daltonize", width=25, command=daltonize, bg='light blue')
daltonButton.grid(column=2, row=0, columnspan=1)
daltonButton.config(state='disabled')
checkButton_p = tk.Checkbutton(SB.frame, text="Protanop", variable=sim_pro, onvalue=1, offvalue=0, height=5, width=20)
checkButton_d = tk.Checkbutton(SB.frame, text="Deutanop", variable=sim_deut, onvalue=1, offvalue=0, height=5, width=20)
checkButton_t = tk.Checkbutton(SB.frame, text="Tritanop", variable=sim_tri, onvalue=1, offvalue=0, height=5, width=20)
checkButton_p.grid(column=0, row=2)
checkButton_d.grid(column=1, row=2)
checkButton_t.grid(column=2, row=2)
SB.update()
root.mainloop()
+16 -14
View File
@@ -2,17 +2,17 @@ import cv2 # OpenCV fuer Bildbearbeitung
import tkinter # Zum Erstellen von GUIs import tkinter # Zum Erstellen von GUIs
import numpy as np # Numpy Import import numpy as np # Numpy Import
import sys import sys
from PIL import Image, ImageTk #Wichtig zum Anzeigen der Bilder im GUI
# Einlesen des Bildes # Einlesen des Bildes
script_dir = sys.path[0] script_dir = sys.path[0]
path = script_dir[:-4] + "Beispielbilder\lena.jpg" path = script_dir[:-4] + "Beispielbilder\grocery_store.jpg"
image = cv2.imread(path) # Einlesen des Bildes (noch hardcodiert, sollte dann in GUI gehen) image = cv2.cvtColor(cv2.imread(path),cv2.COLOR_BGR2RGB) # Einlesen des Bildes (noch hardcodiert, sollte dann in GUI gehen)
rows = image.shape[0] # Auslesen der Zeilenanzahl rows = image.shape[0] # Auslesen der Zeilenanzahl
cols = image.shape[1] # Auslesen der Spaltenanzahl cols = image.shape[1] # Auslesen der Spaltenanzahl
kanaele = image.shape[2] # Auslesen der Kanaele (3 fuer RGB, 1 fuer Graubild) kanaele = image.shape[2] # Auslesen der Kanaele (3 fuer RGB, 1 fuer Graubild)
def gammaCorrection(v): def gammaCorrection(v):
if v <= 0.04045 * 255: if v <= 0.04045 * 255:
return float(((v / 255) / 12.92)) return float(((v / 255) / 12.92))
@@ -32,7 +32,6 @@ def reverseGammaCorrection(v_reverse):
print("Ungültiger Wert!!!") print("Ungültiger Wert!!!")
return 1 return 1
cb_image = np.copy(image) # Kopie des Bildarrays cb_image = np.copy(image) # Kopie des Bildarrays
cb_image = cb_image.astype('float64') # Casting des Arrays auf Float cb_image = cb_image.astype('float64') # Casting des Arrays auf Float
@@ -62,14 +61,7 @@ T_reversed = np.array([[5.47221206, -4.6419601, 0.16963708],
[-1.1252419, 2.29317094, -0.1678952], [-1.1252419, 2.29317094, -0.1678952],
[0.02980165, -0.19318073, 1.16364789]]) [0.02980165, -0.19318073, 1.16364789]])
# Multiplikation der einzelnen Pixelwerte S_p = np.array([[0, 1.05118294, -0.05116099], #Simulationsmatrix fuer Protanopie
for i in range(rows):
for j in range(cols):
cb_image[i, j] = T.dot(cb_image[i, j])
# Simulationsmatrizen fuer Protanop
S_b = np.array([[0, 1.05118294, -0.05116099], #Simulationsmatrix fuer Protanopie
[0, 1, 0], [0, 1, 0],
[0, 0, 1]]) [0, 0, 1]])
@@ -81,11 +73,21 @@ S_t = np.array([[1, 0, 0], #Simulationsmatrix fuer Tritanopi
[0, 1, 0], [0, 1, 0],
[-0.86744736, 1.86727089, 0]]) [-0.86744736, 1.86727089, 0]])
#choice = input("Bitte geben Sie den Typ der zu simulierenden Farbblindheit an:(B,D,T)")
#Multiplikation der einzelnen Pixel
for i in range(rows):
for j in range(cols):
cb_image[i,j] = T_reversed.dot(S_t).dot(T).dot(cb_image[i,j])
sim_image = np.copy(cb_image)
sim_image = sim_image.astype('uint8')
#Rücktransformation der Gammawerte
for i in range(rows):
for j in range(cols):
for x in range(3):
sim_image[i, j, x] = reverseGammaCorrection(cb_image[i, j, x])
cv2.namedWindow("Display") # Displaywindow erstellen cv2.namedWindow("Display") # Displaywindow erstellen
cv2.imshow("Display", image) # Bild zeigen cv2.imshow("Display", cv2.cvtColor(sim_image,cv2.COLOR_RGB2BGR)) # Bild zeigen
cv2.waitKey(0) # Fenster offen halten cv2.waitKey(0) # Fenster offen halten
+126
View File
@@ -0,0 +1,126 @@
import numpy as np
import cv2
def createGammaLookup():
return np.array([removeGammaCorrection(i) for i in np.arange(0, 256)]).astype("float64")
def createReverseGammaLookup():
return np.array([applyGammaCorrection(i / 255) for i in np.arange(0.0, 256.0)]).astype("uint8")
def removeGammaCorrection(v):
if v <= 0.04045 * 255:
return (v / 255) / 12.92
elif v > 0.04045 * 255:
return (((v / 255) + 0.055) / 1.055) ** 2.4
def applyGammaCorrection(v_reverse):
if abs(v_reverse) <= 0.0031308:
return round(255 * (12.92 * abs(v_reverse)))
else:
if (round(255 * (1.055 * abs(v_reverse) ** 0.41666 - 0.055))) > 255:
return 255 - (round(255 * (1.055 * abs(v_reverse) ** 0.41666 - 0.055)) - 255)
else:
return round(255 * (1.055 * abs(v_reverse) ** 0.41666 - 0.055))
class Dyschromasie:
cb_image = np.array([]).astype('float64')
sim_image = np.array([]).astype('int64')
def __init__(self, img_mat=np.array([]), rows=0, cols=0, kanaele=0, sim_faktor=0, sim_kind='Deuteranop'):
self.rows = rows
self.cols = cols
self.kanaele = kanaele
self.img_mat = img_mat
self.sim_faktor = sim_faktor
self.sim_kind = sim_kind
T = np.array([[0.31399022, 0.63951294, 0.04649755],
[0.15537241, 0.75789446, 0.08670142],
[0.01775239, 0.10944209, 0.87256922]])
T_reversed = np.array([[5.47221206, -4.6419601, 0.16963708],
[-1.1252419, 2.29317094, -0.1678952],
[0.02980165, -0.19318073, 1.16364789]])
def Simulate(self):
removeGammaCorrectionLUT = createGammaLookup()
if self.sim_kind == 'Protanop':
sim_mat = np.array([[(1 - self.sim_faktor), 1.05118294 * self.sim_faktor, -0.05116099 * self.sim_faktor],
[0, 1, 0],
[0, 0, 1]])
elif self.sim_kind == 'Deuteranop':
sim_mat = np.array([[1, 0, 0],
[0.9513092 * self.sim_faktor, (1 - self.sim_faktor), 0.04866992 * self.sim_faktor],
[0, 0, 1]])
elif self.sim_kind == 'Tritanop':
sim_mat = np.array([[1, 0, 0],
[0, 1, 0],
[-0.86744736 * self.sim_faktor, 1.86727089 * self.sim_faktor, (1 - self.sim_faktor)]])
# Gammakorrektur durchfuehren
self.cb_image = np.copy(self.img_mat).astype('float64')
self.cb_image = cv2.LUT(self.img_mat, removeGammaCorrectionLUT)
rechen_Mat = np.copy(self.T_reversed.dot(sim_mat).dot(self.T))
# Einzelne Pixelwertberechnung
for i in range(self.rows):
for j in range(self.cols):
self.cb_image[i, j] = rechen_Mat.dot(self.cb_image[i, j])
self.sim_image = np.copy(self.cb_image)
self.sim_image = self.sim_image.astype('int64')
# Rücktransformation der Gammawerte
for i in range(self.rows):
for j in range(self.cols):
for x in range(3):
self.sim_image[i, j, x] = applyGammaCorrection(self.cb_image[i, j, x])
return self.sim_image.astype('uint8')
def daltonize(self):
err2mod = np.array([[0, 0, 0], [0.7, 1, 0], [0.7, 0, 1]])
simulated_image = self.Simulate()
E = np.copy(simulated_image).astype('int32')
for i in range(self.rows):
for j in range(self.cols):
for x in range(3):
E[i, j, x] = abs(int(self.img_mat[i, j, x]) - int(simulated_image[i, j, x]))
ERR = np.zeros_like(self.img_mat).astype('int32')
for i in range(self.rows):
for j in range(self.cols):
err = E[i, j, :3]
ERR[i, j, :3] = np.dot(err2mod, err)
dtpn = np.copy(self.img_mat).astype('int32')
for i in range(self.rows):
for j in range(self.cols):
for x in range(3):
dtpn[i, j, x] = abs(int(ERR[i, j, x]) + int(self.img_mat[i, j, x]))
for i in range(self.rows):
for j in range(self.cols):
dtpn[i, j, 0] = max(0, dtpn[i, j, 0])
dtpn[i, j, 0] = min(255, dtpn[i, j, 0])
dtpn[i, j, 1] = max(0, dtpn[i, j, 1])
dtpn[i, j, 1] = min(255, dtpn[i, j, 1])
dtpn[i, j, 2] = max(0, dtpn[i, j, 2])
dtpn[i, j, 2] = min(255, dtpn[i, j, 2])
result = dtpn.astype('uint8')
dalt = Dyschromasie(result, self.rows, self.cols, self.kanaele, self.sim_faktor, self.sim_kind)
return dalt.Simulate()
+59
View File
@@ -0,0 +1,59 @@
import tkinter as tk
from tkinter import filedialog, messagebox
class AutoScrollbar(tk.Scrollbar):
# A scrollbar that hides itself if it's not needed.
# Only works if you use the grid geometry manager!
def set(self, lo, hi):
if float(lo) <= 0.0 and float(hi) >= 1.0:
# grid_remove is currently missing from Tkinter!
self.tk.call("grid", "remove", self)
else:
self.grid()
tk.Scrollbar.set(self, lo, hi)
def pack(self, **kw):
raise TclError("cannot use pack with this widget")
def place(self, **kw):
raise TclError("cannot use place with this widget")
class ScrollFrame:
def __init__(self, master):
self.vscrollbar = AutoScrollbar(master)
self.vscrollbar.grid(row=0, column=1, sticky='ns')
self.hscrollbar = AutoScrollbar(master, orient='horizontal')
self.hscrollbar.grid(row=1, column=0, sticky='ew')
self.canvas = tk.Canvas(master, yscrollcommand=self.vscrollbar.set,
xscrollcommand=self.hscrollbar.set)
self.canvas.grid(row=0, column=0, sticky='nsew')
self.vscrollbar.config(command=self.canvas.yview)
self.hscrollbar.config(command=self.canvas.xview)
# make the canvas expandable
master.grid_rowconfigure(0, weight=1)
master.grid_columnconfigure(0, weight=1)
# create frame inside canvas
self.frame = tk.Frame(self.canvas)
self.frame.rowconfigure(1, weight=1)
self.frame.columnconfigure(1, weight=1)
# update the frame
self.frame.bind("<Configure>", self.reset_scrollregion)
def reset_scrollregion(self, event):
self.canvas.configure(scrollregion=self.canvas.bbox('all'))
def update(self):
self.canvas.create_window(0, 0, anchor='nw', window=self.frame)
self.frame.update_idletasks()
self.canvas.config(scrollregion=self.canvas.bbox("all"))
if self.frame.winfo_reqwidth() != self.canvas.winfo_width():
# update the canvas's width to fit the inner frame
self.canvas.config(width = self.frame.winfo_reqwidth())
if self.frame.winfo_reqheight() != self.canvas.winfo_height():
# update the canvas's width to fit the inner frame
self.canvas.config(height = self.frame.winfo_reqheight())
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB