The input has a specific format, which is a list of two-element tuples.

Each of the tuples contains the negative :math:`\\{S_p^-\\}` and the positive :math:`\\{S_p^+\\}` scores for one probe item :math:`p`, or ``None`` in case of open set recognition.

To read the lists from score files in 4 or 5 column format, please use the :py:func:`bob.measure.load.cmc_four_column` or :py:func:`bob.measure.load.cmc_five_column` function.

If **threshold** is set to ``None``, the rank 1 recognition rate is defined as the number of test items, for which the highest positive :math:`\\max\\{S_p^+\\}` score is greater than or equal to all negative scores, divided by the number of all probe items :math:`P`:

.. math::

If **threshold** is set to `None`, the recognition rate is defined as the number of test items, for which the

positive score is greater than or equal to all negative scores, divided by

the number of all test items. If several positive scores for one test item exist, the **highest** score is taken.

For a given rank :math:`r>1`, up to :math:`r` negative scores that are higher than the highest positive score are allowed to still count as correctly classified in the top :math:`r` rank.

If ``threshold`` :math:`\\theta` is given, **all** scores below threshold will be filtered out.

Hence, if all positive scores are below threshold :math:`\\max\\{S_p^+\\} < \\theta`, the probe will be misclassified **at any rank**.

For open set recognition, i.e., when there exist a tuple including negative scores without corresponding positive scores (``None``), and **all** negative scores are below ``threshold`` :math:`\\max\\{S_p^+\\} < \\theta`, the probe item is correctly rejected, **and it does not count into the denominator** :math:`P`.

When no ``threshold`` is provided, the open set probes will **always** count as misclassified, regardless of the ``rank``.

.. warn:

For open set tests, this rate does not correspond to a standard rate.

Please use :py:func:`detection_identification_rate` and :py:func:`false_alarm_rate` instead.

If **threshold** assumes one value, the recognition rate is defined as the number of test items, for which the

positive score is greater than or equal to all negative scores and the threshold divided by

the number of all test items. If several positive scores for one test item exist, the **highest** score is taken.

**Parameters:**

``cmc_scores`` : CMC scores loaded with one of the functions (:py:func:`bob.measure.load.cmc_four_column` or :py:func:`bob.measure.load.cmc_five_column`)

``threshold`` : Decision threshold. If `None`, the decision threshold will be the **highest** positive score.

CMC scores loaded with one of the functions (:py:func:`bob.measure.load.cmc_four_column` or :py:func:`bob.measure.load.cmc_five_column`).

Each pair contains the ``negative`` and the ``positive`` scores for **one probe item**.

Each pair can contain up to one empty array (or ``None``), i.e., in case of open set recognition.

``threshold`` : float or ``None``

Decision threshold. If not ``None``, **all** scores will be filtered by the threshold.

In an open set recognition problem, all open set scores (negatives with no corresponding positive) for which all scores are below threshold, will be counted as correctly rejected and **removed** from the probe list (i.e., the denominator).

``rank`` : int or ``None``

The rank for which the recognition rate should be computed, 1 by default.

**Returns:**

``RR`` : float

The rank 1 recognition rate, i.e., the relative number of correctly identified identities

The (open set) recognition rate for the given rank, a value between 0 and 1.

"""

# If no scores are given, the recognition rate is exactly 0.

ifnotcmc_scores:

return0.

correct=0.

correct=0

counter=0

forneg,posincmc_scores:

# set all values that are empty before to None

ifposisnotNoneandnotnumpy.array(pos).size:

pos=None

ifnegisnotNoneandnotnumpy.array(neg).size:

neg=None

ifposisNoneandnegisNone:

raiseValueError("One pair of the CMC scores has neither positive nor negative values")

# filter out any negative or positive scores below threshold; scores with exactly the threshold are also filtered out

# now, None and an empty array have different meanings.

ifthresholdisnotNone:

ifnegisnotNone:

neg=numpy.array(neg)[neg>threshold]

ifposisnotNone:

pos=numpy.array(pos)[pos>threshold]

ifposisNone:

# no positives, so we definitely do not have a match;

# check if we have negatives above threshold

ifnotneg.size:

# we have no negative scores over the threshold, so we have correctly rejected the probe

# don't increase any of the two counters...

continue

# we have negatives over threshold, so we have incorrect classifications; independent on the actual rank

counter+=1

else:

# we have a positive, so we need to count the probe

counter+=1

ifnotnumpy.array(pos).size:

# all positive scores have been filtered out by the threshold, we definitely have a mis-match

continue

#If threshold is none, let's use the highest positive score as the decision threshold

if(thresholdisNone):

# get the maximum positive score for the current probe item

# (usually, there is only one positive score, but just in case...)

max_pos=numpy.max(pos)

# check if the positive score is smaller than all negative scores

if(neg<max_pos).all():

correct+=1.

else:

#If threshold is NOT None, we have an openset identification

max_pos=numpy.max(pos)

if((threshold<max_pos)and(neg<max_pos).all()):

correct+=1.

# return relative number of correctly matched scores

returncorrect/float(len(cmc_scores))

ifnegisNoneornotnumpy.array(neg).size:

# if we had no negatives, or all negatives were below threshold, we have a match at rank 1

correct+=1

else:

# count the number of negative scores that are higher than the best positive score

index=numpy.sum(neg>=max_pos)

ifindex<rank:

correct+=1

returnfloat(correct)/float(counter)

defcmc(cmc_scores):

...

...

@@ -143,24 +189,26 @@ def cmc(cmc_scores):

Calculates the cumulative match characteristic (CMC) from the given input.

The input has a specific format, which is a list of two-element tuples. Each

of the tuples contains the negative and the positive scores for one test

of the tuples contains the negative and the positive scores for one probe

item. To read the lists from score files in 4 or 5 column format, please use

the :py:func:`bob.measure.load.cmc_four_column` or

raiseValueError("For the CMC computation at least one positive score is necessary. Please review who you are loading the scores. You must set `load_only_negatives=False` in the :py:func:`bob.measure.load.cmc_four_column` or `:py:func:`bob.measure.load.cmc_five_column` methods.")

ifposisNoneornotnumpy.array(pos).size:

raiseValueError("For the CMC computation at least one positive score per pair is necessary.")

ifnegisNone:

neg=[]

# get the maximum positive score for the current probe item

# (usually, there is only one positive score, but just in case...)

# (usually, there is only one positive score, but just in case...)

max_pos=numpy.max(pos)

# count the number of negative scores that are higher than the best positive score

# count the number of negative scores that are higher than the best positive score

"""detection_identification_rate(cmc_scores, threshold, rank) -> dir

Computes the `detection and identification rate` for the given threshold.

This value is designed to be used in an open set identification protocol, and defined in Chapter 14.1 of [LiJain2005]_.

Although the detection and identification rate is designed to be computed on an open set protocol, it uses only the probe elements, for which a corresponding gallery element exists.

For closed set identification protocols, this function is identical to :py:func:`recognition_rate`.

The only difference is that for this function, a ``threshold`` for the scores need to be defined, while for :py:func:`recognition_rate` it is optional.

CMC scores loaded with one of the functions (:py:func:`bob.measure.load.cmc_four_column` or :py:func:`bob.measure.load.cmc_five_column`).

Each pair contains the ``negative`` and the ``positive`` scores for **one probe item**.

There need to be at least one probe item, for which positive and negative scores exist.

``threshold`` : float

The decision threshold :math:`\\tau``.

``rank`` : int

The rank for which the curve should be plotted, by default 1.

**Returns:**

``dir`` : float

The detection and identification rate for the given threshold.

"""

# count the correctly classifier probes

correct=0

counter=0

forneg,posincmc_scores:

ifposisNoneornotnumpy.array(pos).size:

# we only consider probes with corresponding gallery items

continue

# we have an in-gallery probe

counter+=1

# check, if it is correctly classified

ifnegisNone:

neg=[]

# get the maximum positive score for the current probe item

# (usually, there is only one positive score, but just in case...)

max_pos=numpy.max(pos)

index=numpy.sum(neg>=max_pos)# compute the rank (in fact, rank - 1)

ifmax_pos>=thresholdandindex<rank:

correct+=1

ifnotcounter:

logger.warn("No in-gallery probe was found")

return0.

returnfloat(correct)/float(counter)

deffalse_alarm_rate(cmc_scores,threshold):

"""false_alarm_rate(cmc_scores, threshold) -> far

Computes the `false alarm rate` for the given threshold,.

This value is designed to be used in an open set identification protocol, and defined in Chapter 14.1 of [LiJain2005]_.

The false alarm rate is designed to be computed on an open set protocol, it uses only the probe elements, for which **no** corresponding gallery element exists.

raiseValueError("Only scores with 4 and 5 columns are supported.")

numpy.savetxt(filename,score_lines,fmt=fmt)

def_convert_cmc_scores(neg_dict,pos_dict):

"""Converts the negative and positive scores read with :py:func:`cmc_four_column` or :py:func:`cmc_four_column` into a format that is handled by the :py:func:`bob.measure.cmc` and similar functions."""

# convert to lists of tuples of ndarrays (or None)

This function computes log-scaled values between :math:`10^{M}` and 1 (including), where :math:`M` is the ``min_ste`` argument, which needs to be a negative integer.

The integral ``counts_per_step`` value defines how many values between two adjacent powers of 10 will be created.

The total number of values will be ``-min_step * counts_per_step + 1``.

**Parameters:**

``min_step`` : int (negative)

The power of 10 that will be the minimum value. E.g., the default ``-4`` will result in the first number to be :math:`10^{-4}` = ``0.00001`` or ``0.01%``

``counts_per_step`` : int (positive)

The number of values that will be put between two adjacent powers of 10.

With the default value ``4`` (and default values of ``min_step``), we will get ``log_list[0] == 1e-4``, ``log_list[4] == 1e-3``, ..., ``log_list[16] == 1``.

**Returns**

``log_list`` : [float]

A list of logarithmically scaled values between :math:`10^{M}` and 1.

See :py:func:`bob.measure.detection_identification_rate`

``far_values`` : [float]

The values for the FAR, where the CAR should be plotted; each value should be in range [0,1].

``rank`` : int or ``None``

The rank for which the curve should be plotted, 1 by default.

``logx`` : bool

Plot the FAR axis in logarithmic scale using :py:func:`matplotlib.pyplot.semilogx` or in linear scale using :py:func:`matplotlib.pyplot.plot`? (Default: ``True``)

``kwargs`` : keyword arguments

Extra plotting parameters, which are passed directly to :py:func:`matplotlib.pyplot.plot` or :py:func:`matplotlib.pyplot.semilogx`.

**Returns:**

The return value is the ``matplotlib`` line that was added as defined by :py:func:`matplotlib.pyplot.plot`.

.. [LiJain2005] **Stan Li and Anil K. Jain**, *Handbook of Face Recognition*, Springer, 2005