| OLD | NEW | 
| (Empty) |  | 
 |   1 # Copyright 2014 The Chromium Authors. All rights reserved. | 
 |   2 # Use of this source code is governed by a BSD-style license that can be | 
 |   3 # found in the LICENSE file. | 
 |   4  | 
 |   5 """Provides implementations of functions that operate on histograms.""" | 
 |   6  | 
 |   7 from __future__ import division | 
 |   8  | 
 |   9 import collections | 
 |  10  | 
 |  11 from telemetry.util import external_modules | 
 |  12  | 
 |  13 np = external_modules.ImportOptionalModule('numpy') | 
 |  14  | 
 |  15  | 
 |  16 def HistogramDistance(hist1, hist2, default_color=None): | 
 |  17   """Earth mover's distance. | 
 |  18   http://en.wikipedia.org/wiki/Earth_mover's_distance""" | 
 |  19   if len(hist1) != len(hist2): | 
 |  20     raise ValueError('Trying to compare histograms ' | 
 |  21                      'of different sizes, %s != %s' % (len(hist1), len(hist2))) | 
 |  22   if len(hist1) == 0: | 
 |  23     return 0 | 
 |  24  | 
 |  25   sum_func = np.sum if np is not None else sum | 
 |  26  | 
 |  27   n1 = sum_func(hist1) | 
 |  28   n2 = sum_func(hist2) | 
 |  29   if (n1 == 0 or n2 == 0) and default_color is None: | 
 |  30     raise ValueError('Histogram has no data and no default color.') | 
 |  31   if n1 == 0: | 
 |  32     hist1[default_color] = 1 | 
 |  33     n1 = 1 | 
 |  34   if n2 == 0: | 
 |  35     hist2[default_color] = 1 | 
 |  36     n2 = 1 | 
 |  37  | 
 |  38   if np is not None: | 
 |  39     remainder = np.multiply(hist1, n2) - np.multiply(hist2, n1) | 
 |  40     cumsum = np.cumsum(remainder) | 
 |  41     total = np.sum(np.abs(cumsum)) | 
 |  42   else: | 
 |  43     total = 0 | 
 |  44     remainder = 0 | 
 |  45     for value1, value2 in zip(hist1, hist2): | 
 |  46       remainder += value1 * n2 - value2 * n1 | 
 |  47       total += abs(remainder) | 
 |  48     assert remainder == 0, ( | 
 |  49         '%s pixel(s) left over after computing histogram distance.' | 
 |  50         % abs(remainder)) | 
 |  51   return abs(float(total) / n1 / n2) | 
 |  52  | 
 |  53  | 
 |  54 class ColorHistogram( | 
 |  55     collections.namedtuple('ColorHistogram', ['r', 'g', 'b', 'default_color'])): | 
 |  56   # pylint: disable=W0232 | 
 |  57   # pylint: disable=E1002 | 
 |  58  | 
 |  59   def __new__(cls, r, g, b, default_color=None): | 
 |  60     return super(ColorHistogram, cls).__new__(cls, r, g, b, default_color) | 
 |  61  | 
 |  62   def Distance(self, other): | 
 |  63     total = 0 | 
 |  64     for i in xrange(3): | 
 |  65       default_color = self[3][i] if self[3] is not None else None | 
 |  66       total += HistogramDistance(self[i], other[i], default_color) | 
 |  67     return total | 
| OLD | NEW |