home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 April / enter-2004-04.iso / files / EVE_1424_100181.exe / ImageOps.py < prev    next >
Encoding:
Text File  |  2004-04-20  |  9.3 KB  |  299 lines

  1. #
  2. # The Python Imaging Library.
  3. # $Id: //modules/pil/PIL/ImageOps.py#1 $
  4. #
  5. # standard image operations
  6. #
  7. # History:
  8. # 2001-10-20 fl   Created
  9. # 2001-10-23 fl   Added autocontrast operator
  10. # 2001-12-18 fl   Added Kevin's fit operator
  11. #
  12. # Copyright (c) 2001 by Secret Labs AB
  13. # Copyright (c) 2001 by Fredrik Lundh
  14. #
  15. # See the README file for information on usage and redistribution.
  16. #
  17.  
  18. import Image
  19.  
  20. #
  21. # helpers
  22.  
  23. def _border(border):
  24.     if type(border) is type(()):
  25.         if len(border) == 2:
  26.             left, top = right, bottom = border
  27.         elif len(border) == 4:
  28.             left, top, right, bottom = border
  29.     else:
  30.         left = top = right = bottom = border
  31.     return left, top, right, bottom
  32.  
  33. def _lut(image, lut):
  34.     if image.mode == "P":
  35.         # FIXME: apply to lookup table, not image data
  36.         raise NotImplemented, "mode P support coming soon"
  37.     elif image.mode in ("L", "RGB"):
  38.         if image.mode == "RGB" and len(lut) == 256:
  39.             lut = lut + lut + lut
  40.         return image.point(lut)
  41.     else:
  42.         raise IOError, "not supported for this image mode"
  43.  
  44. #
  45. # actions
  46.  
  47. def autocontrast(image, cutoff=0, ignore=None):
  48.     "Maximize image contrast, based on histogram"
  49.     histogram = image.histogram()
  50.     lut = []
  51.     for layer in range(0, len(histogram), 256):
  52.         h = histogram[layer:layer+256]
  53.         if ignore is not None:
  54.             # get rid of outliers
  55.             try:
  56.                 h[ignore] = 0
  57.             except TypeError:
  58.                 # assume sequence
  59.                 for ix in ignore:
  60.                     h[ix] = 0
  61.         if cutoff:
  62.             # cut off pixels from both ends of the histogram
  63.             # get number of pixels
  64.             n = 0
  65.             for ix in range(256):
  66.                 n = n + h[ix]
  67.             # remove cutoff% pixels from the low end
  68.             cut = n * cutoff / 100
  69.             for lo in range(256):
  70.                 if cut > h[lo]:
  71.                     cut = cut - h[lo]
  72.                     h[lo] = 0
  73.                 else:
  74.                     h[lo] = h[lo] - cut
  75.                     cut = 0
  76.                 if cut <= 0:
  77.                     break
  78.             # remove cutoff% samples from the hi end
  79.             cut = n * cutoff / 100
  80.             for hi in range(255, -1, -1):
  81.                 if cut > h[hi]:
  82.                     cut = cut - h[hi]
  83.                     h[hi] = 0
  84.                 else:
  85.                     h[hi] = h[hi] - cut
  86.                     cut = 0
  87.                 if cut <= 0:
  88.                     break
  89.         # find lowest/highest samples after preprocessing
  90.         for lo in range(256):
  91.             if h[lo]:
  92.                 break
  93.         for hi in range(255, -1, -1):
  94.             if h[hi]:
  95.                 break
  96.         if hi <= lo:
  97.             # don't bother
  98.             lut.extend(range(256))
  99.         else:
  100.             scale = 255.0 / (hi - lo)
  101.             offset = -lo * scale
  102.             for ix in range(256):
  103.                 ix = int(ix * scale + offset)
  104.                 if ix < 0:
  105.                     ix = 0
  106.                 elif ix > 255:
  107.                     ix = 255
  108.                 lut.append(ix)
  109.     return _lut(image, lut)
  110.  
  111. def colorize(image, black, white):
  112.     "Colorize a grayscale image"
  113.     assert image.mode == "L"
  114.     red = []; green = []; blue = []
  115.     for i in range(256):
  116.         red.append(black[0]+i*(white[0]-black[0])/255)
  117.         green.append(black[1]+i*(white[1]-black[1])/255)
  118.         blue.append(black[2]+i*(white[2]-black[2])/255)
  119.     image = image.convert("RGB")
  120.     return _lut(image, red + green + blue)
  121.  
  122. def crop(image, border=0):
  123.     "Crop border off image"
  124.     left, top, right, bottom = _border(border)
  125.     return image.crop(
  126.         (left, top, image.size[0]-right, image.size[1]-bottom)
  127.         )
  128.  
  129. def deform(image, deformer, resample=Image.BILINEAR):
  130.     "Deform image using the given deformer"
  131.     return image.transform(
  132.         image.size, MESH, deformer.getmesh(image), resample
  133.         )
  134.  
  135. def equalize(image):
  136.     "Equalize image histogram"
  137.     if image.mode == "P":
  138.         h = image.convert("RGB").histogram()
  139.     else:
  140.         h = image.histogram()
  141.     lut = []
  142.     for b in range(0, len(h), 256):
  143.         step = reduce(operator.add, h[b:b+256]) / 255
  144.         n = 0
  145.         for i in range(256):
  146.             lut.append(n / step)
  147.             n = n + h[i+b]
  148.     return _lut(image, lut)
  149.  
  150. def expand(image, border=0, fill=0):
  151.     "Add border to image"
  152.     left, top, right, bottom = _border(border)
  153.     width = left + image.size[0] + right
  154.     height = top + image.size[1] + buttom
  155.     out = Image.new(image.mode, (width, height), fill)
  156.     out.paste((left, top), image)
  157.     return out
  158.  
  159. def fit(image, size, method=Image.NEAREST, bleed=0.0, centering=(0.5, 0.5)):
  160.     """
  161.     This method returns a sized and cropped version of the image,
  162.     cropped to the aspect ratio and size that you request.  It can be
  163.     customized to your needs with "method", "bleed", and "centering"
  164.     as required.
  165.  
  166.     image: a PIL Image object
  167.  
  168.     size: output size in pixels, given as a (width, height) tuple
  169.  
  170.     method: resampling method
  171.  
  172.     bleed: decimal percentage (0-0.49999) of width/height to crop off
  173.     as a minumum around the outside of the image This allows you to
  174.     remove a default amount of the image around the outside, for
  175.     'cleaning up' scans that may have edges of negs showing, or
  176.     whatever.  This percentage is removed from EACH side, not a total
  177.     amount.
  178.  
  179.     centering: (left, top), percentages to crop of each side to fit
  180.     the aspect ratio you require.
  181.  
  182.     This function allows you to customize where the crop occurs,
  183.     whether it is a 'center crop' or a 'top crop', or whatever.
  184.     Default is center-cropped.
  185.  
  186.     (0.5, 0.5) is center cropping (i.e. if cropping the width, take
  187.     50% off of the left side (and therefore 50% off the right side),
  188.     and same with Top/Bottom)
  189.  
  190.     (0.0, 0.0) will crop from the top left corner (i.e. if cropping
  191.     the width, take all of the crop off of the right side, and if
  192.     cropping the height, take all of it off the bottom)
  193.  
  194.     (1.0, 0.0) will crop from the bottom left corner, etc. (i.e. if
  195.     cropping the width, take all of the crop off the left side, and if
  196.     cropping the height take none from the Top (and therefore all off
  197.     the bottom))
  198.  
  199.     by Kevin Cazabon, Feb 17/2000
  200.     kevin@cazabon.com
  201.     http://www.cazabon.com
  202.     """
  203.  
  204.     # ensure inputs are valid
  205.     if type(centering) != type([]):
  206.         centering = [centering[0], centering[1]]
  207.  
  208.     if centering[0] > 1.0 or centering[0] < 0.0:
  209.         centering [0] = 0.50
  210.     if centering[1] > 1.0 or centering[1] < 0.0:
  211.         centering[1] = 0.50
  212.  
  213.     if bleed > 0.49999 or bleed < 0.0:
  214.         bleed = 0.0
  215.  
  216.     # calculate the area to use for resizing and cropping, subtracting
  217.     # the 'bleed' around the edges
  218.  
  219.     # number of pixels to trim off on Top and Bottom, Left and Right
  220.     bleedPixels = (
  221.         int((float(bleed) * float(image.size[0])) + 0.5),
  222.         int((float(bleed) * float(image.size[1])) + 0.5)
  223.         )
  224.  
  225.     liveArea = (
  226.         bleedPixels[0], bleedPixels[1], image.size[0] - bleedPixels[0] - 1,
  227.         image.size[1] - bleedPixels[1] - 1
  228.         )
  229.  
  230.     liveSize = (liveArea[2] - liveArea[0], liveArea[3] - liveArea[1])
  231.  
  232.     # calculate the aspect ratio of the liveArea
  233.     liveAreaAspectRatio = float(liveSize[0])/float(liveSize[1])
  234.  
  235.     # calculate the aspect ratio of the output image
  236.     aspectRatio = float(size[0]) / float(size[1])
  237.  
  238.     # figure out if the sides or top/bottom will be cropped off
  239.     if liveAreaAspectRatio >= aspectRatio:
  240.         # liveArea is wider than what's needed, crop the sides
  241.         cropWidth = int((aspectRatio * float(liveSize[1])) + 0.5)
  242.         cropHeight = liveSize[1]
  243.     else:
  244.         # liveArea is taller than what's needed, crop the top and bottom
  245.         cropWidth = liveSize[0]
  246.         cropHeight = int((float(liveSize[0])/aspectRatio) + 0.5)
  247.  
  248.     # make the crop
  249.     leftSide = int(liveArea[0] + (float(liveSize[0]-cropWidth) * centering[0]))
  250.     if leftSide < 0:
  251.         leftSide = 0
  252.     topSide = int(liveArea[1] + (float(liveSize[1]-cropHeight) * centering[1]))
  253.     if topSide < 0:
  254.         topSide = 0
  255.  
  256.     out = image.crop(
  257.         (leftSide, topSide, leftSide + cropWidth, topSide + cropHeight)
  258.         )
  259.  
  260.     # resize the image and return it
  261.     return out.resize(size, method)
  262.  
  263. def flip(image):
  264.     "Flip image vertically"
  265.     return image.transpose(Image.FLIP_TOP_BOTTOM)
  266.  
  267. def grayscale(image):
  268.     "Convert to grayscale"
  269.     return image.convert("L")
  270.  
  271. def invert(image):
  272.     "Invert image (negative)"
  273.     lut = []
  274.     for i in range(256):
  275.         lut.append(255-i)
  276.     return _lut(image, lut)
  277.  
  278. def mirror(image):
  279.     "Flip image horizontally"
  280.     return image.transpose(Image.FLIP_LEFT_RIGHT)
  281.  
  282. def posterize(image, bits):
  283.     "Reduce the number of bits per color channel"
  284.     lut = []
  285.     mask = ~(2**(8-bits)-1)
  286.     for i in range(256):
  287.         lut.append(i & mask)
  288.     return _lut(image, lut)
  289.  
  290. def solarize(image, threshold=128):
  291.     "Invert all values above threshold"
  292.     lut = []
  293.     for i in range(256):
  294.         if i < threshold:
  295.             lut.append(i)
  296.         else:
  297.             lut.append(255-i)
  298.     return _lut(image, lut)
  299.