diff options
Diffstat (limited to 'PIL/ImageOps.py')
-rw-r--r-- | PIL/ImageOps.py | 408 |
1 files changed, 0 insertions, 408 deletions
diff --git a/PIL/ImageOps.py b/PIL/ImageOps.py deleted file mode 100644 index 89b5e72..0000000 --- a/PIL/ImageOps.py +++ /dev/null @@ -1,408 +0,0 @@ -# -# The Python Imaging Library. -# $Id: ImageOps.py 2760 2006-06-19 13:31:40Z fredrik $ -# -# standard image operations -# -# History: -# 2001-10-20 fl Created -# 2001-10-23 fl Added autocontrast operator -# 2001-12-18 fl Added Kevin's fit operator -# 2004-03-14 fl Fixed potential division by zero in equalize -# 2005-05-05 fl Fixed equalize for low number of values -# -# Copyright (c) 2001-2004 by Secret Labs AB -# Copyright (c) 2001-2004 by Fredrik Lundh -# -# See the README file for information on usage and redistribution. -# - -import Image -import operator - -## -# (New in 1.1.3) The <b>ImageOps</b> module contains a number of -# 'ready-made' image processing operations. This module is somewhat -# experimental, and most operators only work on L and RGB images. -# -# @since 1.1.3 -## - -# -# helpers - -def _border(border): - if type(border) is type(()): - if len(border) == 2: - left, top = right, bottom = border - elif len(border) == 4: - left, top, right, bottom = border - else: - left = top = right = bottom = border - return left, top, right, bottom - -def _color(color, mode): - if Image.isStringType(color): - import ImageColor - color = ImageColor.getcolor(color, mode) - return color - -def _lut(image, lut): - if image.mode == "P": - # FIXME: apply to lookup table, not image data - raise NotImplementedError("mode P support coming soon") - elif image.mode in ("L", "RGB"): - if image.mode == "RGB" and len(lut) == 256: - lut = lut + lut + lut - return image.point(lut) - else: - raise IOError, "not supported for this image mode" - -# -# actions - -## -# Maximize (normalize) image contrast. This function calculates a -# histogram of the input image, removes <i>cutoff</i> percent of the -# lightest and darkest pixels from the histogram, and remaps the image -# so that the darkest pixel becomes black (0), and the lightest -# becomes white (255). -# -# @param image The image to process. -# @param cutoff How many percent to cut off from the histogram. -# @param ignore The background pixel value (use None for no background). -# @return An image. - -def autocontrast(image, cutoff=0, ignore=None): - "Maximize image contrast, based on histogram" - histogram = image.histogram() - lut = [] - for layer in range(0, len(histogram), 256): - h = histogram[layer:layer+256] - if ignore is not None: - # get rid of outliers - try: - h[ignore] = 0 - except TypeError: - # assume sequence - for ix in ignore: - h[ix] = 0 - if cutoff: - # cut off pixels from both ends of the histogram - # get number of pixels - n = 0 - for ix in range(256): - n = n + h[ix] - # remove cutoff% pixels from the low end - cut = n * cutoff / 100 - for lo in range(256): - if cut > h[lo]: - cut = cut - h[lo] - h[lo] = 0 - else: - h[lo] = h[lo] - cut - cut = 0 - if cut <= 0: - break - # remove cutoff% samples from the hi end - cut = n * cutoff / 100 - for hi in range(255, -1, -1): - if cut > h[hi]: - cut = cut - h[hi] - h[hi] = 0 - else: - h[hi] = h[hi] - cut - cut = 0 - if cut <= 0: - break - # find lowest/highest samples after preprocessing - for lo in range(256): - if h[lo]: - break - for hi in range(255, -1, -1): - if h[hi]: - break - if hi <= lo: - # don't bother - lut.extend(range(256)) - else: - scale = 255.0 / (hi - lo) - offset = -lo * scale - for ix in range(256): - ix = int(ix * scale + offset) - if ix < 0: - ix = 0 - elif ix > 255: - ix = 255 - lut.append(ix) - return _lut(image, lut) - -## -# Colorize grayscale image. The <i>black</i> and <i>white</i> -# arguments should be RGB tuples; this function calculates a colour -# wedge mapping all black pixels in the source image to the first -# colour, and all white pixels to the second colour. -# -# @param image The image to colourize. -# @param black The colour to use for black input pixels. -# @param white The colour to use for white input pixels. -# @return An image. - -def colorize(image, black, white): - "Colorize a grayscale image" - assert image.mode == "L" - black = _color(black, "RGB") - white = _color(white, "RGB") - red = []; green = []; blue = [] - for i in range(256): - red.append(black[0]+i*(white[0]-black[0])/255) - green.append(black[1]+i*(white[1]-black[1])/255) - blue.append(black[2]+i*(white[2]-black[2])/255) - image = image.convert("RGB") - return _lut(image, red + green + blue) - -## -# Remove border from image. The same amount of pixels are removed -# from all four sides. This function works on all image modes. -# -# @param image The image to crop. -# @param border The number of pixels to remove. -# @return An image. -# @see Image#Image.crop - -def crop(image, border=0): - "Crop border off image" - left, top, right, bottom = _border(border) - return image.crop( - (left, top, image.size[0]-right, image.size[1]-bottom) - ) - -## -# Deform the image. -# -# @param image The image to deform. -# @param deformer A deformer object. Any object that implements a -# <b>getmesh</b> method can be used. -# @param resample What resampling filter to use. -# @return An image. - -def deform(image, deformer, resample=Image.BILINEAR): - "Deform image using the given deformer" - return image.transform( - image.size, Image.MESH, deformer.getmesh(image), resample - ) - -## -# Equalize the image histogram. This function applies a non-linear -# mapping to the input image, in order to create a uniform -# distribution of grayscale values in the output image. -# -# @param image The image to equalize. -# @param mask An optional mask. If given, only the pixels selected by -# the mask are included in the analysis. -# @return An image. - -def equalize(image, mask=None): - "Equalize image histogram" - if image.mode == "P": - image = image.convert("RGB") - h = image.histogram(mask) - lut = [] - for b in range(0, len(h), 256): - histo = filter(None, h[b:b+256]) - if len(histo) <= 1: - lut.extend(range(256)) - else: - step = (reduce(operator.add, histo) - histo[-1]) / 255 - if not step: - lut.extend(range(256)) - else: - n = step / 2 - for i in range(256): - lut.append(n / step) - n = n + h[i+b] - return _lut(image, lut) - -## -# Add border to the image -# -# @param image The image to expand. -# @param border Border width, in pixels. -# @param fill Pixel fill value (a colour value). Default is 0 (black). -# @return An image. - -def expand(image, border=0, fill=0): - "Add border to image" - left, top, right, bottom = _border(border) - width = left + image.size[0] + right - height = top + image.size[1] + bottom - out = Image.new(image.mode, (width, height), _color(fill, image.mode)) - out.paste(image, (left, top)) - return out - -## -# Returns a sized and cropped version of the image, cropped to the -# requested aspect ratio and size. -# <p> -# The <b>fit</b> function was contributed by Kevin Cazabon. -# -# @param size The requested output size in pixels, given as a -# (width, height) tuple. -# @param method What resampling method to use. Default is Image.NEAREST. -# @param bleed Remove a border around the outside of the image (from all -# four edges. The value is a decimal percentage (use 0.01 for one -# percent). The default value is 0 (no border). -# @param centering Control the cropping position. Use (0.5, 0.5) for -# center cropping (e.g. if cropping the width, take 50% off of the -# left side, and therefore 50% off the right side). (0.0, 0.0) -# will crop from the top left corner (i.e. if cropping the width, -# take all of the crop off of the right side, and if cropping the -# height, take all of it off the bottom). (1.0, 0.0) will crop -# from the bottom left corner, etc. (i.e. if cropping the width, -# take all of the crop off the left side, and if cropping the height -# take none from the top, and therefore all off the bottom). -# @return An image. - -def fit(image, size, method=Image.NEAREST, bleed=0.0, centering=(0.5, 0.5)): - """ - This method returns a sized and cropped version of the image, - cropped to the aspect ratio and size that you request. - """ - - # by Kevin Cazabon, Feb 17/2000 - # kevin@cazabon.com - # http://www.cazabon.com - - # ensure inputs are valid - if type(centering) != type([]): - centering = [centering[0], centering[1]] - - if centering[0] > 1.0 or centering[0] < 0.0: - centering [0] = 0.50 - if centering[1] > 1.0 or centering[1] < 0.0: - centering[1] = 0.50 - - if bleed > 0.49999 or bleed < 0.0: - bleed = 0.0 - - # calculate the area to use for resizing and cropping, subtracting - # the 'bleed' around the edges - - # number of pixels to trim off on Top and Bottom, Left and Right - bleedPixels = ( - int((float(bleed) * float(image.size[0])) + 0.5), - int((float(bleed) * float(image.size[1])) + 0.5) - ) - - liveArea = ( - bleedPixels[0], bleedPixels[1], image.size[0] - bleedPixels[0] - 1, - image.size[1] - bleedPixels[1] - 1 - ) - - liveSize = (liveArea[2] - liveArea[0], liveArea[3] - liveArea[1]) - - # calculate the aspect ratio of the liveArea - liveAreaAspectRatio = float(liveSize[0])/float(liveSize[1]) - - # calculate the aspect ratio of the output image - aspectRatio = float(size[0]) / float(size[1]) - - # figure out if the sides or top/bottom will be cropped off - if liveAreaAspectRatio >= aspectRatio: - # liveArea is wider than what's needed, crop the sides - cropWidth = int((aspectRatio * float(liveSize[1])) + 0.5) - cropHeight = liveSize[1] - else: - # liveArea is taller than what's needed, crop the top and bottom - cropWidth = liveSize[0] - cropHeight = int((float(liveSize[0])/aspectRatio) + 0.5) - - # make the crop - leftSide = int(liveArea[0] + (float(liveSize[0]-cropWidth) * centering[0])) - if leftSide < 0: - leftSide = 0 - topSide = int(liveArea[1] + (float(liveSize[1]-cropHeight) * centering[1])) - if topSide < 0: - topSide = 0 - - out = image.crop( - (leftSide, topSide, leftSide + cropWidth, topSide + cropHeight) - ) - - # resize the image and return it - return out.resize(size, method) - -## -# Flip the image vertically (top to bottom). -# -# @param image The image to flip. -# @return An image. - -def flip(image): - "Flip image vertically" - return image.transpose(Image.FLIP_TOP_BOTTOM) - -## -# Convert the image to grayscale. -# -# @param image The image to convert. -# @return An image. - -def grayscale(image): - "Convert to grayscale" - return image.convert("L") - -## -# Invert (negate) the image. -# -# @param image The image to invert. -# @return An image. - -def invert(image): - "Invert image (negate)" - lut = [] - for i in range(256): - lut.append(255-i) - return _lut(image, lut) - -## -# Flip image horizontally (left to right). -# -# @param image The image to mirror. -# @return An image. - -def mirror(image): - "Flip image horizontally" - return image.transpose(Image.FLIP_LEFT_RIGHT) - -## -# Reduce the number of bits for each colour channel. -# -# @param image The image to posterize. -# @param bits The number of bits to keep for each channel (1-8). -# @return An image. - -def posterize(image, bits): - "Reduce the number of bits per color channel" - lut = [] - mask = ~(2**(8-bits)-1) - for i in range(256): - lut.append(i & mask) - return _lut(image, lut) - -## -# Invert all pixel values above a threshold. -# -# @param image The image to posterize. -# @param threshold All pixels above this greyscale level are inverted. -# @return An image. - -def solarize(image, threshold=128): - "Invert all values above threshold" - lut = [] - for i in range(256): - if i < threshold: - lut.append(i) - else: - lut.append(255-i) - return _lut(image, lut) |