Compare commits

...
2 Commits
Author SHA1 Message Date
Ross Kruger 1e3318dfd6 lots of fixes 2024-02-19 09:44:05 +00:00
Ross Kruger e5ae513cce add requirements 2024-01-04 00:20:26 +00:00
6 changed files with 192 additions and 128 deletions
+7 -1
View File
@@ -3,4 +3,10 @@
logs/* logs/*
.pyc .pyc
__pycache__/*
build
dist
*.build
+6
View File
@@ -0,0 +1,6 @@
@echo off
rem This script was created by Nuitka to execute 'anon_gui.exe' with Python DLL being found.
set PATH=C:\PROGRA~1\PYTHON~1;%PATH%
set PYTHONHOME=C:\Program Files\Python311
"%~dp0anon_gui.exe" %*
BIN
View File
Binary file not shown.
+164 -115
View File
@@ -55,8 +55,11 @@ import hashlib
try: try:
from agw import hyperlink as hl from agw import hyperlink as hl
from agw import pygauge as PG
except ImportError: # if it's not there locally, try the wxPython lib. except ImportError: # if it's not there locally, try the wxPython lib.
import wx.lib.agw.hyperlink as hl import wx.lib.agw.hyperlink as hl
import wx.lib.agw.pygauge as PG
import wx.lib.agw.thumbnailctrl as TC import wx.lib.agw.thumbnailctrl as TC
@@ -565,7 +568,7 @@ class AnonGui(wx.App):
self.series_grid = SeriesGrid(self.panel) self.series_grid = SeriesGrid(self.panel)
if self.clear_files_on_start: if self.clear_files_on_start:
self.ClearFiles() self.ClearFiles(load_dir=False)
self.panel.sizer = wx.BoxSizer(wx.VERTICAL) self.panel.sizer = wx.BoxSizer(wx.VERTICAL)
@@ -627,7 +630,6 @@ class AnonGui(wx.App):
self.list_ctrl.InsertColumn(6, "Hash") self.list_ctrl.InsertColumn(6, "Hash")
self.list_ctrl.InsertColumn(7, "Series Instance UID") self.list_ctrl.InsertColumn(7, "Series Instance UID")
self.AnnonymiseFilesInDir(self.input_dir, self.dir)
# self.UpdateListCtrl() # self.UpdateListCtrl()
@@ -673,12 +675,23 @@ class AnonGui(wx.App):
self.panel.sizer.Add(self.drag_button, 2, wx.EXPAND) self.panel.sizer.Add(self.drag_button, 2, wx.EXPAND)
self.panel.sizer.Add(self.upload_button, 2, wx.EXPAND) self.panel.sizer.Add(self.upload_button, 2, wx.EXPAND)
self.progress_sizer = wx.BoxSizer(wx.VERTICAL)
self.progress_bar = wx.Gauge(self.panel, style=wx.GA_HORIZONTAL|wx.GA_PROGRESS)
#self.progress_bar = PG.PyGauge(self.panel, style=wx.GA_HORIZONTAL|wx.GA_PROGRESS)
#self.progress_bar.SetDrawValue(draw=True, drawPercent=True, font=None, colour=wx.RED, formatString=None)
self.progress_text = wx.StaticText(self.panel, label="Text")
self.progress_sizer.Add(self.progress_bar, 2, wx.EXPAND)
self.progress_sizer.Add(self.progress_text, 2, wx.EXPAND)
self.panel.sizer.Add(self.progress_sizer, 2, wx.EXPAND)
self.progress_sizer.ShowItems(show=False)
# Layout sizers # Layout sizers
self.panel.SetSizer(self.panel.sizer) self.panel.SetSizer(self.panel.sizer)
self.panel.SetAutoLayout(1) self.panel.SetAutoLayout(1)
self.panel.sizer.Fit(self.panel) self.panel.sizer.Fit(self.panel)
self.frame.Show() self.frame.Show()
# self.spinner.Hide() # self.spinner.Hide()
self.AnnonymiseFilesInDir(self.input_dir, self.dir)
self.Bind(wx.EVT_KEY_DOWN, self.onKeyPress) self.Bind(wx.EVT_KEY_DOWN, self.onKeyPress)
@@ -717,29 +730,57 @@ class AnonGui(wx.App):
#files = order_files_by_dicom_attribute(files) #files = order_files_by_dicom_attribute(files)
progress_dialog = wx.ProgressDialog( #progress_dialog = wx.ProgressDialog(
"Annonymise files", # "Annonymise files",
"Removing data...", # "Removing data...",
maximum=len(files), # maximum=len(files),
style=wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME | wx.PD_ESTIMATED_TIME, # style=wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME | wx.PD_ESTIMATED_TIME,
) #)
with self.progress(len(files), "Annonymise files") as p:
#p.SetRange(len(files))
for n, file in enumerate(files): for n, file in enumerate(files):
progress_dialog.Update(n) #progress_dialog.Update(n)
new_filepath: Path p.update(n)
# Get next available filename new_filepath: Path
i: int = 0 # Get next available filename
while os.path.exists( i: int = 0
new_filepath := output_dir.joinpath(f"IMG_{i:03}.dcm") while os.path.exists(
): new_filepath := output_dir.joinpath(f"IMG_{i:03}.dcm")
i += 1 ):
# new_filepath = Path(output_dir).joinpath(f"IMG_{i:03}.dcm") i += 1
# new_filepath = Path(output_dir).joinpath(f"IMG_{i:03}.dcm")
dataset, filepath = anonymize_file(file, new_filepath) dataset, filepath = anonymize_file(file, new_filepath)
self.add_datails_to_file_detail_map(dataset, filepath) self.add_datails_to_file_detail_map(dataset, filepath)
progress_dialog.Destroy() #progress_dialog.Destroy()
self.LoadDir(self.dir) self.LoadDir(self.dir)
@contextlib.contextmanager
def progress(self, total: int, text: str="Working"):
#self.progress_sizer.Show()
self.progress_text.SetLabelText(text)
self.progress_bar.SetRange(total)
self.progress_sizer.ShowItems(show=True)
self.panel.Layout()
#self.panel.sizer.Fit(self.panel)
try:
class P():
def __init__(self, gui, total, text):
self.gui = gui
self.text = text
self.total = total
def update(self, n: int):
self.gui.progress_bar.SetValue(n)
self.gui.progress_text.SetLabelText(f"{self.text} : {n}")
yield P(self, total, text)
finally:
#self.progress_sizer.Hide()
self.progress_sizer.ShowItems(show=False)
self.panel.Layout()
#self.panel.SetAutoLayout(1)
#self.panel.sizer.Fit(self.panel)
def onKeyPress(self, event): def onKeyPress(self, event):
keycode = event.GetKeyCode() keycode = event.GetKeyCode()
@@ -774,7 +815,7 @@ class AnonGui(wx.App):
def OnExit(self): def OnExit(self):
if self.clear_files_on_close: if self.clear_files_on_close:
self.ClearFiles() self.ClearFiles(load_dir=False)
# self.zmq_thread.join() # self.zmq_thread.join()
@@ -915,11 +956,13 @@ class AnonGui(wx.App):
dlg.ShowModal() dlg.ShowModal()
def ClearFiles(self, event=None): def ClearFiles(self, event=None, load_dir: bool=True):
files = Path(self.dir).glob("*") files = Path(self.dir).glob("*")
for f in files: for f in files:
os.remove(f) os.remove(f)
self.LoadDir(clear_file_detail_map=True)
if load_dir:
self.LoadDir(clear_file_detail_map=True)
def add_datails_to_file_detail_map(self, dataset, file): def add_datails_to_file_detail_map(self, dataset, file):
try: try:
@@ -1018,66 +1061,69 @@ class AnonGui(wx.App):
n = 0 n = 0
DATA = {} DATA = {}
progress_dialog = wx.ProgressDialog( #progress_dialog = wx.ProgressDialog(
"Loading files", # "Loading files",
"Extracting data from files", # "Extracting data from files",
maximum=len(self.files), # maximum=len(self.files),
style=wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME | wx.PD_ESTIMATED_TIME, # style=wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME | wx.PD_ESTIMATED_TIME,
) #)
with self.progress((len(self.files)), "Loading files") as p:
#p.SetRange(len(self.files))
self.series_map = defaultdict(list) self.series_map = defaultdict(list)
self.series_map_details = defaultdict(dict) self.series_map_details = defaultdict(dict)
hashes = [] hashes = []
for n, f in enumerate(self.files): for n, f in enumerate(self.files):
progress_dialog.Update(n) #progress_dialog.Update(n)
# dataset = pydicom.read_file(f) p.update(n)
# dataset = pydicom.read_file(f)
if f in self.file_detail_map: if f in self.file_detail_map:
d, hash, d2 = self.file_detail_map[f] d, hash, d2 = self.file_detail_map[f]
print("in map") print("in map")
else: else:
try:
dataset = pydicom.dcmread(f)
except FileNotFoundError:
return
print("recalc")
d, hash, d2 = self.add_datails_to_file_detail_map(dataset, f)
hashes.append(hash)
series_instances_uid = d2["series_instances_uid"]
try: try:
dataset = pydicom.dcmread(f) self.series_map[series_instances_uid].append(f)
except FileNotFoundError: self.series_map_details[series_instances_uid][
return "series_description"
] = d2["series_description"]
self.series_map_details[series_instances_uid]["study_description"] = d2[
"study_description"
]
self.series_map_details[series_instances_uid]["name"] = d2["name"]
except:
logger.debug(f"Unable to get Series Instance UID: {f.name}")
print("recalc") logger.debug(d)
d, hash, d2 = self.add_datails_to_file_detail_map(dataset, f) DATA[n] = d
self.list_ctrl.Append(d)
self.list_ctrl.SetItemPyData(n, {"file": f, "hash": hash})
self.list_ctrl.SetItemData(n, n)
hashes.append(hash) if f in self.file_duplicate_check:
if self.file_duplicate_check[f]["id"]:
self.list_ctrl.SetItemBackgroundColour(n, wx.RED)
n = n + 1
series_instances_uid = d2["series_instances_uid"]
try:
self.series_map[series_instances_uid].append(f)
self.series_map_details[series_instances_uid][
"series_description"
] = d2["series_description"]
self.series_map_details[series_instances_uid]["study_description"] = d2[
"study_description"
]
self.series_map_details[series_instances_uid]["name"] = d2["name"]
except:
logger.debug(f"Unable to get Series Instance UID: {f.name}")
logger.debug(d)
DATA[n] = d
self.list_ctrl.Append(d)
self.list_ctrl.SetItemPyData(n, {"file": f, "hash": hash})
self.list_ctrl.SetItemData(n, n)
if f in self.file_duplicate_check:
if self.file_duplicate_check[f]["id"]:
self.list_ctrl.SetItemBackgroundColour(n, wx.RED)
n = n + 1
self.list_ctrl.UpdateData(DATA) self.list_ctrl.UpdateData(DATA)
self.populate_series_grid() self.populate_series_grid()
progress_dialog.Destroy() #progress_dialog.Destroy()
#if hashes: #if hashes:
# self.check_image_hashes(hashes) # self.check_image_hashes(hashes)
@@ -1110,8 +1156,8 @@ class AnonGui(wx.App):
for hash, dup in resp.json().items(): for hash, dup in resp.json().items():
self.file_duplicate_check[hash_file_map[hash]] = dup self.file_duplicate_check[hash_file_map[hash]] = dup
print(self.file_duplicate_check) if resp.json().items():
wx.CallAfter(self.UpdateListCtrl) wx.CallAfter(self.UpdateListCtrl)
self.image_hash_check_in_progress = False self.image_hash_check_in_progress = False
def OnColRightClick(self, event): def OnColRightClick(self, event):
@@ -1134,52 +1180,55 @@ class AnonGui(wx.App):
files_to_upload[i : i + n] for i in range(0, len(files_to_upload), n) files_to_upload[i : i + n] for i in range(0, len(files_to_upload), n)
] ]
progress_dialog = wx.ProgressDialog( #progress_dialog = wx.ProgressDialog(
"Uploading files", # "Uploading files",
"Uploading files. This is done in batches...", # "Uploading files. This is done in batches...",
maximum=len(chunked_files), # maximum=len(chunked_files),
style=wx.PD_ELAPSED_TIME | wx.PD_ESTIMATED_TIME, # style=wx.PD_ELAPSED_TIME | wx.PD_ESTIMATED_TIME,
) #)
with self.progress(len(chunked_files), "Uploading files (in batches)") as p:
#p.SetRange(len(chunked_files))
upload_file_list = [] upload_file_list = []
duplicate_file_list = [] duplicate_file_list = []
for n, files in enumerate(chunked_files): for n, files in enumerate(chunked_files):
def upload_files(files): def upload_files(files):
self.rqst.headers["X-CSRFToken"] = self.rqst.cookies["csrftoken"] self.rqst.headers["X-CSRFToken"] = self.rqst.cookies["csrftoken"]
# print(self.rqst.headers) # print(self.rqst.headers)
# print(self.rqst.cookies) # print(self.rqst.cookies)
resp = self.rqst.post( resp = self.rqst.post(
f"{self.base_site_url}/api/atlas/upload_dicom", f"{self.base_site_url}/api/atlas/upload_dicom",
# data=data, # data=data,
files=files, files=files,
) )
logger.debug(f"Resp: {resp}") logger.debug(f"Resp: {resp}")
logger.debug(f"{resp.content}") logger.debug(f"{resp.content}")
return resp return resp
progress_dialog.Update(n, f"Uploading batch {n}/{len(chunked_files)}") p.update(n)
#progress_dialog.Update(n, f"Uploading batch {n}/{len(chunked_files)}")
logger.debug(f"n: {n}") logger.debug(f"n: {n}")
# try to upload the files # try to upload the files
resp = upload_files(files) resp = upload_files(files)
if resp.status_code == 200: if resp.status_code == 200:
upload_file_list.extend(resp.json()["uploaded"]) upload_file_list.extend(resp.json()["uploaded"])
duplicate_file_list.extend(resp.json()["duplicates"]) duplicate_file_list.extend(resp.json()["duplicates"])
continue continue
logger.debug(f"n: {n} fail") logger.debug(f"n: {n} fail")
# try again if we fail # try again if we fail
resp = upload_files(files) resp = upload_files(files)
if resp.status_code == 200: if resp.status_code == 200:
upload_file_list.extend(resp.json()["uploaded"]) upload_file_list.extend(resp.json()["uploaded"])
duplicate_file_list.extend(resp.json()["duplicates"]) duplicate_file_list.extend(resp.json()["duplicates"])
continue continue
progress_dialog.Destroy() #progress_dialog.Destroy()
print(upload_file_list) print(upload_file_list)
print(duplicate_file_list) print(duplicate_file_list)
@@ -1213,10 +1262,10 @@ class AnonGui(wx.App):
@app.callback(invoke_without_command=True) @app.callback(invoke_without_command=True)
def runGUI( def runGUI(
ctx: typer.Context, ctx: typer.Context,
#input_dir: Path = "C:\\Temp\\", input_dir: Path = "C:\\Temp\\",
input_dir: Path = "/home/ross/temp/in/", #input_dir: Path = "/home/ross/temp/in/",
#output_dir: Path = "C:\\temp_upload\\", output_dir: Path = "C:\\temp_upload\\",
output_dir: Path = "/home/ross/temp/out/", #output_dir: Path = "/home/ross/temp/out/",
silent_fail: bool = False, silent_fail: bool = False,
clear_files: bool = True, clear_files: bool = True,
clear_files_on_close: bool = True, clear_files_on_close: bool = True,
+3 -12
View File
@@ -1,33 +1,24 @@
# -*- mode: python ; coding: utf-8 -*- # -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis( a = Analysis(
['anon_gui.py'], ['anon_gui.py'],
pathex=[], pathex=[],
#binaries=[(r"C:\Users\krugerro\Desktop\rad_tools\.venv\Lib\site-packages\pywin32_system32\pythoncom311.dll", "."), binaries=[],
#(r"C:\Users\krugerro\Desktop\rad_tools\.venv\Lib\site-packages\pywin32_system32\pywintypes311.dll", "."),
#],
datas=[], datas=[],
hiddenimports=[], hiddenimports=[],
hookspath=[], hookspath=[],
hooksconfig={}, hooksconfig={},
runtime_hooks=[], runtime_hooks=[],
excludes=[], excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False, noarchive=False,
) )
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) pyz = PYZ(a.pure)
exe = EXE( exe = EXE(
pyz, pyz,
a.scripts, a.scripts,
a.binaries, a.binaries,
a.zipfiles,
a.datas, a.datas,
[], [],
name='anon_gui', name='anon_gui',
@@ -37,7 +28,7 @@ exe = EXE(
upx=True, upx=True,
upx_exclude=[], upx_exclude=[],
runtime_tmpdir=None, runtime_tmpdir=None,
console=True, console=False,
disable_windowed_traceback=False, disable_windowed_traceback=False,
argv_emulation=False, argv_emulation=False,
target_arch=None, target_arch=None,
+12
View File
@@ -0,0 +1,12 @@
typer
wxpython
pydicom
dicognito
python-datauri
bs4
requests
zmq
blake3
loguru
dicom2jpg
pyinstaller