def findDynamic(soup): qtmMeasurements = soup.find_all("Measurement") measurements = list() for measurement in qtmMeasurements: if "Gait" in measurement.attrs["Type"] and toBool( measurement.Used.text): measurements.append(measurement) return measurements
def findStatic(soup): qtmMeasurements = soup.find_all("Measurement") static = list() for measurement in qtmMeasurements: if "Static" in measurement.attrs["Type"] and toBool( measurement.Used.text): static.append(measurement) if len(static) > 1: raise Exception( "You can t have 2 activated static c3d within your session") return static[0]
def detectMeasurementType(soup): measurements = soup.find_all("Measurement") types = list() for measurement in measurements: if "Static" not in measurement.attrs["Type"] and toBool( measurement.Used.text): if measurement.attrs["Type"] not in types: types.append(measurement.attrs["Type"]) return types
def findKneeCalibration(soup, side): qtmMeasurements = soup.find_all("Measurement") kneeCalib = list() for measurement in qtmMeasurements: if side + " Knee Calibration" in measurement.attrs["Type"] and toBool( measurement.Used.text): kneeCalib.append(measurement) if len(kneeCalib) > 1: raise Exception( "You can t have 2 activated %s functional knee Calib c3d within your session" % (side)) return kneeCalib[0] if kneeCalib != [] else None
def detectMeasurementType(soup): measurements = soup.find_all("Measurement") types = list() for measurement in measurements: staticFlag = "Static" not in measurement.attrs["Type"] leftKneeFlag = "Left Knee Calibration - CGM2" not in measurement.attrs[ "Type"] rightKneeFlag = "Right Knee Calibration - CGM2" not in measurement.attrs[ "Type"] if staticFlag and leftKneeFlag and rightKneeFlag and toBool( measurement.Used.text): if measurement.attrs["Type"] not in types: types.append(measurement.attrs["Type"]) return types
def main(sessionFilename, createPDFReport=True, checkEventsInMokka=True, anomalyException=False): detectAnomaly = False LOGGER.set_file_handler("pyCGM2-QTM-Workflow.log") LOGGER.logger.info("------------QTM - pyCGM2 Workflow---------------") sessionXML = files.readXml(os.getcwd() + "\\", sessionFilename) sessionDate = files.getFileCreationDate(os.getcwd() + "\\" + sessionFilename) #--------------------------------------------------------------------------- #management of the Processed folder DATA_PATH = os.getcwd() + "\\" + "processed\\" files.createDir(DATA_PATH) staticMeasurement = qtmTools.findStatic(sessionXML) calibrateFilenameLabelled = qtmTools.getFilename(staticMeasurement) if not os.path.isfile(DATA_PATH + calibrateFilenameLabelled): shutil.copyfile(os.getcwd() + "\\" + calibrateFilenameLabelled, DATA_PATH + calibrateFilenameLabelled) LOGGER.logger.info( "qualisys exported c3d file [%s] copied to processed folder" % (calibrateFilenameLabelled)) if qtmTools.findKneeCalibration( sessionXML, "Left") is not None or qtmTools.findKneeCalibration( sessionXML, "Right") is not None: LOGGER.logger.info( " the %s not accept functional knee calibration !!" % (MODEL)) dynamicMeasurements = qtmTools.findDynamic(sessionXML) for dynamicMeasurement in dynamicMeasurements: reconstructFilenameLabelled = qtmTools.getFilename(dynamicMeasurement) # marker order_marker = int( float(dynamicMeasurement.Marker_lowpass_filter_order.text)) fc_marker = float( dynamicMeasurement.Marker_lowpass_filter_frequency.text) if not os.path.isfile(DATA_PATH + reconstructFilenameLabelled): shutil.copyfile(os.getcwd() + "\\" + reconstructFilenameLabelled, DATA_PATH + reconstructFilenameLabelled) LOGGER.logger.info( "qualisys exported c3d file [%s] copied to processed folder" % (reconstructFilenameLabelled)) acq = btkTools.smartReader( str(DATA_PATH + reconstructFilenameLabelled)) acq, zeniState = eventDetector.zeni( acq, fc_lowPass_marker=fc_marker, order_lowPass_marker=order_marker) if zeniState: btkTools.smartWriter( acq, str(DATA_PATH + reconstructFilenameLabelled)) if checkEventsInMokka: cmd = "Mokka.exe \"%s\"" % ( str(DATA_PATH + reconstructFilenameLabelled)) os.system(cmd) # --------------------------GLOBAL SETTINGS ------------------------------------ # global setting ( in user/AppData) if os.path.isfile(pyCGM2.PYCGM2_APPDATA_PATH + "CGM2_5-pyCGM2.settings"): settings = files.openFile(pyCGM2.PYCGM2_APPDATA_PATH, "CGM2_5-pyCGM2.settings") else: settings = files.openFile(pyCGM2.PYCGM2_SETTINGS_FOLDER, "CGM2_5-pyCGM2.settings") # --------------------------MP ------------------------------------ required_mp, optional_mp = qtmTools.SubjectMp(sessionXML) # translators management translators = files.getTranslators(os.getcwd() + "\\", "CGM2_5.translators") if not translators: translators = settings["Translators"] # ikweight ikWeight = files.getIKweightSet(DATA_PATH, "CGM2_5.ikw") if not ikWeight: ikWeight = settings["Fitting"]["Weight"] # --------------------------MODEL CALIBRATION ----------------------- LOGGER.logger.info( "--------------------------MODEL CALIBRATION -----------------------") staticMeasurement = qtmTools.findStatic(sessionXML) calibrateFilenameLabelled = qtmTools.getFilename(staticMeasurement) LOGGER.logger.info("----- CALIBRATION- static file [%s]--" % (calibrateFilenameLabelled)) leftFlatFoot = utils.toBool( sessionXML.Left_foot_normalised_to_static_trial.text) rightFlatFoot = utils.toBool( sessionXML.Right_foot_normalised_to_static_trial.text) headFlat = utils.toBool(sessionXML.Head_normalised_to_static_trial.text) markerDiameter = float(sessionXML.Marker_diameter.text) * 1000.0 hjcMethod = settings["Calibration"]["HJC"] pointSuffix = None # Calibration checking # -------------------- acqStatic = btkTools.smartReader(DATA_PATH + calibrateFilenameLabelled) # Calibration operation # -------------------- model, acqStatic, detectAnomaly = cgm2_5.calibrate( DATA_PATH, calibrateFilenameLabelled, translators, settings, required_mp, optional_mp, False, leftFlatFoot, rightFlatFoot, headFlat, markerDiameter, hjcMethod, pointSuffix, anomalyException=anomalyException) LOGGER.logger.info("----- CALIBRATION- static file [%s]-----> DONE" % (calibrateFilenameLabelled)) # --------------------------MODEL FITTING ---------------------------------- LOGGER.logger.info( "--------------------------MODEL FITTING ----------------------------------" ) dynamicMeasurements = qtmTools.findDynamic(sessionXML) ik_flag = True modelledC3ds = list() eventInspectorStates = list() for dynamicMeasurement in dynamicMeasurements: reconstructFilenameLabelled = qtmTools.getFilename(dynamicMeasurement) LOGGER.logger.info("----Processing of [%s]-----" % (reconstructFilenameLabelled)) mfpa = qtmTools.getForcePlateAssigment(dynamicMeasurement) momentProjection_text = sessionXML.Moment_Projection.text if momentProjection_text == "Default": momentProjection_text = settings["Fitting"]["Moment Projection"] if momentProjection_text == "Distal": momentProjection = enums.MomentProjection.Distal elif momentProjection_text == "Proximal": momentProjection = enums.MomentProjection.Proximal elif momentProjection_text == "Global": momentProjection = enums.MomentProjection.Global elif momentProjection_text == "JCS": momentProjection = enums.MomentProjection.JCS acq = btkTools.smartReader(DATA_PATH + reconstructFilenameLabelled) # filtering # ----------------------- # marker order_marker = int( float(dynamicMeasurement.Marker_lowpass_filter_order.text)) fc_marker = float( dynamicMeasurement.Marker_lowpass_filter_frequency.text) # force plate order_fp = int( float(dynamicMeasurement.Forceplate_lowpass_filter_order.text)) fc_fp = float( dynamicMeasurement.Forceplate_lowpass_filter_frequency.text) # ik accuracy ikAccuracy = float(dynamicMeasurement.IkAccuracy.text) if dynamicMeasurement.First_frame_to_process.text != "": vff = int(dynamicMeasurement.First_frame_to_process.text) else: vff = None if dynamicMeasurement.Last_frame_to_process.text != "": vlf = int(dynamicMeasurement.Last_frame_to_process.text) else: vlf = None # fitting operation # ----------------------- LOGGER.logger.info("[pyCGM2] --- Fitting operation ---") acqGait, detectAnomaly = cgm2_5.fitting( model, DATA_PATH, reconstructFilenameLabelled, translators, settings, ik_flag, markerDiameter, pointSuffix, mfpa, momentProjection, fc_lowPass_marker=fc_marker, order_lowPass_marker=order_marker, fc_lowPass_forcePlate=fc_fp, order_lowPass_forcePlate=order_fp, anomalyException=anomalyException, ikAccuracy=ikAccuracy, frameInit=vff, frameEnd=vlf) outFilename = reconstructFilenameLabelled btkTools.smartWriter(acqGait, str(DATA_PATH + outFilename)) modelledC3ds.append(outFilename) LOGGER.logger.info("----Processing of [%s]-----> DONE" % (reconstructFilenameLabelled)) LOGGER.logger.info( "---------------------GAIT PROCESSING -----------------------") if createPDFReport: nds = normativeDatasets.NormativeData("Schwartz2008", "Free") types = qtmTools.detectMeasurementType(sessionXML) for type in types: modelledTrials = list() for dynamicMeasurement in dynamicMeasurements: if qtmTools.isType(dynamicMeasurement, type): filename = qtmTools.getFilename(dynamicMeasurement) # event checking # ----------------------- acq = btkTools.smartReader(DATA_PATH + filename) geap = AnomalyDetectionProcedure.GaitEventAnomalyProcedure( ) adf = AnomalyFilter.AnomalyDetectionFilter( acq, filename, geap) anomaly_events = adf.run() if anomaly_events["ErrorState"]: detectAnomaly = True LOGGER.logger.warning( "file [%s] not used for generating the gait report. bad gait event detected" % (filename)) else: modelledTrials.append(filename) try: report.pdfGaitReport(DATA_PATH, model, modelledTrials, nds, pointSuffix, title=type) LOGGER.logger.error("Generation of Gait report complete") except: LOGGER.logger.error("Generation of Gait report failed") LOGGER.logger.info( "-------------------------------------------------------") if detectAnomaly: LOGGER.logger.error( "Anomalies has been detected - Find Error messages, then check warning message in the log file" ) else: LOGGER.logger.info("workflow return with no detected anomalies")
def main(sessionFilename, createPDFReport=True): logging.info("------------------------------------------------") logging.info("------------QTM - pyCGM2 Workflow---------------") logging.info("------------------------------------------------") sessionXML = files.readXml(os.getcwd() + "\\", sessionFilename) sessionDate = files.getFileCreationDate(os.getcwd() + "\\" + sessionFilename) #--------------------------------------------------------------------------- #management of the Processed folder DATA_PATH = os.getcwd() + "\\" + "processed\\" files.createDir(DATA_PATH) staticMeasurement = qtmTools.findStatic(sessionXML) calibrateFilenameLabelled = qtmTools.getFilename(staticMeasurement) if not os.path.isfile(DATA_PATH + calibrateFilenameLabelled): shutil.copyfile(os.getcwd() + "\\" + calibrateFilenameLabelled, DATA_PATH + calibrateFilenameLabelled) logging.info( "qualisys exported c3d file [%s] copied to processed folder" % (calibrateFilenameLabelled)) dynamicMeasurements = qtmTools.findDynamic(sessionXML) for dynamicMeasurement in dynamicMeasurements: reconstructFilenameLabelled = qtmTools.getFilename(dynamicMeasurement) if not os.path.isfile(DATA_PATH + reconstructFilenameLabelled): shutil.copyfile(os.getcwd() + "\\" + reconstructFilenameLabelled, DATA_PATH + reconstructFilenameLabelled) logging.info( "qualisys exported c3d file [%s] copied to processed folder" % (reconstructFilenameLabelled)) acq = btkTools.smartReader( str(DATA_PATH + reconstructFilenameLabelled)) acq, zeniState = eventDetector.zeni(acq) if zeniState: btkTools.smartWriter( acq, str(DATA_PATH + reconstructFilenameLabelled)) cmd = "Mokka.exe \"%s\"" % (str(DATA_PATH + reconstructFilenameLabelled)) os.system(cmd) # --------------------------GLOBAL SETTINGS ------------------------------------ # global setting ( in user/AppData) if os.path.isfile(pyCGM2.PYCGM2_APPDATA_PATH + "CGM2_3-pyCGM2.settings"): settings = files.openFile(pyCGM2.PYCGM2_APPDATA_PATH, "CGM2_3-pyCGM2.settings") else: settings = files.openFile(pyCGM2.PYCGM2_SETTINGS_FOLDER, "CGM2_3-pyCGM2.settings") # --------------------------MP ------------------------------------ required_mp, optional_mp = qtmTools.SubjectMp(sessionXML) # --Check MP inspectprocedure = inspectProcedures.AnthropometricDataQualityProcedure( required_mp) inspector = inspectFilters.QualityFilter(inspectprocedure) inspector.run() # translators management translators = files.getTranslators(os.getcwd() + "\\", "CGM2_3.translators") if not translators: translators = settings["Translators"] # ikweight ikWeight = files.getIKweightSet(DATA_PATH, "CGM2_3.ikw") if not ikWeight: ikWeight = settings["Fitting"]["Weight"] # --------------------------MODEL CALIBRATION ----------------------- logging.info( "--------------------------MODEL CALIBRATION -----------------------") staticMeasurement = qtmTools.findStatic(sessionXML) calibrateFilenameLabelled = qtmTools.getFilename(staticMeasurement) logging.info("----- CALIBRATION- static file [%s]--" % (calibrateFilenameLabelled)) leftFlatFoot = utils.toBool( sessionXML.Left_foot_normalised_to_static_trial.text) rightFlatFoot = utils.toBool( sessionXML.Right_foot_normalised_to_static_trial.text) headFlat = utils.toBool(sessionXML.Head_normalised_to_static_trial.text) markerDiameter = float(sessionXML.Marker_diameter.text) * 1000.0 hjcMethod = settings["Calibration"]["HJC"] pointSuffix = None # Calibration checking # -------------------- acqStatic = btkTools.smartReader(DATA_PATH + calibrateFilenameLabelled) for key in MARKERSETS.keys(): logging.info("[pyCGM2] Checking of the %s" % (key)) # presence ip_presence = inspectProcedures.MarkerPresenceQualityProcedure( acqStatic, markers=MARKERSETS[key]) inspector = inspectFilters.QualityFilter(ip_presence) inspector.run() if ip_presence.markersIn != []: ip_gap = inspectProcedures.GapQualityProcedure( acqStatic, markers=ip_presence.markersIn) inspector = inspectFilters.QualityFilter(ip_gap) inspector.run() ip_swap = inspectProcedures.SwappingMarkerQualityProcedure( acqStatic, markers=ip_presence.markersIn) inspector = inspectFilters.QualityFilter(ip_swap) inspector.run() ip_pos = inspectProcedures.MarkerPositionQualityProcedure( acqStatic, markers=ip_presence.markersIn) inspector = inspectFilters.QualityFilter(ip_pos) # Calibration operation # -------------------- logging.info("[pyCGM2] --- calibration operation ---") model, acqStatic = cgm2_3.calibrate(DATA_PATH, calibrateFilenameLabelled, translators, settings, required_mp, optional_mp, False, leftFlatFoot, rightFlatFoot, headFlat, markerDiameter, hjcMethod, pointSuffix) logging.info("----- CALIBRATION- static file [%s]-----> DONE" % (calibrateFilenameLabelled)) # --------------------------MODEL FITTING ---------------------------------- logging.info( "--------------------------MODEL FITTING ----------------------------------" ) dynamicMeasurements = qtmTools.findDynamic(sessionXML) ik_flag = True modelledC3ds = list() eventInspectorStates = list() for dynamicMeasurement in dynamicMeasurements: # reconstructFilenameLabelled = qtmTools.getFilename(dynamicMeasurement) reconstructFilenameLabelled = qtmTools.getFilename(dynamicMeasurement) logging.info("----Processing of [%s]-----" % (reconstructFilenameLabelled)) mfpa = qtmTools.getForcePlateAssigment(dynamicMeasurement) momentProjection_text = sessionXML.Moment_Projection.text if momentProjection_text == "Default": momentProjection_text = settings["Fitting"]["Moment Projection"] if momentProjection_text == "Distal": momentProjection = enums.MomentProjection.Distal elif momentProjection_text == "Proximal": momentProjection = enums.MomentProjection.Proximal elif momentProjection_text == "Global": momentProjection = enums.MomentProjection.Global elif momentProjection_text == "JCS": momentProjection = enums.MomentProjection.JCS acq = btkTools.smartReader(DATA_PATH + reconstructFilenameLabelled) # Fitting checking # -------------------- for key in MARKERSETS.keys(): if key != "Calibration markers": logging.info("[pyCGM2] Checking of the %s" % (key)) # presence ip_presence = inspectProcedures.MarkerPresenceQualityProcedure( acq, markers=MARKERSETS[key]) inspector = inspectFilters.QualityFilter(ip_presence) inspector.run() if ip_presence.markersIn != []: ip_gap = inspectProcedures.GapQualityProcedure( acq, markers=ip_presence.markersIn) inspector = inspectFilters.QualityFilter(ip_gap) inspector.run() ip_swap = inspectProcedures.SwappingMarkerQualityProcedure( acq, markers=ip_presence.markersIn) inspector = inspectFilters.QualityFilter(ip_swap) inspector.run() ip_pos = inspectProcedures.MarkerPositionQualityProcedure( acq, markers=ip_presence.markersIn) inspector = inspectFilters.QualityFilter(ip_pos) # filtering # ----------------------- # marker order_marker = int( float(dynamicMeasurement.Marker_lowpass_filter_order.text)) fc_marker = float( dynamicMeasurement.Marker_lowpass_filter_frequency.text) # force plate order_fp = int( float(dynamicMeasurement.Forceplate_lowpass_filter_order.text)) fc_fp = float( dynamicMeasurement.Forceplate_lowpass_filter_frequency.text) # event checking # ----------------------- inspectprocedureEvents = inspectProcedures.GaitEventQualityProcedure( acq) inspector = inspectFilters.QualityFilter(inspectprocedureEvents) inspector.run() eventInspectorStates.append(inspectprocedureEvents.state) # fitting operation # ----------------------- logging.info("[pyCGM2] --- Fitting operation ---") acqGait = cgm2_3.fitting(model, DATA_PATH, reconstructFilenameLabelled, translators, settings, ik_flag, markerDiameter, pointSuffix, mfpa, momentProjection, fc_lowPass_marker=fc_marker, order_lowPass_marker=order_marker, fc_lowPass_forcePlate=fc_fp, order_lowPass_forcePlate=order_fp) outFilename = reconstructFilenameLabelled btkTools.smartWriter(acqGait, str(DATA_PATH + outFilename)) modelledC3ds.append(outFilename) logging.info("----Processing of [%s]-----> DONE" % (reconstructFilenameLabelled)) # --------------------------GAIT PROCESSING ----------------------- if not all(eventInspectorStates): raise Exception( "[pyCGM2] Impossible to run Gait processing. Badly gait event detection. check the log file" ) logging.info( "---------------------GAIT PROCESSING -----------------------") if createPDFReport: nds = normativeDatasets.Schwartz2008("Free") types = qtmTools.detectMeasurementType(sessionXML) for type in types: modelledTrials = list() for dynamicMeasurement in dynamicMeasurements: if qtmTools.isType(dynamicMeasurement, type): filename = qtmTools.getFilename(dynamicMeasurement) modelledTrials.append(filename) report.pdfGaitReport(DATA_PATH, model, modelledTrials, nds, pointSuffix, title=type) logging.info("----- Gait Processing -----> DONE")