def generalfix_TrailingNulls(ds: Dataset, log: list) -> bool: fixed = False elemsTobeCorrected = [] for key, a in ds.items(): a = ds[key] if key.is_private: continue if a.VR == 'UI' or a.VR == 'OB' or a.VR == 'OW' or a.VR == 'UN': continue if type(a) == pydicom.dataelem.RawDataElement: a = pydicom.dataelem.DataElement_from_raw(a) if type(a.value) == Sequence: for item in a.value: fixed = fixed or generalfix_TrailingNulls(item, log) elif type(a.value) == Dataset: fixed = fixed or generalfix_TrailingNulls(a.value, log) else: partial_fixed = subfix_HasTrailingNulls(a) if partial_fixed: msg = mesgtext_cc.ErrorInfo("<{}> {}".format( a.description(), validate_vr.tag2str(a.tag))) err = "<{}> {}".format(a.description(), validate_vr.tag2str(a.tag)) msg = mesgtext_cc.ErrorInfo( "General Fix - Trailing null bytesz", "fixed by removing the trailing null bytes for {}".format( err)) log.append(msg.getWholeMessage()) elemsTobeCorrected.append(a) fixed = True return fixed
def subfix_ReplaceSlashWithBackslash(attrib: DataElement, log: list) -> bool: fixed = False msg = mesgtext_cc.ErrorInfo('General Fix -', '') fix = 'fixed attribute <{}> ({}) value by changing slash to backslash {} -> {}' if type(attrib.value) == MultiValue: tmp = attrib.value else: tmp = [attrib.value] for idx in range(0, len(tmp)): old_val = tmp[idx] if type(tmp[idx]) == str: tmp[idx] = tmp[idx].replace('/', '\\') elif type(tmp[idx]) == bytes: x = bytearray() for elem in tmp[idx]: if elem == ord('/'): x.append(ord('\\')) else: x.append(elem) tmp[idx] = bytes(x) if old_val != tmp[idx]: msg.fix = fix.format(attrib.name, idx + 1, old_val, tmp[idx]) log.append(msg.getWholeMessage()) fixed = True if type(attrib.value) != MultiValue: attrib.value = tmp[0] return fixed
def subfix_AddOrChangeAttrib(ds: Dataset, log: list, error_regexp: str, fix_message: str, keyword: str, value) -> bool: fixed = False t = Dictionary.tag_for_keyword(keyword) if t is None: return False desc = Dictionary.dictionary_description(t) ErrorOccured = False log_l = len(log) for i in range(0, log_l): if re.match(error_regexp, log[i]) is not None: msg = mesgtext_cc.ErrorInfo(log[i], fix_message) log[i] = msg.getWholeMessage() ErrorOccured = True if ErrorOccured: if keyword in ds: ds[keyword].value = value # just modify fixed = True else: vr = Dictionary.dictionary_VR(t) vm = 1 elem = DataElement(t, vr, value) ds[keyword] = elem fixed = True return fixed
def fix_VRForLongitudinalTemporalInformationModified(ds: Dataset, log: list) -> bool: fixed = False msg = mesgtext_cc.ErrorInfo() kw = "LongitudinalTemporalInformationModified" Error_regex = ".*Invalid Value Representation SH \(CS Required\)" \ ".*{}.*".format(kw) idx = subfix_LookUpRegexInLog(Error_regex, log) if len(idx) == 0: idx.append(-1) log.append("Error - bad VR for {}".format(kw)) if kw in ds: tag = Dictionary.tag_for_keyword(kw) if ds[tag].VR == "SH": ds[tag].VR = "CS" for i in idx: msg.msg = log[i] msg.fix = "fixed by editing SH to CS" msg1 = msg.getWholeMessage() log[i] = msg1 fixed = True return fixed
def generalfix_RemoveUnwanterPixelAspctRatio(ds: Dataset, log: list) -> bool: fixed = False kw = "PixelAspectRatio" is_one_to_one = False if kw in ds: elem = ds[kw] if type(elem) == MultiValue: if len(elem) == 2: is_one_to_one = (elem.value[0] == elem.value[2]) if (Condition_UnwantedPixelAspectRatioWhenPixelSpacingPresent( ds, ds, ds ) or Condition_UnwantedPixelAspectRatioWhenImagerPixelSpacingPresent( ds, ds, ds ) or Condition_UnwantedPixelAspectRatioWhenNominalScannedPixelSpacingPresent( ds, ds, ds ) or Condition_UnwantedPixelAspectRatioWhenSharedPixelMeasuresMacro( ds, ds, ds ) or Condition_UnwantedPixelAspectRatioWhenPerFramePixelMeasuresMacro( ds, ds, ds) or Condition_UnwantedPixelAspectRatioWhenMPEG2MPHLTransferSyntax( ds, ds, ds) or is_one_to_one): msg = mesgtext_cc.ErrorInfo() msg.msg = '{} Error - {}'.format( ErrorType.BadValue.value, "<PixelAspectRatio> is 1:1 or redundant") msg.fix = "fixed by removing the attribute" log.append(msg.getWholeMessage()) del ds["PixelAspectRatio"] fixed = True return fixed
def LoopOverAllAtribsAndRemoveIfConditionIsTrue(ds: Dataset, cond, log: list, err='') -> bool: fixed = False elements_to_be_removed = [] for key, a in ds.items(): a = ds[key] if type(a) == pydicom.dataelem.RawDataElement: a = pydicom.dataelem.DataElement_from_raw(a) if type(a.value) == Sequence: for item in a.value: fixed = fixed or LoopOverAllAtribsAndRemoveIfConditionIsTrue( item, cond, log, err) elif type(a.value) == Dataset: fixed = fixed or LoopOverAllAtribsAndRemoveIfConditionIsTrue( a.value, cond, log, err) else: if cond(a): ttaagg = validate_vr.tag2str(a.tag) attrib = "<{}> -> {}".format(a.keyword, ttaagg) tmperr = err.format(attrib) msg = mesgtext_cc.ErrorInfo() msg.msg = tmperr msg.fix = "fixed by removing the attribute" log.append(msg.getWholeMessage()) fixed = True elements_to_be_removed.append(a.tag) for tg in elements_to_be_removed: del ds[tg] return fixed
def fix_PatientPositionAndPatientOrientationCodeSequencePresent( ds: Dataset, log: list) -> bool: code_kws = [ 'CodeValue', "CodeMeaning", "CodingSchemeDesignator", "LongCodeValue", "URNCodeValue", "CodingSchemeVersion" ] msg = mesgtext_cc.ErrorInfo() fixed = False pp = 'PatientPosition' posq = 'PatientOrientationCodeSequence' Error_regex = ".*May not be present when {} is present.*{}.*".format( posq, pp) if posq in ds: if pp in ds: seq_elem = ds[posq] idx = subfix_LookUpRegexInLog(Error_regex, log) txt = subfix_CodeSeqItem2txt(seq_elem, 0) if len(idx) == 0: idx.append(-1) log.append("{} = {} and {} both are present".format( pp, ds[pp].value, txt)) for i in idx: msg.msg = log[i] if len(seq_elem.value) > 0: msg.fix = "kept {} but removed {}".format(txt, pp) del ds[pp] else: msg.fix = "kept {} but removed {}".format(pp, txt) del ds[posq] log[i] = msg.getWholeMessage() fixed = True return fixed
def priorfix_RemoveIllegalTags(ds: Dataset, parent_kw: str, log: list) -> bool: tags_to_be_removed = [] fixed = False for k, a in ds.items(): try: a = ds[k] except KeyError as err: if not k.is_private: if not Dictionary.dictionary_has_tag(k): ttaagg = validate_vr.tag2str(a.tag) eerr = mesgtext_cc.ErrorInfo( "General Fix - tag {} in {}is not a standard dicom tag" .format(ttaagg, parent_kw), 'fixed by removing the attribute') log.append(eerr.getWholeMessage()) tags_to_be_removed.append(a.tag) continue if type(a.value) == Sequence: for item in a.value: fixed = fixed or priorfix_RemoveIllegalTags( item, a.keyword, log) elif type(a.value) == Dataset: fixed = fixed or priorfix_RemoveIllegalTags( a.value, a.keyword, log) for tg in tags_to_be_removed: del ds[tg] return fixed
def fix_RemoveFOVDimensionsWhenZero(ds: Dataset, log: list) -> bool: fixed = False kw = "FieldOfViewDimensions" Error_regex = ".*Value is zero for.*attribute.*Field.*View.*Dimension.*" msg = mesgtext_cc.ErrorInfo() idx = subfix_LookUpRegexInLog(Error_regex, log) if len(idx) == 0: idx.append(-1) log.append("Error - bad value (=0) for {}".format(kw)) if kw in ds: tag = Dictionary.tag_for_keyword(kw) elem = ds[tag] for i in elem.value: if i == 0: fixed = True break if fixed: del ds[kw] for i in idx: msg.msg = log[i] msg.fix = "fixed by removing the attribute" msg1 = msg.getWholeMessage() log[i] = msg1 return fixed
def fix_BitsAllocated8ToBitsAllocated16(ds: Dataset, log: list): log_l = len(log) ErrorPattern = "Error - Unrecognized enumerated value <{}> for value 1 of " \ "attribute {} BinaryValueDescription_BitsAre{}" convert = False for i in range(0, log_l): if log[i] == ErrorPattern.format(8, "Bits Allocated", 16) or\ log[i] == ErrorPattern.format(8, "Bits Stored", 16) or\ log[i] == ErrorPattern.format(7, "High Bit", 15) : x = "fixed by conversion of PixelData to 16 bits" msg = mesgtext_cc.ErrorInfo(log[i], x) log[i] += msg.getWholeMessage() convert = True if convert: subfix_ConvertImageData16(ds, log)
def subfix_checkandfixBasicCodeSeq(seqelem: DataElement, log: list) -> bool: fixed = False msg = mesgtext_cc.ErrorInfo("General Fix - Remove empty code seq ") items_to_be_deleted = [] text_fun = lambda ds, att: '{}: <{}>\t'.format(att, ds[att].value) subfix_UpdateSRTCodes(seqelem, log) for i, item in enumerate(seqelem.value, 1): hasCodeValue = True if "CodeValue" in item else False emptyCodeValue = True if not hasCodeValue else item[ "CodeValue"].is_empty textCodeValue = '' if not hasCodeValue else text_fun(item, "CodeValue") hasCodeMeaning = True if "CodeMeaning" in item else False emptyCodeMeaning = True if not hasCodeMeaning else item[ "CodeMeaning"].is_empty textCodeMeaning = '' if not hasCodeMeaning else text_fun( item, "CodeMeaning") hasLongCodeValue = True if "LongCodeValue" in item else False emptyLongCodeValue = True if not hasLongCodeValue else item[ "LongCodeValue"].is_empty textLongCodeValue = '' if not hasLongCodeValue else text_fun( item, "LongCodeValue") hasURNCodeValue = True if "URNCodeValue" in item else False emptyURNCodeValue = True if not hasURNCodeValue else item[ "CodURNCodeValue"].is_empty textURNCodeValue = '' if not hasURNCodeValue else text_fun( item, "CodURNCodeValue") hasCodingSchemeDesignator = True if "CodingSchemeDesignator" in item else False emptyCodingSchemeDesignator = True if not hasCodingSchemeDesignator else item[ "CodingSchemeDesignator"].is_empty textCodingSchemeDesignator = '' if not hasCodingSchemeDesignator else text_fun( item, "CodingSchemeDesignator") hasCodingSchemeVersion = True if "CodingSchemeVersion" in item else False emptyCodingSchemeVersion = True if not hasCodingSchemeVersion else item[ "CodingSchemeVersion"].is_empty textCodingSchemeVersion = '' if not hasCodingSchemeVersion else text_fun( item, "CodingSchemeVersion") hasCodeValue = hasCodeValue or hasLongCodeValue or hasURNCodeValue emptyCodeValue = not (not emptyCodeValue or not emptyLongCodeValue or not emptyURNCodeValue) textCodeValue = (textCodeValue + textLongCodeValue + textURNCodeValue) bit_code = numpy.uint8(0) if emptyCodeValue: bit_code = bit_code | 0x1 if emptyCodeMeaning: bit_code = bit_code | 0x10 if emptyCodingSchemeDesignator: bit_code = bit_code | 0x100 state_text = subfix_CodeSeqItem2txt(seqelem, i - 1) state_text = ". Item current value is: " + state_text if state_text != '' else '' if hasCodingSchemeVersion and emptyCodingSchemeVersion: del item["CodingSchemeVersion"] msg.fix = "Empty CodingSchemeVersion in item {} of {} was deleted".format( i, seqelem.name) + state_text del_msg = msg.getWholeMessage() log.append(del_msg) if bit_code == 0x111 or bit_code == 0x110 or bit_code == 0x011 or \ bit_code == 0x101 or bit_code == 0x001 or bit_code == 0x010: items_to_be_deleted.append(item) msg.fix = "Item {} of {} was deleted".format(i, seqelem.keyword) del_msg = msg.getWholeMessage() log.append(del_msg) fixed = True if bit_code == 0x100: if hasCodingSchemeDesignator: item["CodingSchemeDesignator"] = '99LOCAL' msg.fix = "The value for CodingSchemeDesignator in "\ "item {} of {} was modified to 99LOCAL".format( i, seqelem.keyword ) + state_text del_msg = msg.getWholeMessage() log.append(del_msg) else: kw = "CodingSchemeDesignator" new_tag = Dictionary.tag_for_keyword(kw) new_vr = Dictionary.dictionary_VR(new_tag) new_elem = DataElement(new_tag, new_vr, "99LOCAL") item[kw] = new_elem msg.fix = "An element of CodingSchemeDesignator with value "\ "<99LOCAL> in item {} of {} was added".format( i, seqelem.keyword )+ state_text del_msg = msg.getWholeMessage() log.append(del_msg) fixed = True for el in items_to_be_deleted: seqelem.value.remove(el)
def subfix_UpdateSRTCodes(seqelem: DataElement, log: list) -> bool: fixed = False msg = mesgtext_cc.ErrorInfo( "General Fix - Upadate old snomed codes to SCT") items_to_be_deleted = [] text_fun = lambda ds, att: '{}: {}\t'.format(att, ds[att]) for i, item in enumerate(seqelem.value, 1): hasCodeValue = True if "CodeValue" in item else False emptyCodeValue = True if not hasCodeValue else item[ "CodeValue"].is_empty textCodeValue = '' if not hasCodeValue else text_fun(item, "CodeValue") hasCodeMeaning = True if "CodeMeaning" in item else False emptyCodeMeaning = True if not hasCodeMeaning else item[ "CodeMeaning"].is_empty textCodeMeaning = '' if not hasCodeMeaning else text_fun( item, "CodeMeaning") hasLongCodeValue = True if "LongCodeValue" in item else False emptyLongCodeValue = True if not hasLongCodeValue else item[ "LongCodeValue"].is_empty textLongCodeValue = '' if not hasLongCodeValue else text_fun( item, "LongCodeValue") hasURNCodeValue = True if "URNCodeValue" in item else False emptyURNCodeValue = True if not hasURNCodeValue else item[ "CodURNCodeValue"].is_empty textURNCodeValue = '' if not hasURNCodeValue else text_fun( item, "CodURNCodeValue") hasCodingSchemeDesignator = True if "CodingSchemeDesignator" in item else False emptyCodingSchemeDesignator = True if not hasCodingSchemeDesignator else item[ "CodingSchemeDesignator"].is_empty textCodingSchemeDesignator = '' if not hasCodingSchemeDesignator else text_fun( item, "CodingSchemeDesignator") hasCodingSchemeVersion = True if "CodingSchemeVersion" in item else False emptyCodingSchemeVersion = True if not hasCodingSchemeVersion else item[ "CodingSchemeVersion"].is_empty textCodingSchemeVersion = '' if not hasCodingSchemeVersion else text_fun( item, "CodingSchemeVersion") hasCodeValue = hasCodeValue or hasLongCodeValue or hasURNCodeValue emptyCodeValue = not (not emptyCodeValue or not emptyLongCodeValue or not emptyURNCodeValue) textCodeValue = (textCodeValue + textLongCodeValue + textURNCodeValue) bit_code = numpy.uint8(0) if emptyCodeValue: bit_code = bit_code | 0x1 if emptyCodeMeaning: bit_code = bit_code | 0x10 if emptyCodingSchemeDesignator: bit_code = bit_code | 0x100 state_text = subfix_CodeSeqItem2txt(seqelem, i - 1) isSRT = False if hasCodingSchemeDesignator: v = item["CodingSchemeDesignator"].value if v == "SNM3" or v == "99SDM" or v == "SRT": isSRT = True else: if hasCodeValue: v = item["CodeValue"].value if re.match("[A-Z][A-Z0-9]{0,2}-[0-9A-Z]{4,5}", v) is not None: isSRT = True if not isSRT or not hasCodeValue: return False value = item["CodeValue"].value first_dict = srt.mapping['SRT'] second_dict = sctsrt.replaced_entries replacing_value = '' if value in first_dict: replacing_value = first_dict[value] elif value in second_dict: replacingvalue = second_dict[value] if len(replacing_value) == 0: return False replacing_meaning = '' if replacing_value in sctsrt.sct_meaning: replacing_meaning = sctsrt.sct_meaning[replacing_value] msg1 = "item {} of {}:\t".format(i, seqelem.keyword) msg1 += "({}-{})".format(i, 1) + subfix_UpdateOrInsertCodeAttribute( seqelem, i - 1, "CodeValue", replacing_value) msg1 += "({}-{})".format(i, 2) + subfix_UpdateOrInsertCodeAttribute( seqelem, i - 1, "CodeMeaning", replacing_meaning) msg1 += "({}-{})".format(i, 3) + subfix_UpdateOrInsertCodeAttribute( seqelem, i - 1, "CodingSchemeDesignator", 'SCT') msg.fix = msg1 msg2 = msg.getWholeMessage() log.append(msg2) fixed = True return fixed