def test_update(self): ini_service = InitialService() conn = ini_service.get_connection() instance_service = InstanceService(conn) try: instance_service.insert("Stroke Annotation-update1", "CT", "Stroke annotation descriptions.", "./data/stroke_instance-update1", 0, 50, 10, 0) except Error: pass last_rowid = instance_service.query({"name": "Stroke Annotation-update1"})[0]["instance_id"] labelcandidates_service = LabelCandidatesService(conn) labelcandidates_service.insert(last_rowid, 0, None, "Ischemic Stroke-update1") status = labelcandidates_service.update({"instance_id": last_rowid}, {"text": "Ischemic Stroke-update2", "label_type": 1}) update_item = labelcandidates_service.query({"instance_id": last_rowid}) assert status is True assert update_item[0]["text"] == "Ischemic Stroke-update2" status = labelcandidates_service.update({"instance_id": 1000}, {"text": "Ischemic Stroke-update2", "label_type": 1}) assert status is False
def test_delete(self): ini_service = InitialService() conn = ini_service.get_connection() instance_service = InstanceService(conn) # In case the record doesn't exist. try: instance_service.insert("Stroke Annotation-del1", "CT", "Stroke annotation descriptions.", "./data/stroke_instance-del1", 0, 50, 10, 0) except Error: pass last_rowid = instance_service.query({"name": "Stroke Annotation-del1"})[0]["instance_id"] labelcandidates_service = LabelCandidatesService(conn) labelcandidates_service.insert(last_rowid, 0, None, "Ischemic Stroke") candidate_id = labelcandidates_service.query({"text": "Ischemic Stroke", "instance_id": last_rowid})[0][ "candidate_id"] status = labelcandidates_service.delete({"candidate_id": candidate_id}) assert status is True labelcandidates_service.insert(last_rowid, 0, None, "Ischemic Stroke") candidate_id = labelcandidates_service.query({"text": "Ischemic Stroke", "instance_id": last_rowid}) status = labelcandidates_service.delete({"text": "Ischemic Stroke", "instance_id": last_rowid}) assert status is True status = labelcandidates_service.delete({"text": "Ischemic Stroke", "instance_id": last_rowid}) assert status is False
def test_create(self): ini_service = InitialService() conn = ini_service.get_connection() labelcandidates_service = LabelCandidatesService(conn) insert_status = labelcandidates_service.insert(1, 0, None, "Ischemic Stroke") assert insert_status is False instance_service = InstanceService(conn) instance_service.insert("Stroke annotation", "CT", "description...", "./data/stroke_data", 0, 100, 10, 0) last_rowid = instance_service.query({"name": "Stroke annotation"})[0]["instance_id"] insert_rowid = labelcandidates_service.insert(last_rowid, 0, None, "Ischemic Stroke") assert insert_rowid == 1
def test_query_one_record(self): ini_service = InitialService() conn = ini_service.get_connection() instance_service = InstanceService(conn) labelcandidates_service = LabelCandidatesService(conn) # In case the record doesn't exist. try: instance_service.insert("Stroke annotation", "CT", "Stroke annotation descriptions.", "./data/stroke_data", 0, 50, 10, 0) except Error: print(Error) pass last_rowid = instance_service.query({"name": "Stroke annotation"})[0]["instance_id"] labelcandidates_service.insert(last_rowid, 0, None, "Ischemic Stroke") result = labelcandidates_service.query({"instance_id": last_rowid}) assert result[0]["text"] == "Ischemic Stroke"
def test_instance_detail_delete(self, client): ini_service = InitialService() conn = ini_service.get_connection() instance_service = InstanceService(conn) instance_id = instance_service.insert( "Stroke Annotation Task2", "CT", "The stroke CT scans for annotation tasks.", "tests/services/sample_data", 0, 200, 1, 0) res = client.delete(url_for('instance_detail', instance_id=instance_id)) assert res.json == {} assert res.status == "200 OK" res = client.delete(url_for('instance_detail', instance_id=instance_id)) assert res.json == {} assert res.status == "404 NOT FOUND"
def test_list_all_studies(self, client): res = client.get(url_for('list_all_studies', instance_id=1)) assert res.json == {} assert res.status == '200 OK' # Setup studies sample data ini_service = InitialService() conn = ini_service.get_connection() instance_service = InstanceService(conn) instance_service.insert("Stroke Annotation Task", "CT", "The stroke CT scans for annotation tasks.", "tests/services/sample_data", 0, 200, 1, 0) result = instance_service.query({}) assert result[0]["instance_id"] == 1 assert result[0]["name"] == "Stroke Annotation Task" studies_service = StudiesService(conn) studies_service.insert(1, "Dicom_691_2", 25, 0, "folder", 100, 1) studies_service.insert(1, "Raw_1003/3CH_tagging", 30, 1, "folder", 100, 1) series_service = SeriesService(conn) series_service.insert(1, "series1", "series1/path", ["1"], 1, "200", "200", "0.5", "0.5", "0.5", 512, 512, 512, 1, 100101, "", "", "") series_service.insert(1, "series2", "series2/path", ["1"], 1, "200", "200", "0.5", "0.5", "0.5", 512, 512, 512, 1, 100101, "", "", "") series_service.insert(2, "series3", "series3/path", ["1"], 1, "200", "200", "0.5", "0.5", "0.5", 512, 512, 512, 1, 100101, "", "", "") series_service.insert(2, "series4", "series4/path", ["1"], 1, "200", "200", "0.5", "0.5", "0.5", 512, 512, 512, 1, 100101, "", "", "") res = client.get(url_for('list_all_studies', instance_id=1)) assert len(res.json[0]) == 2 assert res.json[0][0]["instance_id"] == 1 assert res.json[0][0]["patient_uid"] == "Dicom_691_2" assert res.json[1][0]["instance_id"] == 1 assert res.json[1][0]["patient_uid"] == "Raw_1003/3CH_tagging" assert res.status == '200 OK'
def add_labels(series_id, file_name): # Temporary mock the user Id. user_id = 1 data = request.data label_service = LabelService(get_conn()) status = label_service.insert(series_id, user_id, file_name, data) update_status = request.args.get('update_status', type=bool, default=False) if update_status: series_service = SeriesService(get_conn()) study_service = StudiesService(get_conn()) instance_service = InstanceService(get_conn()) series = series_service.query({'series_id': series_id}) if len(series) > 0: study_id = series[0]['study_id'] status = series[0]['status'] if status < SERIES_STATUS.annotating.value: series_service.update( {'series_id': series_id}, {'status': SERIES_STATUS.annotating.value}) study = study_service.query({'study_id': study_id}) instance_id = study[0]['instance_id'] if study[0]['status'] != STUDY_STATUS.annotating.value: study_service.update( {'study_id': study_id}, {'status': STUDY_STATUS.annotating.value}) instance = instance_service.query({'instance_id': instance_id}) if instance[0]['status'] != INSTANCE_STATUS.annotating.value: instance_service.update( {'instance_id': instance_id}, {'status': INSTANCE_STATUS.annotating.value}) if status: return jsonify({}), 201 else: return jsonify({status: "Transaction Rollback."}), 404
def insert(self, instance_id, label_type, input_type, text, contour_label_value=-1): """ Insert new record for LabelCandidates. :param instance_id: :param label_type: :param input_type: :param text: :param contour_label_value: id for contour label. -1 for default self-increasing id. :return: """ instance_service = InstanceService(self.sql_connection) if len(instance_service.query({"instance_id": instance_id})) == 0: # There is no such instance ID. return False cur = self.sql_connection.cursor() sql, v = prepare_insert("label_candidates", {"instance_id": instance_id, "label_type": label_type, "input_type": input_type, "text": text, "contour_label_value": contour_label_value}) cur.execute(sql, v) self.sql_connection.commit() return cur.lastrowid
def instance_list(): instance_service = InstanceService(get_conn()) label_candidates_service = LabelCandidatesService(get_conn()) if request.method == "GET": instances = instance_service.query({}) return jsonify(instances), 200 elif request.method == "POST": data = json.loads(request.data) name = data.get("name", "New instance") modality = data.get("modality", "CT") description = data.get("description", "") data_path = "" # Set the data_path as default now. has_audit = False annotator_id = list( filter(None, str.split(data.get("annotator_id", ""), "|"))) auditor_id = list( filter(None, str.split(data.get("auditor_id", ""), "|"))) label_candidates = data.get("label_candidates", []) instance_id = instance_service.insert(name, modality, description, data_path, has_audit, 0, 0, INSTANCE_STATUS.init.value) if instance_id == -1: # Instance name already exist. return jsonify({"err": "Instance Name exist"}), 409 for user_id in annotator_id: instance_service.insert_user_in_instance( instance_id, user_id, False) for user_id in auditor_id: instance_service.insert_user_in_instance( instance_id, user_id, True) for label in label_candidates: label_type = int(label['label_type']) input_type = int(label['input_type']) text = label['text'] contour_label_value = label['contour_label_value'] label_candidates_service.insert(instance_id, label_type, input_type, text, contour_label_value) return jsonify({"instance_id": instance_id}), 201
def import_dcm(self, instance_id, data_path): instance_service = InstanceService(self.conn) instance_service.update({'instance_id': instance_id}, {'status': INSTANCE_STATUS.importing_dicom.value}) series_extraction_service = SeriesExtractionService() all_series_list = series_extraction_service.extract_series_from_path(os.path.join(DATA_ROOT, data_path)) study_service = StudiesService(self.conn) series_service = SeriesService(self.conn) for suid in all_series_list: series = all_series_list[suid] patient_uid = 0 study_uid = 0 study_service.insert(instance_id, patient_uid, study_uid, suid, "[]", 0, 0) study = study_service.query({"instance_id": instance_id, "suid": suid}) study = study[0] total_files_number = 0 folder_name_arr = [] for series_path in series: folder_name_arr.append(series_path) one_series = series[series_path][0] patient_uid = one_series.info.PatientID study_uid = one_series.info.StudyID if patient_uid == "" or study_uid == "": patient_uid = "" study_uid = suid # disp_name = "pid:" + one_series.info.PatientID + "_sid:" + one_series.info.StudyID total_files_number += one_series.length series_info = one_series.info if len(one_series.shape) == 2: z_dim = 1 x_dim = one_series.shape[0] y_dim = one_series.shape[1] else: z_dim = one_series.shape[0] x_dim = one_series.shape[1] y_dim = one_series.shape[2] series_service.insert(study['study_id'], one_series.description, series_path, one_series.filenames, one_series.length, series_info.get("WindowWidth"), series_info.get("WindowCenter"), one_series.sampling[1], one_series.sampling[1], one_series.sampling[0], x_dim, y_dim, z_dim, series_info.get("PatientID"), series_info.get("SeriesInstanceUID"), series_info.get("StudyDate") or "", "", "", SERIES_STATUS.init.value) study_service.update({"instance_id": instance_id, "suid": suid}, {"total_files_number": total_files_number, "patient_uid": patient_uid, "study_uid": study_uid, "folder_name": str(folder_name_arr), "status": STUDY_STATUS.ready_to_annotate.value}) instance_service.update({'instance_id': instance_id}, {'status': INSTANCE_STATUS.ready_to_annotate.value}) return True
def instance_detail(instance_id): """ [POST] /instance/<instance_id> name, modality, description, annotator_ids(split by vbar), auditor_ids, label_candidates: :return: """ instance_service = InstanceService(get_conn()) label_candidates_service = LabelCandidatesService(get_conn()) if request.method == "GET": instance_info = instance_service.query( {"instance_id": instance_id}) if len(instance_info) == 0: return jsonify({}), 200 label_candidate_service = LabelCandidatesService(get_conn()) label_candidates = label_candidate_service.query( {"instance_id": instance_id}) json_result = instance_info[0] json_result['label_candidates'] = label_candidates return jsonify(json_result), 200 elif request.method == "DELETE": status = instance_service.delete({"instance_id": instance_id}) instance_service.delete_all_users_in_instance(instance_id) label_candidates_service.delete({"instance_id": instance_id}) if status: return jsonify({}), 200 else: return jsonify({}), 404 elif request.method == "PUT": instance_info = instance_service.query( {"instance_id": instance_id}) if len(instance_info) == 0: return jsonify({}), 200 data = json.loads(request.data) name = data.get("name", "New instance") modality = data.get("modality", "CT") description = data.get("description", "") # data_path = "" # Set the data_path as default now. has_audit = False annotator_id = list( filter(None, str.split(data.get("annotator_id", ""), "|"))) auditor_id = list( filter(None, str.split(data.get("auditor_id", ""), "|"))) label_candidates = data.get("label_candidates", []) instance_service.update({"instance_id": instance_id}, { "name": name, "modality": modality, "description": description, "has_audit": has_audit }) instance_service.delete_all_users_in_instance(instance_id) for user_id in annotator_id: instance_service.insert_user_in_instance( instance_id, user_id, False) for user_id in auditor_id: instance_service.insert_user_in_instance( instance_id, user_id, True) # Delete all label candidates for current instance and add again. label_candidates_service.delete({"instance_id": instance_id}) for label in label_candidates: label_type = int(label['label_type']) input_type = int(label['input_type']) text = label['text'] contour_label_value = label['contour_label_value'] label_candidates_service.insert(instance_id, label_type, input_type, text, contour_label_value) return jsonify({"instance_id": instance_id}), 201
def save_studies(self, instance_id, split_entry_num=100, start_idx=0, end_idx=-1, store_type="train", save_pair=True, save_label=True, save_data=True, compression=None): """ Save all annotations and and dicom data for each study in the instance. :param instance_id: :param split_entry_num: create new h5 file if stored entries more than the max split number :param start_idx: start file number. :param end_idx: end of the file number. :param store_type: train or test :param save_pair: True or False. If save the pair, will only save the series which have labels. :param save_label: True or False :param save_data: True or False :param compression: Whether the hdf5 file compressed or not. "gzip|lzf" :return: """ msg_box = [] instance_service = InstanceService(self.conn) instance = instance_service.query({"instance_id": instance_id}) instance_name = instance[0]['name'] study_service = StudiesService(self.conn) studies = study_service.query({"instance_id": instance_id}) study_num = split_entry_num * start_idx if end_idx == -1: end_num = len(studies) else: end_num = split_entry_num * end_idx study_h5 = None time_stamp = str(int(time.time())) for idx, study in enumerate(studies): if idx == study_num and idx < end_num: study_id = study['study_id'] app.logger.info( f"Save study-instance_id:{instance_id}({instance_name}),study_id:{study_id}" ) h5_path = os.path.join(OUTPUT_ROOT, str(instance_id)) if study_num % split_entry_num == 0: if not os.path.exists(h5_path): os.makedirs(h5_path) if study_h5 is not None: study_h5.close() h5_file_name = f"Export-{instance_id}-{instance_name}-{time_stamp}-{study_num // split_entry_num}.h5" study_h5 = h5py.File(os.path.join(h5_path, h5_file_name), 'w') if save_pair: _, saved_label, _ = self.save_onestudy_label( study_id, study, study_h5, msg_box, store_type, compression) self.save_onestudy_dcm(study_id, study, study_h5, msg_box, store_type, compression, saved_label) else: if save_label: self.save_onestudy_label(study_id, study, study_h5, msg_box, store_type, compression) if save_data: self.save_onestudy_dcm(study_id, study, study_h5, msg_box, store_type, compression) study_num += 1 study_h5.close() return msg_box