# 
 | 
# The Python Imaging Library. 
 | 
# $Id$ 
 | 
# 
 | 
# global image statistics 
 | 
# 
 | 
# History: 
 | 
# 1996-04-05 fl   Created 
 | 
# 1997-05-21 fl   Added mask; added rms, var, stddev attributes 
 | 
# 1997-08-05 fl   Added median 
 | 
# 1998-07-05 hk   Fixed integer overflow error 
 | 
# 
 | 
# Notes: 
 | 
# This class shows how to implement delayed evaluation of attributes. 
 | 
# To get a certain value, simply access the corresponding attribute. 
 | 
# The __getattr__ dispatcher takes care of the rest. 
 | 
# 
 | 
# Copyright (c) Secret Labs AB 1997. 
 | 
# Copyright (c) Fredrik Lundh 1996-97. 
 | 
# 
 | 
# See the README file for information on usage and redistribution. 
 | 
# 
 | 
  
 | 
import Image 
 | 
import operator, math 
 | 
  
 | 
## 
 | 
# The <b>ImageStat</b> module calculates global statistics for an 
 | 
# image, or a region of an image. 
 | 
## 
 | 
  
 | 
## 
 | 
# Calculate statistics for the given image.  If a mask is included, 
 | 
# only the regions covered by that mask are included in the 
 | 
# statistics. 
 | 
  
 | 
class Stat: 
 | 
    "Get image or feature statistics" 
 | 
  
 | 
    ## 
 | 
    # Create a statistics object. 
 | 
    # 
 | 
    # @def __init__(image, mask=None) 
 | 
    # @param image A PIL image, or a precalculate histogram. 
 | 
    # @param mask An optional mask. 
 | 
  
 | 
    def __init__(self, image_or_list, mask = None): 
 | 
        try: 
 | 
            if mask: 
 | 
                self.h = image_or_list.histogram(mask) 
 | 
            else: 
 | 
                self.h = image_or_list.histogram() 
 | 
        except AttributeError: 
 | 
            self.h = image_or_list # assume it to be a histogram list 
 | 
        if type(self.h) != type([]): 
 | 
            raise TypeError, "first argument must be image or list" 
 | 
        self.bands = range(len(self.h) / 256) 
 | 
  
 | 
    def __getattr__(self, id): 
 | 
        "Calculate missing attribute" 
 | 
        if id[:4] == "_get": 
 | 
            raise AttributeError, id 
 | 
        # calculate missing attribute 
 | 
        v = getattr(self, "_get" + id)() 
 | 
        setattr(self, id, v) 
 | 
        return v 
 | 
  
 | 
    def _getextrema(self): 
 | 
        "Get min/max values for each band in the image" 
 | 
  
 | 
        def minmax(histogram): 
 | 
            n = 255 
 | 
            x = 0 
 | 
            for i in range(256): 
 | 
                if histogram[i]: 
 | 
                    n = min(n, i) 
 | 
                    x = max(x, i) 
 | 
            return n, x # returns (255, 0) if there's no data in the histogram 
 | 
  
 | 
        v = [] 
 | 
        for i in range(0, len(self.h), 256): 
 | 
            v.append(minmax(self.h[i:])) 
 | 
        return v 
 | 
  
 | 
    def _getcount(self): 
 | 
        "Get total number of pixels in each layer" 
 | 
  
 | 
        v = [] 
 | 
        for i in range(0, len(self.h), 256): 
 | 
            v.append(reduce(operator.add, self.h[i:i+256])) 
 | 
        return v 
 | 
  
 | 
    def _getsum(self): 
 | 
        "Get sum of all pixels in each layer" 
 | 
  
 | 
        v = [] 
 | 
        for i in range(0, len(self.h), 256): 
 | 
            sum = 0.0 
 | 
            for j in range(256): 
 | 
                sum = sum + j * self.h[i+j] 
 | 
            v.append(sum) 
 | 
        return v 
 | 
  
 | 
    def _getsum2(self): 
 | 
        "Get squared sum of all pixels in each layer" 
 | 
  
 | 
        v = [] 
 | 
        for i in range(0, len(self.h), 256): 
 | 
            sum2 = 0.0 
 | 
            for j in range(256): 
 | 
                sum2 = sum2 + (j ** 2) * float(self.h[i+j]) 
 | 
            v.append(sum2) 
 | 
        return v 
 | 
  
 | 
    def _getmean(self): 
 | 
        "Get average pixel level for each layer" 
 | 
  
 | 
        v = [] 
 | 
        for i in self.bands: 
 | 
            v.append(self.sum[i] / self.count[i]) 
 | 
        return v 
 | 
  
 | 
    def _getmedian(self): 
 | 
        "Get median pixel level for each layer" 
 | 
  
 | 
        v = [] 
 | 
        for i in self.bands: 
 | 
            s = 0 
 | 
            l = self.count[i]/2 
 | 
            b = i * 256 
 | 
            for j in range(256): 
 | 
                s = s + self.h[b+j] 
 | 
                if s > l: 
 | 
                    break 
 | 
            v.append(j) 
 | 
        return v 
 | 
  
 | 
    def _getrms(self): 
 | 
        "Get RMS for each layer" 
 | 
  
 | 
        v = [] 
 | 
        for i in self.bands: 
 | 
            v.append(math.sqrt(self.sum2[i] / self.count[i])) 
 | 
        return v 
 | 
  
 | 
  
 | 
    def _getvar(self): 
 | 
        "Get variance for each layer" 
 | 
  
 | 
        v = [] 
 | 
        for i in self.bands: 
 | 
            n = self.count[i] 
 | 
            v.append((self.sum2[i]-(self.sum[i]**2.0)/n)/n) 
 | 
        return v 
 | 
  
 | 
    def _getstddev(self): 
 | 
        "Get standard deviation for each layer" 
 | 
  
 | 
        v = [] 
 | 
        for i in self.bands: 
 | 
            v.append(math.sqrt(self.var[i])) 
 | 
        return v 
 | 
  
 | 
Global = Stat # compatibility 
 |