U Phk @sddlmZddlZddlmZmZddlmZmZddl m Z ddl m Z ddl ZddlZddlmZddlmZmZmZdd lmZmZmZmZmZmZdd lmZdd lm Z dd l!m"Z"m#Z#dd l$m%Z%ddl&m'Z'm(Z(ddl)m*Z*ddl+m,Z,m-Z-m.Z.ddl/m0Z0m1Z1ee2dZ3ddddddddddg Z4Gddde%eZ5Gddde5Z6Gddde5Z7Gd dde5Z8Gd!dde5Z9Gd"dde5Z:Gd#dde5Z;Gd$dde5ZdS)') annotationsN)ABCabstractmethod)HashableMapping)deepcopy)Any) get_logger) OperationsSampleOperationsSummaryOperations)concat_multikeys_to_dictconcat_val_to_npget_foreground_imageget_foreground_label get_label_ccpverify_report_format) ConfigParser) ID_SEP_KEY) MetaTensoraffine_to_spacing) MapTransform)sumunique)convert_to_numpy) DataStatsKeysImageStatsKeysLabelStatsKeys) ImageMetaKey label_union) module_nameAnalyzer ImageStats FgImageStats LabelStatsImageStatsSummFgImageStatsSummLabelStatsSumm FilenameStatsImageHistogramImageHistogramSummcseZdZdZddddfdd Zdddd d d Zdddd d dZddddZeddZ dddddZ e dddddZ Z S)r!a The Analyzer component is a base class. Other classes inherit this class will provide a callable with the same class name and produces one pre-formatted dictionary for the input data. The format is pre-defined by the init function of the class that inherit this base class. Function operations can also be registered before the runtime of the callable. Args: report_format: a dictionary that outlines the key structures of the report format. strdictNone) stats_name report_formatreturncs<tdt|dd}|d|_||_tidd|_dS)NF)globals)super__init__rgetr/r.ops)selfr.r/parser __class__M/home/dell461/cl/sdc2/HISourceFinder-master-l/src/monai/auto3dseg/analyzer.pyr4Fs    zAnalyzer.__init__r )keyopr0cCs<||j|<t|j}||ddkr,|||<|d|_dS)z Register a statistical operation to the Analyzer and update the report_format. Args: key: value key in the report. op: Operation sub-class object that represents statistical operations. r-r2N)r6rr/r5)r7r=r>r8r;r;r< update_opsMs  zAnalyzer.update_ops) nested_keyr>r0cCs|t}t|dkrtd|\}}}||jkr>ig|j|<|j|d|di||j|<t|j}||ddkr|||<dS)a0 Update operations for nested label format. Operation value in report_format will be resolved to a dict with only keys. Args: nested_key: str that has format of 'key1#0#key2'. op: Operation sub-class object that represents statistical operations. zFNested_key input format is wrong. Please ensure it is like key1#0#key2rNNA) splitrlen ValueErrorr6updaterr/r5)r7r@r>keysroot_Z child_keyr8r;r;r<update_ops_nested_label^s       z Analyzer.update_ops_nested_label)r0cCs||j|jS)z Get the report format by resolving the registered operations recursively. Returns: a dictionary with {keys: None} pairs. )resolve_formatr/r7r;r;r<get_report_formatws zAnalyzer.get_report_formatcCs8tt|j}t|dr4|jD]}||diq |S)a= Unwrap a function value and generates the same set keys in a dict when the function is actually called in runtime Args: func: Operation sub-class object that represents statistical operations. The func object should have a `data` dictionary which stores the statistical operation information. For some operations (ImageStats for example), it may also contain the data_addon property, which is part of the update process. Returns: a dict with a set of keys. data_addonN)r,fromkeyslistdatahasattrrNrF)funcretr=r;r;r< unwrap_opss   zAnalyzer.unwrap_ops)reportr0cCs^|D]P\}}t|tr*||||<qt|trPt|dkrP||dq|||<qdS)z Resolve the format of the pre-defined report. Args: report: the dictionary to resolve. Values will be replaced in-place. rN)items isinstancer rUrPrDrK)r7rVkvr;r;r<rKs  zAnalyzer.resolve_formatrrQr0cCstd|jjddS)z:Analyze the dict format dataset, return the summary reportz Subclass z must implement this method.N)NotImplementedErrorr:__name__)r7rQr;r;r<__call__szAnalyzer.__call__)r] __module__ __qualname____doc__r4r?rJrM staticmethodrUrKrr^ __classcell__r;r;r9r<r!:s   cs8eZdZdZejfddddfdd ZddZZS) r"a Analyzer to extract image stats properties for each case(image). Args: image_key: the key to find image data in the callable function input (data) Examples: .. code-block:: python import numpy as np from monai.auto3dseg import ImageStats from monai.data import MetaTensor input = {} input['image'] = np.random.rand(1,30,30,30) input['image'] = MetaTensor(np.random.rand(1,30,30,30)) # MetaTensor analyzer = ImageStats(image_key="image") print(analyzer(input)["image_stats"]) Notes: if the image data is NumPy array, the spacing stats will be [1.0] * `ndims` of the array, where the `ndims` is the lesser value between the image dimension and 3. r+r-) image_keyr.r0c sbt|tstd||_tjdtjdtjdtjdtj dtj di}t ||| tj tdS)Nzimage_key input must be str)rXr+rErdrSHAPECHANNELS CROPPED_SHAPESPACINGSIZEMM INTENSITYr3r4r?r )r7rdr.r/r9r;r<r4s$  zImageStats.__init__cstt|t}t}tdfddtjjdD}dkr\dd|D}t }dd|D|t j <t ||t j <dd|D|t j<t|jtrt|jjnd gtd |jj|t j<d dt|t j d|t jD|t j<fd d|D|t j<t| sDtd jd|j<t|tdt|S)a Callable to execute the pre-defined functions Returns: A dictionary. The dict has the key in self.report_format. The value of ImageStatsKeys.INTENSITY is in a list format. Each element of the value list has stats pre-defined by SampleOperations (max, min, ....). Raises: RuntimeError if the stats report generated is not consistent with the pre- defined report_format. Note: The stats operation uses numpy and torch to compute max, min, and other functions. If the input has nan/inf, the stats results will be nan/inf. Fcsg|]}j|qSr;rd.0idr7r;r< sz'ImageStats.__call__..r nda_croppedscSsg|] }t|qSr;)rrmndar;r;r<rqscSsg|]}t|jqSr;rPshapersr;r;r<rqscSsg|]}t|jqSr;rurmZnda_cr;r;r<rqsg?rAcSsg|]\}}||qSr;r;)rmabr;r;r<rqscsg|]}jtj|qSr;r6rrjevaluaterwrLr;r<rqsreport generated by differs from the report format.zGet image stats spent ) r,timetorchis_grad_enabledset_grad_enabledrangerdrvrrMrrerDrfrgrXrraffinetolistminndimrhziprirjr RuntimeErrorr:r.loggerdebug)r7rQstartrestore_grad_statendasrrrVr;ror<r^s6 $      zImageStats.__call__ r]r_r`rar IMAGE_STATSr4r^rcr;r;r9r<r"scs@eZdZdZejfddddfdd Zdddd d ZZS) r#ay Analyzer to extract foreground label properties for each case(image and label). Args: image_key: the key to find image data in the callable function input (data) label_key: the key to find label data in the callable function input (data) Examples: .. code-block:: python import numpy as np from monai.auto3dseg import FgImageStats input = {} input['image'] = np.random.rand(1,30,30,30) input['label'] = np.ones([30,30,30]) analyzer = FgImageStats(image_key='image', label_key='label') print(analyzer(input)["image_foreground_stats"]) r+)rd label_keyr.cs8||_||_tjdi}t|||tjtdSN)rdrrrjr3r4r?r )r7rdrr.r/r9r;r<r4+s  zFgImageStats.__init__rr,r[cst|t}t}tdfddtjjdD}jj|djkr|t djd|djfdd|D}dd|D}t  }fd d|D|t j <t| std jd |j<t|td t|S) ak Callable to execute the pre-defined functions Returns: A dictionary. The dict has the key in self.report_format and value in a list format. Each element of the value list has stats pre-defined by SampleOperations (max, min, ....). Raises: RuntimeError if the stats report generated is not consistent with the pre- defined report_format. Note: The stats operation uses numpy and torch to compute max, min, and other functions. If the input has nan/inf, the stats results will be nan/inf. Fcsg|]}j|qSr;rkrlror;r<rqKsz)FgImageStats.__call__..r Label shape  is different from image shape csg|]}t|qSr;rrs ndas_labelr;r<rqQscSs&g|]}|dkr|ntdgqS)rg)numelrrsr;r;r<rqRscsg|]}jtj|qSr;rzrmZnda_frLr;r<rqWsr|r}z!Get foreground image stats spent )r,r~rrrrrdrvrrErrMrrjrrr:r.rr)r7rQrrrnda_foregroundsrVr;)rprr7r<r^4s( $      zFgImageStats.__call__ r]r_r`rarFG_IMAGE_STATSr4r^rcr;r;r9r<r#s csDeZdZdZejdfdddddfdd Zdd d d d ZZS) r$a Analyzer to extract label stats properties for each case(image and label). Args: image_key: the key to find image data in the callable function input (data) label_key: the key to find label data in the callable function input (data) do_ccp: performs connected component analysis. Default is True. Examples: .. code-block:: python import numpy as np from monai.auto3dseg import LabelStats input = {} input['image'] = np.random.rand(1,30,30,30) input['label'] = np.ones([30,30,30]) analyzer = LabelStats(image_key='image', label_key='label') print(analyzer(input)["label_stats"]) Tr+ bool | None)rdrr.do_ccpc s||_||_||_tjdtjdtjtjdtjdigi}|jr\|tjdtj dtj dit ||| tjtttjdtjg}||tdSNr0)rdrrr LABEL_UID IMAGE_INTSTLABEL PIXEL_PCTrF LABEL_SHAPE LABEL_NCOMPr3r4r?r rjoinrJ)r7rdrr.rr/id_seqr9r;r<r4}s$zLabelStats.__init__zMapping[Hashable, MetaTensor]z!dict[Hashable, MetaTensor | dict]r[cst|t}tjtjtfr>jjjdkr>d}nd}t }t dfddt jj dD}j tjj |dj krtdj d|dj fd d|D}d d|D}t}tttjfr|j}|tj}g}d} g} |D]} t} i} | kfd d|D}fd d|D| tj<t}| || |7} jr|r~tjt\}}|| tj<|| tj <|| t!"d | dt| qt#|D]*\}}||$tj%t&| || iqt'(}||tj)<fdd|D|tj<||tj*<t+|(slt,dj-d|j.<t |t!"dt|S)a Callable to execute the pre-defined functions. Returns: A dictionary. The dict has the key in self.report_format and value in a list format. Each element of the value list has stats pre-defined by SampleOperations (max, min, ....). Examples: output dict contains { LabelStatsKeys.LABEL_UID:[0,1,3], LabelStatsKeys.IMAGE_INTST: {...}, LabelStatsKeys.LABEL:[ { LabelStatsKeys.PIXEL_PCT: 0.8, LabelStatsKeys.IMAGE_INTST: {...}, LabelStatsKeys.LABEL_SHAPE: [...], LabelStatsKeys.LABEL_NCOMP: 1 } { LabelStatsKeys.PIXEL_PCT: 0.1, LabelStatsKeys.IMAGE_INTST: {...}, LabelStatsKeys.LABEL_SHAPE: [...], LabelStatsKeys.LABEL_NCOMP: 1 } { LabelStatsKeys.PIXEL_PCT: 0.1, LabelStatsKeys.IMAGE_INTST: {...}, LabelStatsKeys.LABEL_SHAPE: [...], LabelStatsKeys.LABEL_NCOMP: 1 } ] } Raises: RuntimeError if the stats report generated is not consistent with the pre- defined report_format. Notes: The label class_ID of the dictionary in LabelStatsKeys.LABEL IS NOT the index. Instead, the class_ID is the LabelStatsKeys.LABEL_UID with the same index. For instance, the last dict in LabelStatsKeys.LABEL in the Examples is 3, which is the last element under LabelStatsKeys.LABEL_UID. The stats operation uses numpy and torch to compute max, min, and other functions. If the input has nan/inf, the stats results will be nan/inf. cudaTFcsg|]}j|qSr;rkrlror;r<rqsz'LabelStats.__call__..rrrcsg|]}t|qSr;rrsrr;r<rqscSs(g|] }|dkr|n tdgqS)r)rrTensorrsr;r;r<rqscsg|] }|qSr;r;rs) mask_indexr;r<rqscsg|]}jtj|qSr;r6rrr{)rmZnda_mrLr;r<rqsz label z stats takes csg|]}jtj|qSr;rrrLr;r<rqsr|r}zGet label stats spent )/r,r~rXrdrrrdevicetyperrrrvrastypeint16rErrQcpunumpynprrrrappendrr empty_cacherrrrr enumeraterFrfloatrrMrrrrr:r.)r7rQrZ using_cudarrr unique_labelZlabel_substatsZ pixel_sumZ pixel_arrindexZ start_label label_dictZ nda_masksZ pixel_count shape_list ncomponentsrnrIrVr;)rprrr7r<r^sl0( $        "$       zLabelStats.__call__ r]r_r`rar LABEL_STATSr4r^rcr;r;r9r<r$es cs@eZdZdZejdfdddfdd Zdd d d d ZZS) r%au This summary analyzer processes the values of specific key `stats_name` in a list of dict. Typically, the list of dict is the output of case analyzer under the same prefix (ImageStats). Args: stats_name: the key of the to-process value in the dict. average: whether to average the statistical value across different image modalities. Tr+rr.averagec s||_tjdtjdtjdtjdtjdtjdi}t ||| tjt | tjt | tjt | tjt | tjt | tjt dSr) summary_averagerrerfrgrhrirjr3r4r?r r r7r.rr/r9r;r<r4s*zImageStatsSumm.__init__ list[dict]r,r[cCs*t|tstd|jdt|dkr:td|jd|j|dkrXt|jdt|}t j t j t j t j t jfD]@}t||j|g}|j|j||jdkr|jrdndd||<q|t j}||}t||j|g|}|j|j||jrd ndd||<t||s&td |jd |S)  Callable to execute the pre-defined functions Returns: A dictionary. The dict has the key in self.report_format and value in a list format. Each element of the value list has stats pre-defined by SampleOperations (max, min, ....). Raises: RuntimeError if the stats report generated is not consistent with the pre- defined report_format. Examples: output dict contains a dictionary for all of the following keys{ ImageStatsKeys.SHAPE:{...} ImageStatsKeys.CHANNELS: {...}, ImageStatsKeys.CROPPED_SHAPE: {...}, ImageStatsKeys.SPACING: {...}, ImageStatsKeys.SIZEMM: {...}, ImageStatsKeys.INTENSITY: {...}, } Notes: The stats operation uses numpy and torch to compute max, min, and other functions. If the input has nan/inf, the stats results will be nan/inf. Callable  requires list inputsr input list is empty is not in input datardimNr|r})rXrPrEr:rDr.KeyErrorrrMrrerfrgrhrirr6r{rrrjrGr rr)r7rQrVrYZv_np intst_strop_keys intst_dictr;r;r<r^-s,   . "zImageStatsSumm.__call__rr;r;r9r<r%s cs@eZdZdZejdfdddfdd Zdd d d d ZZS) r&ax This summary analyzer processes the values of specific key `stats_name` in a list of dict. Typically, the list of dict is the output of case analyzer under the similar name (FgImageStats). Args: stats_name: the key of the to-process value in the dict. average: whether to average the statistical value across different image modalities. Tr+rrcs2||_tjdi}t|||tjtdSr)rrrjr3r4r?r rr9r;r<r4ts zFgImageStatsSumm.__init__rr,r[cCst|tstd|jdt|dkr:td|jd|j|dkrXt|jdt|}t j }|| }t ||j|g|}|j |j||jrdndd||<t||std|jd |S) aY Callable to execute the pre-defined functions. Returns: A dictionary. The dict has the key in self.report_format and value in a list format. Each element of the value list has stats pre-defined by SampleOperations (max, min, ....) and SummaryOperation (max of the max, mean of the mean, etc). Raises: RuntimeError if the stats report generated is not consistent with the pre- defined report_format. Examples: output dict contains a dictionary for all of the following keys{ ImageStatsKeys.INTENSITY: {...}, } Notes: The stats operation uses numpy and torch to compute max, min, and other functions. If the input has nan/inf, the stats results will be nan/inf. rrrrz is not in input data.Nrr|r})rXrPrEr:rDr.rrrMrrjrGr r6r{rrr)r7rQrVrrrr;r;r<r^{s    "zFgImageStatsSumm.__call__rr;r;r9r<r&hs csDeZdZdZejddfddddfdd Zdd d d d ZZS) r'av This summary analyzer processes the values of specific key `stats_name` in a list of dict. Typically, the list of dict is the output of case analyzer under the similar name (LabelStats). Args: stats_name: the key of the to-process value in the dict. average: whether to average the statistical value across different image modalities. Tr+r)r.rrc s||_||_tjdtjdtjtjdtjdigi}|jrV|tjdtjdtj dit ||| tjt ttjdtjg}||tttjdtjg}||t ttjdtjg}||tttjdtj g}||tdSr)rrrrrrrrFrrr3r4r?r rrrJr )r7r.rrr/rr9r;r<r4s.zLabelStatsSumm.__init__rr,r[cCst|tstd|jdt|dkr:td|jd|j|dkrXt|jdt|}t ||jt j gddd}t |}||t j <t j }||}t||j|g|}|j|j||jrdndd ||<g}t j} |D]} i} t j} |j| | | g} t || dd }|j| d| j||jd kr:|jr:d ndd | | <|jrt j}|jt j| |g}t ||dd }|j| d|j||jd kr|jrd ndd | |<t j}|j| | t jg}t ||ddd }|j| d|j||jd kr|jrd ndd | |<t j }|j| | |g}|| d|}t|||dd }|j| d|j||jr`dndd | |<|| q||t j<t||std|jd|S)a Callable to execute the pre-defined functions Returns: A dictionary. The dict has the key in self.report_format and value in a list format. Each element of the value list has stats pre-defined by SampleOperations (max, min, ....) and SummaryOperation (max of the max, mean of the mean, etc). Raises: RuntimeError if the stats report generated is not consistent with the pre- defined report_format. Notes: The stats operation uses numpy and torch to compute max, min, and other functions. If the input has nan/inf, the stats results will be nan/inf. rrrrrNT)axisraggedr) allow_missingrr)rrr|r})rXrPrEr:rDr.rrrMrrrrrrGr r6r{rrrrrrrrrr)r7rQrVZuid_nprrrrZdetailed_label_listZ label_strZlabel_idstatsZpct_strZpct_fixed_keysZpct_npZ ncomp_strZncomp_fixed_keysZncomp_npZ shape_strZshape_fixed_keysshape_npZintst_fixed_keysr;r;r<r^sj     "       zLabelStatsSumm.__call__rr;r;r9r<r's   cs2eZdZdZddddfdd Zdd ZZS) r(a/ This class finds the file path for the loaded image/label and writes the info into the data pipeline as a monai transforms. Args: key: the key to fetch the filename (for example, "image", "label"). stats_name: the key to store the filename in the output stats report. z str | Noner+r-)r=r.r0cs||_t|idSr)r=r3r4)r7r=r.r9r;r<r46szFilenameStats.__init__cCst|}|jr|j|kr*td|jdt||jtsLtd|jdtj||jjkrzttjd||jd||jjtj||j<n d||j<|S)NzData with key z is missing.zValue type of z is not MetaTensor.z not found in MetaTensor .r-) r,r=rErXrrFILENAME_OR_OBJmetar.)r7rQrpr;r;r<r^:s  zFilenameStats.__call__)r]r_r`rar4r^rcr;r;r9r<r(+s csFeZdZdZejddfdddddfdd Zd d d d d ZZS) r)a! Analyzer to compute intensity histogram. Args: image_key: the key to find image data in the callable function input (data) hist_bins: list of positive integers (one for each channel) for setting the number of bins used to compute the histogram. Defaults to [100]. hist_range: list of lists of two floats (one for each channel) setting the intensity range to compute the histogram. Defaults to [-500, 500]. Examples: .. code-block:: python import numpy as np from monai.auto3dseg.analyzer import ImageHistogram input = {} input['image'] = np.random.rand(1,30,30,30) input['label'] = np.ones([30,30,30]) analyzer = ImageHistogram(image_key='image') print(analyzer(input)) Nr+zlist[int] | int | Nonez list | None)rdr. hist_bins hist_rangec s@||_|dkrdgnt|tr"|n|g|_|dkr:ddgn||_ddd}t|||tj t t dd|jDs|jg|_t |jt |jkrt dt |jdt |jd tt|j|jD]l\}}|\}} t|tr|d kr t d |d d |t| tr"t | dkrt d |d d| qdS)Ndi icounts bin_edgescss|]}t|tVqdSr)rXrP)rmhrr;r;r< zsz*ImageHistogram.__init__..zNumber of histogram bins () and histogram ranges (z) need to be the same!rz Expected rz1. hist_bins value to be positive integer but got rz8. hist_range values to be list of length 2 but received )rdrXrPrrr3r4r?r HISTOGRAMr allrDrErrint) r7rdr.rrr/rnZ hist_paramsZ _hist_binsZ _hist_ranger9r;r<r4es&   zImageHistogram.__init__r,r[c CsHt|}t||jdd}t|d}t|jdkrB||j|_t|j|krltd|dt|jdt|jdkr||j|_t|j|krtd|dt|jdg}t |D]|}tj ||d f|j||j|d|j|dfd \}}| | d } t | | s.td |jd || q|||j<|S)a Callable to execute the pre-defined functions Returns: A dictionary. The dict has the key in self.report_format and value Raises: RuntimeError if the stats report generated is not consistent with the pre- defined report_format. Note: The stats operation uses numpy and torch to compute max, min, and other functions. If the input has nan/inf, the stats results will be nan/inf. T) wrap_sequencerrz4There is a mismatch between the number of channels (z) and number histogram bins (z).r.)binsrrr|r})r,rrdrrvrDrrErr histogramrrrMrr:rr.) r7rQrprZ nr_channelsreportschannelrr_reportr;r;r<r^s8       zImageHistogram.__call__ r]r_r`rarIMAGE_HISTOGRAMr4r^rcr;r;r9r<r)Ks #cs@eZdZdZejdfdddfdd Zdd d d d ZZS) r*ay This summary analyzer processes the values of specific key `stats_name` in a list of dict. Typically, the list of dict is the output of case analyzer under the same prefix (ImageHistogram). Args: stats_name: the key of the to-process value in the dict. average: whether to average the statistical value across different image modalities. Tr+rrcs2||_tjdi}t|||tjtdSr)rrrr3r4r?r rr9r;r<r4s zImageHistogramSumm.__init__rr,r[c Cst|tstd|jdt|dkr:td|jd|j|dkrXt|jdi}|D]}|s|tj}t t|D]}t ||d||d<q~q`t t|D]z}||dt |tj|d7<t ||d|tj|dkrtd||dd |tj|dqq`t t|D]}||d ||d<q6tj|i}t||std |jd |S) rrrrrrrrzbin edges are not consistent! z vs. r|r})rXrPrEr:rDr.rrrrrarrayrrrrrrMr)r7rQZsumm_histogramrprYrVr;r;r<r^s0   ($$ zImageHistogramSumm.__call__rr;r;r9r<r*s )? __future__rr~abcrrcollections.abcrrcopyrtypingrrrrmonai.apps.utilsr Zmonai.auto3dseg.operationsr r r monai.auto3dseg.utilsr rrrrrmonai.bundle.config_parserrZmonai.bundle.utilsr monai.datarrmonai.transforms.transformr0monai.transforms.utils_pytorch_numpy_unificationrr monai.utilsrmonai.utils.enumsrrrmonai.utils.miscrrr]r__all__r!r"r#r$r%r&r'r(r)r*r;r;r;r< sT          tfQ*Z@ s