feat: Update volume slider range and default values

chore: Refactor code for improved readability and maintainability
This commit is contained in:
2024-06-17 13:55:15 +02:00
parent f611abde66
commit 34982dd973
8 changed files with 127 additions and 78 deletions

3
.gitignore vendored
View File

@@ -3,4 +3,5 @@
/express-app/
/react-app/
/.vscode/
/3D_app.old/
/3D_app.old/
3D_app/data.sqlite

View File

@@ -1,4 +1,3 @@
from re import I
from dash import callback, Input, Output, State
from selection_filtre import switch_case
import plotly.graph_objects as go
@@ -185,16 +184,16 @@ def get_callbacks():
data_avec_traitement = switch_case(
data_avec_traitement,
int(select_filtre_1),
float(fs_filtre_1),
float(cutoff_filtre_1),
int(fs_filtre_1),
int(cutoff_filtre_1),
int(order_filtre_1),
int(windowsize_filtre_1),
)
data_avec_traitement = switch_case(
data_avec_traitement,
int(select_filtre_2),
float(fs_filtre_2),
float(cutoff_filtre_2),
int(fs_filtre_2),
int(cutoff_filtre_2),
int(order_filtre_2),
int(windowsize_filtre_2),
)
@@ -250,7 +249,7 @@ def get_callbacks():
data_sans_traitement_fft = np.fft.fft(
volume[
int(select_ascan_y) - 1,
select_ascan_z[0] : select_ascan_z[1],
select_ascan_z[0] : int(select_ascan_z[1] / 2),
int(select_ascan_x) - 1,
]
)

View File

@@ -6,6 +6,7 @@ import plotly.express as px
from os.path import join
from util import lire_fichier_csv
from selection_filtre import switch_case
from callbacks.ascan import data_traits
# on définit le dossier et les fichiers à lire
dossier = "Dataset/Shear_transform"
@@ -107,11 +108,15 @@ def get_callbacks():
Input("layer-slider-bscan-zx", "value"),
Input("layer-slider-bscan-xy", "value"),
],
[dash.dependencies.State("fade-ascan", "is_in")],
prevent_initial_call=True,
[State("fade-ascan", "is_in"), State("store-settings", "data")],
)
def update_heatmap_ascan(layer, layer1, is_in):
fig = px.line(y=volume[layer - 1, :, layer1], title="A-scan")
def update_heatmap_ascan(layer, layer1, is_in, settings):
if settings["apply_sampling_everywhere"]:
data = volume
else:
data = pre_volume
fig = px.line(y=data[layer - 1, :, layer1], title="A-scan")
return [fig, True]
@@ -119,9 +124,15 @@ def get_callbacks():
@callback(
Output("heatmap-ascan-fullscreen", "figure"),
Input("layer-slider-ascan-fullscreen", "value"),
State("store-settings", "data")
)
def update_heatmap_ascan_fullscreen(layer):
fig = px.line(y=volume[layer - 1, :, 5], title="A-scan")
def update_heatmap_ascan_fullscreen(layer, settings):
if settings["apply_sampling_everywhere"]:
data = volume
else:
data = pre_volume
fig = px.line(y=data[layer - 1, :, 5], title="A-scan")
return fig
# callback pour les B-scan XY
@@ -132,12 +143,16 @@ def get_callbacks():
Output("fade-bscan-xy", "is_in"),
],
[Input("layer-slider-bscan-zx", "value")],
[dash.dependencies.State("fade-bscan-zx", "is_in")],
prevent_initial_call=True,
[State("fade-bscan-zx", "is_in"), State("store-settings", "data")],
)
def update_heatmap_bscan_zx(layer, is_in):
def update_heatmap_bscan_zx(layer, is_in, settings):
if settings["apply_sampling_everywhere"]:
data = volume
else:
data = pre_volume
fig = px.imshow(
volume[layer - 1, :, :],
data[layer - 1, :, :],
color_continuous_scale="Jet",
aspect="auto",
title="B-scan ZX",
@@ -149,10 +164,16 @@ def get_callbacks():
@callback(
Output("heatmap-bscan-zx-fullscreen", "figure"),
Input("layer-slider-bscan-zx-fullscreen", "value"),
State("store-settings", "data")
)
def update_heatmap_bscan_zx_fullscreen(layer):
def update_heatmap_bscan_zx_fullscreen(layer, settings):
if settings["apply_sampling_everywhere"]:
data = volume
else:
data = pre_volume
fig = px.imshow(
volume[layer - 1, :, :],
data[layer - 1, :, :],
color_continuous_scale="Jet",
aspect="auto",
title="B-scan ZX",
@@ -168,11 +189,15 @@ def get_callbacks():
Output("fade-bscan-zx", "is_in"),
],
[Input("layer-slider-bscan-xy", "value")],
[dash.dependencies.State("fade-bscan-xy", "is_in")],
prevent_initial_call=True,
[State("fade-bscan-xy", "is_in"), State("store-settings", "data")],
)
def update_heatmap_bscan_xy(layer, is_in):
fig = go.Figure(data=go.Heatmap(z=volume[:, :, layer], colorscale="Jet"))
def update_heatmap_bscan_xy(layer, is_in, settings):
if settings["apply_sampling_everywhere"]:
data = volume
else:
data = pre_volume
fig = go.Figure(data=go.Heatmap(z=data[:, :, layer], colorscale="Jet"))
fig.update_layout(title="B-scan XY")
return [fig, layer, True]
@@ -181,9 +206,15 @@ def get_callbacks():
@callback(
Output("heatmap-bscan-xy-fullscreen", "figure"),
Input("layer-slider-bscan-xy-fullscreen", "value"),
State("store-settings", "data"),
)
def update_heatmap_bscan_xy_fullscreen(layer):
fig = go.Figure(data=go.Heatmap(z=volume[:, :, layer], colorscale="Jet"))
def update_heatmap_bscan_xy_fullscreen(layer, settings):
if settings["apply_sampling_everywhere"]:
data = volume
else:
data = pre_volume
fig = go.Figure(data=go.Heatmap(z=data[:, :, layer], colorscale="Jet"))
fig.update_layout(title="B-scan XY")
return fig
@@ -232,22 +263,6 @@ def get_callbacks():
return not is_open
return is_open
@callback(
[
Output("3dplot", "clickData"),
Output("layer-slider-bscan-xy", "value"),
Output("layer-slider-bscan-zx", "value"),
],
Input("3dplot", "clickData"),
)
def display_3dplot_click_data(clickData):
if clickData is None:
return [None, 1, 1]
bscan_xy = clickData["points"][0]["z"]
bscan_zx = clickData["points"][0]["x"]
return [clickData, bscan_xy, bscan_zx]
@callback(
[
Output("heatmap-bscan-xy", "clickData"),
@@ -288,7 +303,7 @@ def get_callbacks():
prevent_initial_call=True,
)
def update_bscan_layers(bscan_xy, bscan_zx):
fig = go.Figure(data=go.Heatmap(z=volume[:, :, bscan_xy], colorscale="Jet"))
fig = go.Figure(data=go.Heatmap(z=pre_volume[:, :, bscan_xy], colorscale="Jet"))
fig.add_shape(
type="line",
x0=0 - 1,
@@ -300,7 +315,7 @@ def get_callbacks():
fig.update_layout(title="B-scan XY")
fig2 = px.imshow(
volume[bscan_zx - 1, :, :],
pre_volume[bscan_zx - 1, :, :],
color_continuous_scale="Jet",
aspect="auto",
title="B-scan ZX",
@@ -314,7 +329,7 @@ def get_callbacks():
line=dict(color="white", width=1),
)
fig3 = px.line(y=volume[bscan_zx - 1, :, bscan_xy], title="A-scan")
fig3 = px.line(y=pre_volume[bscan_zx - 1, :, bscan_xy], title="A-scan")
return [fig, fig2, fig3]
@@ -329,6 +344,7 @@ def get_callbacks():
State("echantillonage-x", "value"),
State("echantillonage-y", "value"),
State("echantillonage-z", "value"),
State("apply-sampling-everywhere", "value"),
],
prevent_initial_call=True,
)
@@ -339,6 +355,7 @@ def get_callbacks():
echantillonage_x_value,
echantillonage_y_value,
echantillonage_z_value,
apply_sampling,
):
if clicks != None and clicks == 1:
return [
@@ -348,6 +365,7 @@ def get_callbacks():
"echantillonage_x": echantillonage_x_value,
"echantillonage_y": echantillonage_y_value,
"echantillonage_z": echantillonage_z_value,
"apply_sampling_everywhere": apply_sampling,
},
0,
]
@@ -394,14 +412,14 @@ def get_callbacks():
{str(i): str(i) for i in range(0, dim_x, max(1, int(dim_x / 20)))},
dim_z - 1,
{str(i): str(i) for i in range(1, dim_z + 1, max(1, int(dim_z / 20)))},
volume.min(),
0,
volume.max() / 2,
{
str(i): str(i)
for i in range(
int(volume.min()),
0,
int(volume.max() / 2) + 1,
int((volume.max() / 2 - volume.min()) / 10),
int(volume.max() / 20),
)
},
dim_y,
@@ -528,5 +546,5 @@ def get_callbacks():
if format == "raw":
np.save(join("Dataset/saves", filename), pre_volume)
else:
np.save(join("Dataset/saves", filename), volume)
np.save(join("Dataset/saves", filename), data_traits)
return True

View File

@@ -42,12 +42,14 @@ def get_callbacks():
@callback(
Output("open-modal", "is_open"),
[Input("open-button", "n_clicks"), Input("open-close", "n_clicks")],
[Input("open-button", "n_clicks"), Input("open-close", "n_clicks"), Input("open-refresh", "n_clicks")],
[dash.dependencies.State("open-modal", "is_open")],
)
def toggle_open(n1, n2, is_open):
def toggle_open(n1, n2, n3, is_open):
if n1 or n2:
return not is_open
elif n3:
return True
return is_open
@@ -88,6 +90,7 @@ def get_callbacks():
[
Output("open-modal", "is_open", allow_duplicate=True),
Output("store-files", "data"),
Output("opened-file", "children"),
],
Input({"type": "file-item", "index": ALL}, "n_clicks"),
State({"type": "file-item", "index": ALL}, "children"),
@@ -96,11 +99,11 @@ def get_callbacks():
def open_file(n, filenames):
ctx = dash.callback_context
if not ctx.triggered or all(click is None for click in n):
return [None, ""]
return [None, "", "No file opened"]
file_index = ctx.triggered[0]["prop_id"].split(".")[0]
file_index = eval(file_index)
filename = filenames[file_index["index"]]
return [False, filename]
return [False, filename, f"Opened file: {filename}"]
@callback(

View File

@@ -2,6 +2,7 @@ import sqlite3
from util import *
import numpy as np
import datetime
from progress.bar import IncrementalBar
timestamp_start = datetime.datetime.now()
@@ -9,6 +10,7 @@ db = sqlite3.connect('data.sqlite')
cursor = db.cursor()
cursor.execute('CREATE TABLE IF NOT EXISTS volume (x INTEGER, y INTEGER, z INTEGER, value REAL)')
cursor.execute('CREATE TABLE IF NOT EXISTS properties (name TEXT, value TEXT)')
# on définit le dossier et les fichiers à lire
@@ -21,17 +23,25 @@ fichiers_selectionnes = [
# fichiers_selectionnes = ['Shear_x001-x101_y{:03d}_Rot00.csv'.format(i) for i in range(10, 62)]
# on lit les fichiers et on les met dans un tableau
pre_volume = np.array(lire_fichier_csv(dossier, fichiers_selectionnes))
volume = pre_volume[:, ::32, :]
volume = np.array(lire_fichier_csv(dossier, fichiers_selectionnes))[:, ::16, :]
dim_x, dim_y, dim_z = volume.shape
X, Y, Z = np.mgrid[0:dim_x, 0:dim_y, 0:dim_z]
bar = IncrementalBar('Processing', max=dim_x*dim_y*dim_z, suffix="%(percent).2f%% - %(index)d/%(max)d (%(eta).3fs remaining estimated)",)
cursor.execute('DELETE FROM volume')
for x in range(dim_x):
for y in range(dim_y):
for z in range(dim_z):
cursor.execute('INSERT INTO volume (x, y, z, value) VALUES (?, ?, ?, ?)', (x, y, z, volume[x, y, z]))
bar.next()
bar.finish()
cursor.execute('DELETE FROM properties')
cursor.execute('INSERT INTO properties (name, value) VALUES (?, ?)', ('dim_x', str(dim_x)))
cursor.execute('INSERT INTO properties (name, value) VALUES (?, ?)', ('dim_y', str(dim_y)))
cursor.execute('INSERT INTO properties (name, value) VALUES (?, ?)', ('dim_z', str(dim_z)))
db.commit()
db.close()

View File

@@ -6,21 +6,24 @@ from os.path import isfile, join
import diskcache
from json import load
from callbacks.main import *
import numpy as np
from util import lire_fichier_csv
cache = diskcache.Cache("./cache")
background_callback_manager = DiskcacheManager(cache)
# on crée l'application
app = dash.Dash(
__name__,
external_stylesheets=[dbc.themes.DARKLY, dbc.icons.BOOTSTRAP],
use_pages=True,
background_callback_manager=background_callback_manager,
)
config = load(open("config.json", "r"))
app.title = config["app_title"]
cache = diskcache.Cache("./cache")
background_callback_manager = DiskcacheManager(cache)
print("Reloading...")
@@ -32,6 +35,23 @@ if "saves" not in listdir("Dataset"):
files = listdir("Dataset/saves")
# on définit le dossier et les fichiers à lire
dossier = "Dataset/Shear_transform"
fichiers_selectionnes = [
"Shear_x001-x101_y{:03d}_Rot00_transform.csv".format(i) for i in range(10, 14)
]
# valeurs d'échantillonage
echantillonage_x = 1
echantillonage_y = 32
echantillonage_z = 1
pre_volume = np.array(lire_fichier_csv(dossier, fichiers_selectionnes))
volume = pre_volume[::echantillonage_x, ::echantillonage_y, ::echantillonage_z]
dim_x, dim_y, dim_z = volume.shape
X, Y, Z = np.mgrid[0:dim_x, 0:dim_y, 0:dim_z]
# on lit le fichier modal.md pour le tuto
with open("assets/modal.md", "r") as f:
@@ -101,6 +121,12 @@ modal_settings = dbc.Modal(
),
]
),
dbc.Switch(
id="apply-sampling-everywhere",
label="Apply sampling on A-Scan and B-Scan",
value=True,
className="me-2",
),
]
),
dbc.ModalFooter(
@@ -325,6 +351,7 @@ nav_bar = dbc.Navbar(
dbc.NavItem(button_settings),
dbc.NavItem(button_open),
dbc.NavItem(button_save),
dbc.Label(id="opened-file", style={"marginLeft": "10px", "padding": "0 auto"}),
],
className="ml-auto",
navbar=True,
@@ -365,6 +392,7 @@ app.layout = dbc.Container(
"echantillonage_x": 1,
"echantillonage_y": 32,
"echantillonage_z": 1,
"apply_sampling_everywhere": True,
},
),
dcc.Store(id="store-filters", data={}),

View File

@@ -130,15 +130,15 @@ mesh_card = dbc.Fade(
), # 'fig' is your 3D plotly figure
dcc.Slider(
id="iso-slider",
min=volume.min(),
min=0,
max=volume.max() / 2,
value=volume.min(),
value=0,
marks={
str(i): str(i)
for i in range(
int(volume.min()),
0,
int(volume.max() / 2) + 1,
int((volume.max() / 2 - volume.min()) / 10),
int(volume.max() / 20),
)
},
step=1,

View File

@@ -1,3 +1,4 @@
Pour le README de l'app 3D, se référer à [3D_app/README.md](3D_app/README.md)
# -----------------------Tache----------------------------
@@ -15,15 +16,10 @@
-Point of interest scan : caractérisation du ou des défauts qui seront représenter par des points d'intêrets.
### Secondaire :
### Secondaire :
Comparé les traitement entre pytohn et matlab en les correllant et dire qu'il sont à ..% différent et les superposés.
# -----------------------Biblio--------------------------
Papier vue
@@ -45,7 +41,6 @@ Low frequency ultrasonic dataset for pulse echo object detection in an isotropic
https://www.ncbi.nlm.nih.gov/pmc/articles/PMC9108879/
étude dont il serait intéressant de récupérer le data set, proposer par Hassan Rabah
Dataset for structural health monitoring of pipelines using ultrasonic guided waves
https://www.ncbi.nlm.nih.gov/pmc/articles/PMC9747640/
pareil, a voir pour récupérer le data set, proposer par Slavisa Jovanovic
@@ -53,7 +48,7 @@ pareil, a voir pour récupérer le data set, proposer par Slavisa Jovanovic
liste de projet de reconstruction 3D
https://github.com/bluestyle97/awesome-3d-reconstruction-papers?tab=readme-ov-file#neural-surface
Cours MIT, Machine learning for inverse graphics par Prof, Sitzmann:
Cours MIT, Machine learning for inverse graphics par Prof, Sitzmann:
https://www.scenerepresentations.org/courses/inverse-graphics-23/
Étude et développement de méthodes de caractérisation de défauts basées sur les reconstructions ultrasonores TFM:
@@ -63,9 +58,9 @@ Slicer-IGT, add-on de slicer permettant la représentation 3D en temps réel.
Site internet : https://www.slicerigt.org/wp/
GitHub : https://github.com/SlicerIGT/SlicerIGT
Réseau de neurone GNG :
Réseau de neurone GNG :
GitHub : https://github.com/ansrivas/GNG/tree/master?tab=readme-ov-file
GitHub-1: https://github.com/rendchevi/growing-neural-gas/blob/master/README.md
GitHub-1: https://github.com/rendchevi/growing-neural-gas/blob/master/README.md
Youtube_GitHub-1: https://www.youtube.com/watch?v=Dt73QWZQck4&t=2226s
Reconstruction
@@ -81,34 +76,29 @@ Technique TFM/FMC : présentation et travaux normatifs en cours:
https://www.isgroupe.com/fr/blog/technique-tfm-mc-presentation-travaux-normatifs-en-cours
# -----------------------Tuto------------------------------
apprendre openGL
https://opengl.developpez.com/tutoriels/apprendre-opengl/
camera
https://opengl.developpez.com/tutoriels/apprendre-opengl/?page=camera
le but de l'utilisation de openGl est d'in fine de développer un outil d'imagerie 3D pour représenter sous forme de voxel les set de data générer ou mesurer.
# -----------------------Note------------------------------
k wave
pour la simulation d'onde sonore, première introduction à la représentation de voxel dans Matlab.
OpenCV n'est pas forcement pertinent pour le moment l'outil à été élaborer surtout pour faire du traitement d'image.
Pour la suite du stage il sera intéressant voir nécessaire de se familiariser avec les méthode de filtrage pour ensuite en faire une implémentation FPGA si le temps nous le permet.
Pour un préambule de solution, pourquoi ne pas imaginé un système capable de faire tourner un os (raspberry pi) et en parallèle d'un FPGA qui ferais le gros des calculs (de filtrage par exemple)
Pour être très optimiste sur la suite de ce projet, imaginons un FPGA reconfigurable à la volée en fonction du type de filtrage que l'utilisateur souhaiterais utiliser dans sont système.
algorithme de contrôle vraiment nécessaire ?
algorithme de contrôle vraiment nécessaire ?
d'abord penser à une méthode de reconstruction 3D en temps réel, quel 'artefact' complète un objet, lequel n'est qu'un bruit donc devra être filtré.