def process(self, image): """ Args: image: The image to process. Returns: a single image, or a list containing one or more images. """ BaseFilter.process(self, image) # Create the mask around the source image mask = image.split()[-1] if image.mode[-1] != 'A' or isSimpleBBox(mask): mask = createMask(image, threshold=self._threshold, fillHoles=True, backgroundColor=self.background, blurRadius=self._blurRadius, maskScale=self._maskScale) # Process each value newImages = [] for value in self._values: if value is None: value = self.background bg = ImageChops.constant(image, value) newImage = Image.composite(image.split()[0], bg, mask) newImage.putalpha(image.split()[-1]) newImages.append(newImage) if len(newImages) == 1: return newImages[0] else: return newImages
def process(self, image): """ Args: image: The image to process. Returns: a single image, or a list containing one or more images. """ BaseFilter.process(self, image) if self.box[2] > image.size[0] or self.box[3] > image.size[1]: raise RuntimeError('Crop coordinates exceed image bounds') return image.crop(self.box)
def process(self, image): """ Args: image: The image to process. Returns: a single image, or a list containing one or more images. """ BaseFilter.process(self, image) mask = image.split()[1] for i in range(self.level): sharpness_enhancer = ImageEnhance.Sharpness(image.split()[0]) image = sharpness_enhancer.enhance(0.0) image.putalpha(mask) return image
def process(self, image): """ Args: image: The image to process. Returns: a single image, or a list containing one or more images. """ BaseFilter.process(self, image) if self.mode != 'gray': raise RuntimeError("EqualizeHistogram only supports grayscale images.") if self.region == 'bbox': bbox = image.split()[1].getbbox() croppedImage = image.crop(bbox) croppedImage.load() alpha = croppedImage.split()[1] croppedImage = ImageOps.equalize(croppedImage.split()[0]) croppedImage.putalpha(alpha) image.paste(croppedImage, bbox) elif self.region == 'mask': bbox = image.split()[1].getbbox() croppedImage = image.crop(bbox) croppedImage.load() alpha = croppedImage.split()[1] # Fill in the part of the cropped image outside the bounding box with # uniformly-distributed noise noiseArray = \ numpy.random.randint(0, 255, croppedImage.size[0]*croppedImage.size[1]) noiseImage = Image.new('L', croppedImage.size) noiseImage.putdata(noiseArray) compositeImage = Image.composite(croppedImage, noiseImage, alpha) # Equalize the composite image compositeImage = ImageOps.equalize(compositeImage.split()[0]) # Paste the part of the equalized image within the mask back # into the cropped image croppedImage = Image.composite(compositeImage, croppedImage, alpha) croppedImage.putalpha(alpha) # Paste the cropped image back into the full image image.paste(croppedImage, bbox) elif self.region == 'all': alpha = image.split()[1] image = ImageOps.equalize(image.split()[0]) image.putalpha(alpha) return image
def process(self, image): """ Args: image: The image to process Returns: a single image, or a list containing one or more images """ BaseFilter.process(self, image) if self.mode != 'gray': raise RuntimeError("NormalizeContrast only supports grayscale images.") if self.region == 'bbox': bbox = image.split()[1].getbbox() croppedImage = image.crop(bbox) croppedImage.load() alpha = croppedImage.split()[1] croppedImage = \ ImageOps.autocontrast(croppedImage.split()[0], cutoff=self.cutoff) croppedImage.putalpha(alpha) image.paste(croppedImage, image.bbox) elif self.region == 'mask': bbox = image.split()[1].getbbox() croppedImage = image.crop(bbox) croppedImage.load() alpha = croppedImage.split()[1] # Fill in the part of the cropped image outside the bounding box with a # uniform shade of gray grayImage = ImageChops.constant(croppedImage, 128) compositeImage = Image.composite(croppedImage, grayImage, alpha) # Equalize the composite image compositeImage = ImageOps.autocontrast(compositeImage.split()[0], cutoff=self.cutoff) # Paste the part of the equalized image within the mask back # into the cropped image croppedImage = Image.composite(compositeImage, croppedImage, alpha) croppedImage.putalpha(alpha) # Paste the cropped image back into the full image image.paste(croppedImage, bbox) elif self.region == 'all': alpha = image.split()[1] image = ImageOps.autocontrast(image.split()[0], cutoff=self.cutoff) image.putalpha(alpha) return image
def process(self, image): """ TODO check bounding box """ BaseFilter.process(self, image) image = image.convert('LA') matrix = [1, 0, self.x_axis, 0, 1, self.y_axis, 0, 0, 1] translated_image = image.transform(image.size, Image.AFFINE, matrix) # Create a new larger image to hold the translated image # It is filled with the background color and an alpha value of 0 outputImage = Image.new('LA', translated_image.size, (self.background, 0)) # Paste the translated image into the new image, using the image's # alpha channel as a mask # This effectively just fills the area around the rotation with the # background color, and imports the alpha channel from the translated image outputImage.paste(translated_image, None, translated_image.split()[1]) outputImage = outputImage.convert('L') return outputImage
def process(self, image): """ TODO check bounding box """ BaseFilter.process(self, image) image = image.convert("LA") matrix = [1, 0, self.x_axis, 0, 1, self.y_axis, 0, 0, 1] translated_image = image.transform(image.size, Image.AFFINE, matrix) # Create a new larger image to hold the translated image # It is filled with the background color and an alpha value of 0 outputImage = Image.new("LA", translated_image.size, (self.background, 0)) # Paste the translated image into the new image, using the image's # alpha channel as a mask # This effectively just fills the area around the rotation with the # background color, and imports the alpha channel from the translated image outputImage.paste(translated_image, None, translated_image.split()[1]) outputImage = outputImage.convert("L") return outputImage
def process(self, image): """ Args: image: The image to process. Returns: a single image, or a list containing one or more images. """ BaseFilter.process(self, image) sizes = [] for i, size in enumerate(self.sizes): if len(size) == 1: # Convert scalar sizes to absolute sizes in pixels sizes.append((int(round(image.size[0]*float(size[0]))), int(round(image.size[1]*float(size[0]))))) else: sizes.append((int(size[0]), int(size[1]))) newImages = [] for size in sizes: if image.size == size: newImage = image elif self.method == 'fit': # Resize the image to fit in the target size, preserving aspect ratio targetRatio = size[0] / float(size[1]) imageRatio = image.size[0] / float(image.size[1]) if imageRatio > targetRatio: xSize = size[0] scale = size[0] / float(image.size[0]) ySize = int(scale * image.size[1]) else: ySize = size[1] scale = size[1] / float(image.size[1]) xSize = int(scale * image.size[0]) newImage = self._resize(image, (xSize, ySize)) # Pad with the background color if necessary if newImage.size != size: paddedImage = Image.new('LA', size, self.background) paddedImage.paste(newImage, ((size[0] - newImage.size[0])/2, (size[1] - newImage.size[1])/2)) newImage = paddedImage elif self.method == 'crop': # Resize the image to fill the new size targetRatio = size[0] / float(size[1]) imageRatio = image.size[0] / float(image.size[1]) if imageRatio > targetRatio: # Original image is too wide scale = size[1] / float(image.size[1]) newSize = (int(scale * image.size[0]), size[1]) cropStart = ((newSize[0] - size[0]) / 2, 0) else: # Original image is too tall scale = size[0] / float(image.size[0]) newSize = (size[0], int(scale * image.size[1])) cropStart = (0, (newSize[1] - size[1]) / 2) newImage = self._resize(image, newSize) # Crop if necessary if newSize != size: newImage = newImage.crop((cropStart[0], cropStart[1], cropStart[0] + size[0], cropStart[1] + size[1])) elif self.method == 'stretch': # Resize the image to each target size, ignoring aspect ratio newImage = self._resize(image, size) elif self.method == 'center': # Center the original image in the new image without rescaling it newImage = Image.new('LA', size, self.background) x = (size[0] - image.size[0]) / 2 y = (size[1] - image.size[1]) / 2 newImage.paste(image, (x, y)) newImages.append(newImage) if not self.simultaneous: if len(newImages) == 1: return newImages[0] else: return newImages else: return [newImages] def getOutputCount(self): """Return the number of images returned by each call to process(). If the filter creates multiple simultaneous outputs, return a tuple: (outputCount, simultaneousOutputCount). """ if not self.simultaneous: return len(self.sizes) else: return 1, len(self.sizes) def _resize(self, image, size): """Resize the image with the appropriate sampling method. """ if self.highQuality: if size < image.size: return image.resize(size, Image.ANTIALIAS) else: return image.resize(size, Image.BICUBIC) else: return image.resize(size)
def process(self, image): """ Args: image: The image to process Returns: a single image, or a list containing one or more images """ # Get our random state back saveState = numpy.random.get_state() numpy.random.set_state(self._randomState) # Send through parent class first BaseFilter.process(self, image) alpha = image.split()[1] # ----------------------------------------------------------------------- # black and white if self.mode == 'bw': # For black and white images, our doBackground pixels are 255 and our figure pixels # are 0. pixels = numpy.array(image.split()[0].getdata(), dtype=int) noise = numpy.random.random(len(pixels)) # get array of floats from 0 to 1 if self.doForeground and self.doBackground: noise = numpy.array(noise < self.noiseLevel, dtype=int) * 255 pixels -= noise pixels = numpy.abs(pixels) else: # "Flip" self.noiseLevel percent of the foreground pixels # We only want to add noise to the figure, so we will flip some percent of the # 0 pixels. if self.doForeground: noise = numpy.array(noise < self.noiseLevel, dtype=int) * 255 pixels |= noise # "Flip" self.noiseLevel percent of the background pixels # We only want to add noise to the background, so we will flip some percent of the # 255 pixels. if self.doBackground: noise = numpy.array(noise > self.noiseLevel, dtype=int) * 255 pixels &= noise # ----------------------------------------------------------------------- # gray-scale elif self.mode == 'gray': pixels = numpy.array(image.split()[0].getdata(), dtype=int) noise = numpy.random.random(len(pixels)) # get array of floats from 0 to 1 # Add +/- self.noiseLevel to each pixel noise = (noise - 0.5) * 2 * self.noiseLevel * 256 mask = numpy.array(alpha.getdata(), dtype=int) != 0 if self.doForeground and self.doBackground: pixels += noise elif self.doForeground: pixels[mask != 0] += noise[mask != 0] elif self.doBackground: pixels[mask == 0] += noise[mask == 0] pixels = pixels.clip(min=0, max=255) else: raise "AddNoise Filter: this image mode not supported" # write out the new pixels newimage = Image.new(image.mode, image.size) newimage.putdata(pixels) newimage.putalpha(alpha) # If generating dynamic noise, change our random state each time. if self.dynamic: self._randomState = numpy.random.get_state() # Restore random state numpy.random.set_state(saveState) return newimage
def process(self, image): """ Args: image: The image to process. Returns: a single image, or a list containing one or more images. """ BaseFilter.process(self, image) if not self.expand and self.targetRatio: # Pad the image to the aspect ratio of the sensor # This allows us to rotate in expand=False without cutting off parts # of the image unnecessarily # Unlike expand=True, the object doesn't get smaller ratio = (image.size[0] / float(image.size[1])) if ratio < self.targetRatio: # Make image wider size = (int(image.size[0] * self.targetRatio / ratio), image.size[1]) newImage = Image.new('LA', size, (self.background, 0)) newImage.paste(image, ((newImage.size[0] - image.size[0])/2, 0)) image = newImage elif ratio > self.targetRatio: # Make image taller size = (image.size[0], int(image.size[1] * ratio / self.targetRatio)) newImage = Image.new('LA', size, (self.background, 0)) newImage.paste(image, (0, (newImage.size[1] - image.size[1])/2)) image = newImage if self.highQuality: resample = Image.BICUBIC else: resample = Image.NEAREST outputs = [] for angle in self.angles: # Rotate the image, which expands it and pads it with black and a 0 image = image.convert('LA') # alpha value rotatedImage = image.rotate(angle, resample=resample, expand=self.expand) # Create a new larger image to hold the rotated image # It is filled with the background color and an alpha value of 0 outputImage = Image.new('LA', rotatedImage.size, (self.background, 0)) # Paste the rotated image into the new image, using the rotated image's # alpha channel as a mask # This effectively just fills the area around the rotation with the # background color, and imports the alpha channel from the rotated image outputImage.paste(rotatedImage, None, rotatedImage.split()[1]) outputs.append(outputImage.convert('L')) return outputs def getOutputCount(self): """ Return the number of images returned by each call to process(). If the filter creates multiple simultaneous outputs, return a tuple: (outputCount, simultaneousOutputCount). """ return len(self.angles)