✨ feat(data_processing.py): add raw_data parameter to get_advanced_data function to improve flexibility The L variable was not being computed in the get_advanced_data function, which is necessary for the calculation of the tortuosity. The raw_data parameter was added to the get_advanced_data function to improve flexibility and allow for more advanced calculations to be performed. 🐛 fix(input.py): add filename attribute to ScannedObject class The filename attribute was not being set in the ScannedObject class, which is necessary for generating the output file headers. ✨ feat(output.py): add function to generate headers for output file The generate_headers function was added to generate the headers for the output file. The headers include the filename, date, version, discretisation method, and whether the data was verticalised. 🚀 chore(MainWindow.py): enable process_advanced_data function 🎨 style(MainWindow.ui, UI_MainWindow.py): adjust GUI layout and label text for better user experience The GUI layout has been adjusted to improve the user experience. The window width has been reduced from 1419 to 1336 pixels to better fit the screen. The minimum and maximum sizes of the MainSettings widget have been increased from 518 to 600 pixels to allow for more space for the labels. The labels have been updated to include the units of measurement to improve clarity. 🐛 fix(AdvancedDataWorker.py): add raw_data parameter to __init__ method ✨ feat(AdvancedDataWorker.py): add support for raw data processing in get_advanced_data method The AdvancedDataWorker class now has a raw_data parameter in its __init__ method, which is used in the get_advanced_data method. This allows for raw data processing in addition to the existing discrete data processing. 🐛 fix(DiscreteDataWorker.py): generate headers before formatting data ✨ feat(DiscreteDataWorker.py): add support for generating headers in output file The DiscreteDataWorker class now generates headers for the output file if the add_headers setting is enabled. The headers are generated before formatting the data to ensure that the headers are included in the output file. 🐛 fix(PreProcessWorker.py): set filename of ScannedObject The PreProcessWorker class now sets the filename of the ScannedObject to the basename 🎨 style(UI_Settings.py): reorganize widgets in the settings UI for better readability 🐛 fix(data_extraction.py): fix standard deviation calculation to use unbiased estimator 🔧 chore(SettingManager.py): add "add_headers" setting with default value of True The changes in UI_Settings.py are purely cosmetic and do not affect the functionality of the code. The fix in data_extraction.py corrects the standard deviation calculation to use the unbiased estimator. The addition of the "add_headers" setting in SettingManager.py allows for the addition of headers to output files.
215 lines
7.8 KiB
Python
215 lines
7.8 KiB
Python
"""
|
||
Created on Mon Apr 24 2023
|
||
@name: data_processing.py
|
||
@desc: A module to process the data
|
||
@auth: Djalim Simaila
|
||
@e-mail: djalim.simaila@inrae.fr
|
||
"""
|
||
from utils.math import data_extraction as de
|
||
import numpy as np
|
||
from utils.files.input import ScannedObject
|
||
|
||
def progressbar_placeholder(percent:int):
|
||
"""
|
||
This function is a placeholder for a progressbar function
|
||
"""
|
||
|
||
def get_raw_data(obj:ScannedObject, ndigits:int,delta_z:float=1,update_progress_bar = progressbar_placeholder)->dict:
|
||
"""
|
||
Calculates data from the given object
|
||
|
||
:param obj: Object to analyse
|
||
:param ndigits: Number of digits to keep after the comma
|
||
:param delta_z: Delta z to use for the discretisation
|
||
:param update_progress_bar: Function to update the progress bar
|
||
:return: dict(str:list) with the following keys:
|
||
- X (en mm) : list of x values
|
||
- Y (en mm) : list of y values
|
||
- Z (en mm) : list of z values
|
||
- theta (en rad) : list of theta values
|
||
- rayon (en mm) : list of radius values
|
||
- Xi-Xmoy : list of Xi-Xmoy values
|
||
- Yi-Ymoy : list of Yi-Ymoy values
|
||
"""
|
||
|
||
# Create the data dict
|
||
colones = ["X (en mm)",
|
||
"Y (en mm)",
|
||
"Z (en mm)",
|
||
"theta (en rad)",
|
||
"rayon (en mm)",
|
||
"Xi-Xmoy",
|
||
"Yi-Ymoy"]
|
||
data = {}
|
||
for colone in colones:
|
||
data[colone] = []
|
||
|
||
# Get the discrete vertices
|
||
discrete_vertices = obj.get_discrete_vertices(delta_z)
|
||
progress = 0
|
||
|
||
# Calculate the data for each discrete vertex
|
||
for discrete_values in discrete_vertices:
|
||
mean_x ,mean_y, mean_z = de.get_x_y_z_mean(discrete_values)
|
||
for x,y,z in discrete_values:
|
||
data["X (en mm)"].append(round(x, ndigits))
|
||
data["Y (en mm)"].append(round(y, ndigits))
|
||
data["Z (en mm)"].append(round(z, ndigits))
|
||
data["theta (en rad)"].append(round(de.get_theta_from_x_y(x,y,mean_x,mean_y), ndigits))
|
||
data["rayon (en mm)"].append(round(de.get_radius_from_x_y(x,y,mean_x,mean_y), ndigits))
|
||
data["Xi-Xmoy"].append(round(x-mean_x, ndigits))
|
||
data["Yi-Ymoy"].append(round(y-mean_y, ndigits))
|
||
update_progress_bar(int(progress/len(discrete_vertices)*100))
|
||
progress += 1
|
||
return data
|
||
|
||
def get_discrete_data(obj:ScannedObject, ndigits:int, delta_z:float=1, update_progress_bar= progressbar_placeholder)->dict:
|
||
"""
|
||
Calculates data from the given object
|
||
|
||
:param obj: Object to analyse
|
||
:param ndigits: Number of digits to keep after the comma
|
||
:param delta_z: Delta z to use for the discretisation
|
||
:param update_progress_bar: Function to update the progress bar
|
||
:return: dict(str:list) with the following keys:
|
||
- X moy (en mm) : list of x mean values
|
||
- Y moy (en mm) : list of y mean values
|
||
- Z moy (en mm) : list of z mean values
|
||
- Rayon moyen (en mm) : list of mean radius values
|
||
- Rayon ecart type (en mm) : list of radius standard deviation values
|
||
"""
|
||
|
||
# Create the data dict
|
||
colones = ["X moy (en mm)",
|
||
"Y moy (en mm)",
|
||
"Z moy (en mm)",
|
||
"Discretisation(en mm)",
|
||
"Rayon moyen (en mm)",
|
||
"Rayon ecart type (en mm)"]
|
||
data = {}
|
||
for colone in colones:
|
||
data[colone] = []
|
||
|
||
# Get the discrete vertices
|
||
discrete_vertices = obj.get_discrete_vertices(delta_z)
|
||
progress = 0
|
||
for discrete_values in discrete_vertices:
|
||
x,y,z = de.get_x_y_z_mean(discrete_values)
|
||
data["X moy (en mm)"].append(round(x, ndigits))
|
||
data["Y moy (en mm)"].append(round(y, ndigits))
|
||
data["Z moy (en mm)"].append(round(z, ndigits))
|
||
first = discrete_values[0]
|
||
last = discrete_values[-1]
|
||
data["Discretisation(en mm)"].append(round(last[2]-first[2],ndigits))
|
||
data["Rayon moyen (en mm)"].append(round(de.get_mean_radius(discrete_values), ndigits))
|
||
data["Rayon ecart type (en mm)"].append(round(de.get_radius_std(discrete_values), ndigits))
|
||
update_progress_bar(int(progress/len(discrete_vertices)*100))
|
||
progress += 1
|
||
return data
|
||
|
||
def get_advanced_data(discrete_data:dict, raw_data:dict, V_scan = 0, update_progress_bar= progressbar_placeholder)->dict:
|
||
"""
|
||
Calculates morphological indicators from the given discrete data
|
||
|
||
:param discrete_data: dict(str:list) with the following keys:
|
||
- X moy (en mm) : list of x mean values
|
||
- Y moy (en mm) : list of y mean values
|
||
- Z moy (en mm) : list of z mean values
|
||
- Rayon moyen (en mm) : list of mean radius values
|
||
- Rayon ecart type (en mm) : list of radius standard deviation values
|
||
:param raw_data: dict(str:list) with the following keys:
|
||
- X (en mm) : list of x values
|
||
- Y (en mm) : list of y values
|
||
- Z (en mm) : list of z values
|
||
- theta (en rad) : list of theta values
|
||
- rayon (en mm) : list of radius values
|
||
- Xi-Xmoy : list of Xi-Xmoy values
|
||
- Yi-Ymoy : list of Yi-Ymoy values/
|
||
:param V_scan: the volume given by the scanner software
|
||
:param update_progress_bar: Function to update the progress bar
|
||
:return: dict with the following keys:
|
||
- Tortuosite
|
||
- Volume en mm3
|
||
- Surface en mm2
|
||
- Moyenne des rayons moyens 〈R〉
|
||
- Ecart-type des rayons moyens σ_<R>
|
||
- σ_<R>^tot
|
||
- H
|
||
- L
|
||
- l
|
||
- MI_l
|
||
- MI_p
|
||
- MI_mR
|
||
- MI_mH
|
||
- MI_mr_in
|
||
- V_scan
|
||
- R_V_scan
|
||
- S_V_scan
|
||
- Rayon hydraulique R_h
|
||
- HI
|
||
"""
|
||
all_R = discrete_data["Rayon moyen (en mm)"]
|
||
# Tortusity
|
||
l = 0
|
||
L = 0
|
||
vertices = list(zip(discrete_data["X moy (en mm)"],
|
||
discrete_data["Y moy (en mm)"],
|
||
discrete_data["Z moy (en mm)"]))
|
||
for index in range(len(vertices)-1):
|
||
l += de.get_distance_between_two_vertices(vertices[index], vertices[index+1])
|
||
l += discrete_data["Discretisation(en mm)"][-1] /2 + discrete_data["Discretisation(en mm)"][0] /2
|
||
L = de.get_distance_between_two_vertices(vertices[0], vertices[-1]) + discrete_data["Discretisation(en mm)"][-1] /2 + discrete_data["Discretisation(en mm)"][0] /2
|
||
T = l/L
|
||
update_progress_bar(10)
|
||
|
||
# Volume and surface
|
||
H = raw_data["Z (en mm)"][-1] - raw_data["Z (en mm)"][0]
|
||
|
||
R_mean = de.get_mean(all_R)
|
||
R2_mean = de.get_mean([np.power(r,2) for r in all_R])
|
||
V = np.pi * R2_mean * H
|
||
|
||
S = 2 * np.pi * R_mean * H
|
||
update_progress_bar(30)
|
||
|
||
# Morphological indicators
|
||
R_mean_std = de.get_standard_deviation(all_R)
|
||
mean_sigma_r_squared = de.get_mean([np.power(r,2) for r in discrete_data["Rayon ecart type (en mm)"]])
|
||
sigma_r_tot = np.sqrt(np.power(R_mean_std,2) + mean_sigma_r_squared )
|
||
MI_l = R_mean_std/R_mean
|
||
MI_p = np.sqrt(mean_sigma_r_squared)/R_mean
|
||
|
||
R_max = max(raw_data["Z (en mm)"])
|
||
R_in = 40
|
||
MI_mR = R_max/R_mean
|
||
MI_mH = R_max/H
|
||
MI_mr_in = R_max/R_in
|
||
R_V_scan = np.sqrt(V_scan/np.pi*H)
|
||
S_V_scan = 2 * np.sqrt(np.pi * H * V_scan)
|
||
R_h = R2_mean/ R_mean
|
||
HI = R_mean * R_V_scan / R2_mean
|
||
update_progress_bar(100)
|
||
return {
|
||
"Tortuosité":T,
|
||
"Volume en mm3":V,
|
||
"Surface en mm2":S,
|
||
"<R>":R_mean,
|
||
"<R²>":R2_mean,
|
||
"σ_<R>":R_mean_std,
|
||
"σ_<R>^tot":sigma_r_tot,
|
||
"H": H,
|
||
"L": L,
|
||
"l":l,
|
||
"MI_l":MI_l,
|
||
"MI_p":MI_p,
|
||
"R_max":R_max,
|
||
"MI_mR":MI_mR,
|
||
"MI_mH":MI_mH,
|
||
"MI_mR_in":MI_mr_in,
|
||
"V_scan":V_scan,
|
||
"R_V_scan":R_V_scan,
|
||
"S_V_scan":S_V_scan,
|
||
"Rayon hydraulique R_h":R_h,
|
||
"HI":HI
|
||
}
|