def process(self, image): """ @param image -- The image to process. Returns a single image, or a list containing one or more images. """ BaseFilter.process(self, image) base, alpha = image.split() if self.scaleTowardCenter: scale = float(self.factor) assert base.mode == "L" maxValue = 255 # TODO: Determine how to get maximum value __allowed__. offset = ((1.0 - self.factor) / 2.0) * maxValue newImage = ImageMath.eval( "convert(convert(gray, 'F') * scale + offset, mode)", gray=base, scale=scale, offset=offset, mode=base.mode, ) else: contrastEnhancer = ImageEnhance.Contrast(image.split()[0]) newImage = contrastEnhancer.enhance(self.factor) newImage.putalpha(alpha) return newImage
def process(self, image): """ @param image -- The image to process. Returns a single image, or a list containing one or more images. """ BaseFilter.process(self, image) s = min(image.size) sizeRange = [0, s] imageArray = numpy.array(image.split()[0].getdata()) newImage = Image.new("LA", image.size) newImage.putdata([uint(p) for p in imageArray]) newImage.putalpha(image.split()[1]) for i in xrange(int(self.difficulty * self.maxLines)): # Generate random line start = (random.randint(sizeRange[0], sizeRange[1]), random.randint(sizeRange[0], sizeRange[1])) end = (random.randint(sizeRange[0], sizeRange[1]), random.randint(sizeRange[0], sizeRange[1])) # Generate random color color = random.randint(0, 255) # Add the line to the image draw = ImageDraw.Draw(newImage) draw.line((start, end), fill=color) return newImage
def process(self, image): """ @param image -- The image to process. Returns a single image, or a list containing one or more images. """ BaseFilter.process(self, image) s = min(image.size) sizeRange = [int(0.1 * s), int(0.4 * s)] newArray = numpy.array(image.split()[0].getdata()) newArray.resize(image.size[1], image.size[0]) for j in xrange(self.numRectangles): # Generate random rectange size = (self.random.randint(sizeRange[0], sizeRange[1]), self.random.randint(sizeRange[0], sizeRange[1])) loc = [ self.random.randint(0, image.size[1]), self.random.randint(0, image.size[0]) ] # Move the location so that the rectangle is centered on it loc[0] -= size[0] / 2 loc[1] -= size[1] / 2 # Generate random color color = self.random.randint(0, 255) # Add the rectangle to the image newArray[max(0,loc[0]):min(newArray.shape[0], loc[0]+size[0]), \ max(0,loc[1]):min(newArray.shape[1],loc[1]+size[1])] = color newImage = Image.new("L", image.size) newImage.putdata([uint(p) for p in newArray.flatten()]) newImage.putalpha(image.split()[1]) return newImage
def process(self, image): """ @param image -- The image to process. Returns a single image, or a list containing one or more images. """ BaseFilter.process(self, image) s = min(image.size) sizeRange = [int(0.1 * s), int(0.4 * s)] newArray = numpy.array(image.split()[0].getdata()) newArray.resize(image.size[1],image.size[0]) for j in xrange(self.numRectangles): # Generate random rectange size = (self.random.randint(sizeRange[0], sizeRange[1]), self.random.randint(sizeRange[0], sizeRange[1])) loc = [self.random.randint(0,image.size[1]), self.random.randint(0,image.size[0])] # Move the location so that the rectangle is centered on it loc[0] -= size[0]/2 loc[1] -= size[1]/2 # Generate random color color = self.random.randint(0,255) # Add the rectangle to the image newArray[max(0,loc[0]):min(newArray.shape[0], loc[0]+size[0]), \ max(0,loc[1]):min(newArray.shape[1],loc[1]+size[1])] = color newImage = Image.new("L", image.size) newImage.putdata([uint(p) for p in newArray.flatten()]) newImage.putalpha(image.split()[1]) return newImage
def process(self, image): """ @param image -- The image to process. Returns a single image, or a list containing one or more images. """ BaseFilter.process(self, image) mode = image.mode; originalSize = image.size; sizes = [(int(round(image.size[0]*s)), int(round(image.size[1]*s))) for s in self.scales] resizedImages = [] for size in sizes: if size < image.size: resizedImage = image.resize(size,Image.ANTIALIAS) else: resizedImage = image.resize(size,Image.BICUBIC) x = (originalSize[0] - size[0])/2 y = (originalSize[1] - size[1])/2 newImage = Image.new(mode,originalSize,self.background) newImage.paste(resizedImage,(x,y)) resizedImages.append(newImage) if not self.simultaneous: return resizedImages else: return [resizedImages]
def process(self, image): """ @param 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): """ @param image -- The image to process. Returns a single image, or a list containing one or more images. """ BaseFilter.process(self, image) #Create numpy array from image grayscale data and resize to image dimensions imageArray = numpy.array(image.split()[0].getdata()) imageArray.resize(image.size[1], image.size[0]) #Calculate offset from difficulty level offset = self.difficulty * (self.maxOffset) #Add random change to offset within window size halfWindowSize = 0.1 * offset offset = (offset - halfWindowSize) + halfWindowSize * self.random.random() * ( (-1)**self.random.randint(1, 2)) #Apply random direction offset *= ((-1)**self.random.randint(1, 2)) imageArray += offset #Recreate PIL image newImage = Image.new("L", image.size) newImage.putdata([uint(p) for p in imageArray.flatten()]) newImage.putalpha(image.split()[1]) return newImage
def process(self, image): """ @param image -- The image to process. Returns a single image, or a list containing one or more images. """ BaseFilter.process(self, image) mode = image.mode originalSize = image.size sizes = [(int(round(image.size[0] * s)), int(round(image.size[1] * s))) for s in self.scales] resizedImages = [] for size in sizes: if size < image.size: resizedImage = image.resize(size, Image.ANTIALIAS) else: resizedImage = image.resize(size, Image.BICUBIC) x = (originalSize[0] - size[0]) / 2 y = (originalSize[1] - size[1]) / 2 newImage = Image.new(mode, originalSize, self.background) newImage.paste(resizedImage, (x, y)) resizedImages.append(newImage) if not self.simultaneous: return resizedImages else: return [resizedImages]
def process(self, image): """ @param image -- The image to process. Returns a single image, or a list containing one or more images. """ BaseFilter.process(self, image) newImage = ImageOps.flip(image) return newImage
def process(self, image): """ 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 # 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) return outputs
def process(self, image): """ @param image -- The image to process. Returns a single image, or a list containing one or more images. """ BaseFilter.process(self, image) newImage = ImageOps.mirror(image) if not self.both: return newImage else: return [image, newImage]
def process(self, image): """ @param 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): """ @param image -- The image to process. Returns a single image, or a list containing one or more images. """ BaseFilter.process(self, image) brightnessEnhancer = ImageEnhance.Brightness(image.split()[0]) newImage = brightnessEnhancer.enhance(self.factor) newImage.putalpha(image.split()[1]) return newImage
def process(self, image): """ 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 # 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) return outputs
def process(self, image): """ @param image -- The image to process. Returns a single image, or a list containing one or more images. """ BaseFilter.process(self, image) type = self.random.choice(self.types) #Default matrix matrix = (1, 0, 0, 0, 1, 0) size = list(image.size) newImage = Image.new('LA', size) if type == 'shear_x': shear = self.difficulty*self.maxShear - self.difficulty*0.3 + self.difficulty*0.3*self.random.random() matrix = (1, shear, -shear*size[1], 0, 1, 0) size[0] += int(shear*size[0]) newImage = image.transform(tuple(size), Image.AFFINE, matrix) bbox = list(newImage.split()[1].getbbox()) bbox[1] = 0 bbox[3] = size[1] newImage = newImage.crop(bbox) elif type == 'shear_y': shear = self.difficulty*self.maxShear - self.difficulty*0.3 + self.difficulty*0.3*self.random.random() matrix = (1, 0, 0, shear, 1, -shear*size[0]) size[1] += int(shear*size[1]) newImage = image.transform(tuple(size), Image.AFFINE, matrix) bbox = list(newImage.split()[1].getbbox()) bbox[0] = 0 bbox[2] = size[0] newImage = newImage.crop(bbox) elif type == 'squeeze_x': squeeze = self.minSqueeze - (self.minSqueeze - self.maxSqueeze)*(self.difficulty - self.difficulty*0.3 + self.difficulty*0.3*self.random.random()) matrix = (1/squeeze, 0, 0, 0, 1, 0) newImage = ImageChops.offset(image.transform(tuple(size), Image.AFFINE, matrix), int((size[0] - squeeze*size[0])/2), 0) elif type == 'squeeze_y': squeeze = self.minSqueeze - (self.minSqueeze - self.maxSqueeze)*(self.difficulty - self.difficulty*0.3 + self.difficulty*0.3*self.random.random()) matrix = (1, 0, 0, 0, 1/squeeze, 0) newImage = ImageChops.offset(image.transform(tuple(size), Image.AFFINE, matrix), 0, int((size[1] - squeeze*size[1])/2)) #Appropriate sizing if newImage.size[0] > image.size[0] or newImage.size[1] > image.size[1]: newImage = newImage.resize(image.size) elif newImage.size[1] < image.size[1]: retImage = Image.new('LA', image.size) retImage.paste(newImage, (0, int((image.size[1] - newImage.size[1])/2.0))) newImage = retImage elif newImage.size[0] < image.size[0]: retImage = Image.new('LA', image.size) retImage.paste(newImage, (0, int((image.size[0] - newImage.size[0])/2.0))) return newImage
def process(self, image): """ @param image -- The image to process. Returns a single image, or a list containing one or more images. """ BaseFilter.process(self, image) if image.size == (self.width, self.height): return image # Resize the image targetRatio = self.width / float(self.height) imageRatio = image.size[0] / float(image.size[1]) if self.scaleHeightTo: ySize = self.scaleHeightTo scaleFactor = self.scaleHeightTo / float(image.size[1]) xSize = int(scaleFactor * image.size[0]) elif self.scaleWidthTo: xSize = self.scaleWidthTo scaleFactor = self.scaleWidthTo / float(image.size[0]) ySize = int(scaleFactor * image.size[1]) else: if imageRatio > targetRatio: xSize = self.width scaleFactor = self.width / float(image.size[0]) ySize = int(scaleFactor * image.size[1]) else: ySize = self.height scaleFactor = self.height / float(image.size[1]) xSize = int(scaleFactor * image.size[0]) if (xSize, ySize) < image.size: image = image.resize((xSize, ySize),Image.ANTIALIAS) else: image = image.resize((xSize, ySize),Image.BICUBIC) # Pad the image if necessary if self.pad and image.size != (self.width, self.height): paddedImage = Image.new('L', (self.width, self.height), self.background) alpha = Image.new('L', (self.width, self.height)) paddedImage.putalpha(alpha) paddedImage.paste(image, ((self.width - image.size[0])/2, (self.height - image.size[1])/2)) image = paddedImage return image
def process(self, image): """ @param image -- The image to process. Returns a single image, or a list containing one or more images. """ BaseFilter.process(self, image) if image.size == (self.width, self.height): return image # Resize the image targetRatio = self.width / float(self.height) imageRatio = image.size[0] / float(image.size[1]) if self.scaleHeightTo: ySize = self.scaleHeightTo scaleFactor = self.scaleHeightTo / float(image.size[1]) xSize = int(scaleFactor * image.size[0]) elif self.scaleWidthTo: xSize = self.scaleWidthTo scaleFactor = self.scaleWidthTo / float(image.size[0]) ySize = int(scaleFactor * image.size[1]) else: if imageRatio > targetRatio: xSize = self.width scaleFactor = self.width / float(image.size[0]) ySize = int(scaleFactor * image.size[1]) else: ySize = self.height scaleFactor = self.height / float(image.size[1]) xSize = int(scaleFactor * image.size[0]) if (xSize, ySize) < image.size: image = image.resize((xSize, ySize), Image.ANTIALIAS) else: image = image.resize((xSize, ySize), Image.BICUBIC) # Pad the image if necessary if self.pad and image.size != (self.width, self.height): paddedImage = Image.new('L', (self.width, self.height), self.background) alpha = Image.new('L', (self.width, self.height)) paddedImage.putalpha(alpha) paddedImage.paste(image, ((self.width - image.size[0]) / 2, (self.height - image.size[1]) / 2)) image = paddedImage return image
def process(self, image): """ @param 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 xrange(self.level): sharpness_enhancer = ImageEnhance.Sharpness(image.split()[0]) image = sharpness_enhancer.enhance(0.0) image.putalpha(mask) return image
def process(self, image): """ @param image -- The image to process. Returns a single image, or a list containing one or more images. """ BaseFilter.process(self, image) #Type of gradient? type = self.random.choice(self.types) gradientImage = self.gradientImages.get((image.size, type)) if not gradientImage: #Gradient image, used as mask gradientImage = Image.new("L", image.size) gradientArray = numpy.array(gradientImage.split()[0].getdata()) gradientArray.resize(image.size[1], image.size[0]) #Calculate gradient opacity = self.difficulty - self.difficulty * .2 + self.random.random( ) * self.difficulty * .2 for i in xrange(image.size[1]): for j in xrange(image.size[0]): if type == 'horizontal': gradientArray[i][j] = int( float(j) / image.size[0] * 255 / opacity) elif type == 'vertical': gradientArray[i][j] = int( float(i) / image.size[1] * 255 / opacity) elif type == 'circular': gradientArray[i][j] = int( math.sqrt((i - image.size[1] / 2)**2 + (j - image.size[0] / 2)**2) / math.sqrt((image.size[1] / 2)**2 + (image.size[0] / 2)**2) * 255 / opacity) gradientImage.putdata([uint(p) for p in gradientArray.flatten()]) #Add gradient image to dictionary self.gradientImages[(image.size, type)] = gradientImage #Image to composite with for brightness whiteImage = Image.new("LA", image.size) whiteArray = numpy.array(whiteImage.split()[0].getdata()) whiteArray += 255 whiteImage.putdata([uint(p) for p in whiteArray]) newImage = Image.composite(image, whiteImage, gradientImage) return newImage
def process(self, image): """ @param 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([uint(p) for p in 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): """ @param 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([uint(p) for p in 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): """ @param 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): """ @param image -- The image to process. Returns a single image """ BaseFilter.process(self, image) newImage = image # Shifting by more than one pixel can cause problems, so even if # stepSize > 1, get there by thickening by one shift at a time for x in xrange(-self.shiftSize,self.shiftSize+1): for y in xrange(-self.shiftSize,self.shiftSize+1): offsetImage = ImageChops.offset(image,x,y) newImage = ImageChops.lighter(newImage,offsetImage) return newImage
def process(self, image): """ @param image -- The image to process. Returns a single image """ BaseFilter.process(self, image) newImage = image # Shifting by more than one pixel can cause problems, so even if # stepSize > 1, get there by thickening by one shift at a time for x in xrange(-self.shiftSize, self.shiftSize + 1): for y in xrange(-self.shiftSize, self.shiftSize + 1): offsetImage = ImageChops.offset(image, x, y) newImage = ImageChops.lighter(newImage, offsetImage) return newImage
def process(self, image): """ @param 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): """ Perform LogPolar filtering on the input image and return the response @param image -- The image to process """ #image.save("logPolarDebugInput.png") BaseFilter.process(self, image) #image.save("logPolarDebugPostBase.png") out = self._applyKernel(image, 0) outImg = Image.fromarray(out.astype(numpy.int8)) #outImg.save("logPolarDebug.png") maskOut = self._applyKernel(image, 1) maskOutImg = Image.fromarray(maskOut.astype(numpy.int8)) outImg.putalpha(maskOutImg) #outImg.save("logPolarDebugMask.png") self._lastOutputImage = outImg return outImg
def process(self, image): """ @param image -- The image to process. Returns a single image, or a list containing one or more images. """ BaseFilter.process(self, image) if image.size == (self.width, self.height): return image if image.size[0] > self.width or image.size[1] > self.height: raise RuntimeError('Image is larger than target size') newImage = Image.new(image.mode, (self.width, self.height), self.background) xPad = self.width - image.size[0] yPad = self.height - image.size[1] newImage.paste(image, (xPad/2, yPad/2)) return newImage
def process(self, image): """ @param image -- The image to process. Returns a single image, or a list containing one or more images. """ BaseFilter.process(self, image) if image.size == (self.width, self.height): return image if image.size[0] > self.width or image.size[1] > self.height: raise RuntimeError('Image is larger than target size') newImage = Image.new(image.mode, (self.width, self.height), self.background) xPad = self.width - image.size[0] yPad = self.height - image.size[1] newImage.paste(image, (xPad / 2, yPad / 2)) return newImage
def process(self, image): """ @param image -- The image to process. Returns a single image, or a list containing one or more images. """ BaseFilter.process(self, image) #Type of gradient? type = self.random.choice(self.types) gradientImage = self.gradientImages.get((image.size, type)) if not gradientImage: #Gradient image, used as mask gradientImage = Image.new("L", image.size) gradientArray = numpy.array(gradientImage.split()[0].getdata()) gradientArray.resize(image.size[1], image.size[0]) #Calculate gradient opacity = self.difficulty - self.difficulty*.2 + self.random.random()*self.difficulty*.2 for i in xrange(image.size[1]): for j in xrange(image.size[0]): if type == 'horizontal': gradientArray[i][j] = int(float(j)/image.size[0]*255/opacity) elif type == 'vertical': gradientArray[i][j] = int(float(i)/image.size[1]*255/opacity) elif type == 'circular': gradientArray[i][j] = int(math.sqrt((i - image.size[1]/2)**2 + (j - image.size[0]/2)**2)/math.sqrt((image.size[1]/2)**2 + (image.size[0]/2)**2)*255/opacity) gradientImage.putdata([uint(p) for p in gradientArray.flatten()]) #Add gradient image to dictionary self.gradientImages[(image.size, type)] = gradientImage #Image to composite with for brightness whiteImage = Image.new("LA", image.size) whiteArray = numpy.array(whiteImage.split()[0].getdata()) whiteArray += 255 whiteImage.putdata([uint(p) for p in whiteArray]) newImage = Image.composite(image, whiteImage, gradientImage) return newImage
def process(self, image): """ @param image -- The image to process. Returns a single image, or a list containing one or more images. """ BaseFilter.process(self, image) sizes = [(int(round(image.size[0]*s)), int(round(image.size[1]*s))) for s in self.scales] resizedImages = [] for size in sizes: if size < image.size: resizedImages.append(image.resize(size,Image.ANTIALIAS)) else: resizedImages.append(image.resize(size,Image.BICUBIC)) if not self.simultaneous: return resizedImages else: return [resizedImages]
def process(self, image): """ @param image -- The image to process. Returns a single image, or a list containing one or more images. """ BaseFilter.process(self, image) #Create numpy array from image grayscale data and resize to image dimensions imageArray = numpy.array(image.split()[0].getdata()) imageArray.resize(image.size[1], image.size[0]) #Calculate offset from difficulty level offset = self.difficulty*(self.maxOffset) #Add random change to offset within window size halfWindowSize = 0.1*offset offset = (offset - halfWindowSize) + halfWindowSize*self.random.random()*((-1)**self.random.randint(1, 2)) #Apply random direction offset *= ((-1)**self.random.randint(1, 2)) imageArray += offset #Recreate PIL image newImage = Image.new("L", image.size) newImage.putdata([uint(p) for p in imageArray.flatten()]) newImage.putalpha(image.split()[1]) return newImage
def process(self, image): """ Performs the following operations: 1. Locates the original bounding box of the image as defined by the image's alpha mask. It is assumed that the alpha mask will consist of a single rectangular, in which case the resulting bbox will be exactly equivalent to the mask representation. However, if for some reason the positive regions of the alpha mask is not a single rectangle, things will still work. 2. Fit the bounding box to the target dimensions, scaling as needed, and filling in padding regions if needed (if the aspect ratio of the bounding box does not match that of the target dimensions which, in general, will be True.) If padding is needed, we fill from the original image pixels around the bounding box if fillFromImageWherePossible is True and we're not outside the original image bounds, otherwise, we use 'fillValue'. 3. Apply each scale in 'scales' to the resulting cropped image, and pad each side by 'padding' (pulling from the real image pixels when possible, and filling with 'fillValue' where not.) 4. Return the list of cropped images. """ BaseFilter.process(self, image) assert image.mode == "LA" # Pull bbox of the alpha mask if 'tracking' in image.info: bbox = image.info['tracking'] else: bbox = image.split()[1].getbbox() # If alpha channel is completely empty, we will end up # with a bbox of 'None'. Nothing much we can do if bbox is None: bbox = (0, 0, image.size[0], image.size[1]) print 'WARNING: empty alpha channel' # Ascertain the original raw size of the tracking box width = bbox[2] - bbox[0] height = bbox[3] - bbox[1] newImages = [] for scaleIdx, scale in enumerate(self._scales): # Target dimensions depend on the scale at which we're operating targetDims = (self._targetDims[0] * scale, self._targetDims[1] * scale) scaleFactorX = float(targetDims[0]) / float(width) scaleFactorY = float(targetDims[1]) / float(height) # Determine the scaling factors needed to map the # bounding box to the target dimensions (prior to # padding be accounted for) if self._preservationMode is None: pass elif self._preservationMode == "aspect": scaleFactor = min(scaleFactorX, scaleFactorY) scaleFactorX = scaleFactor scaleFactorY = scaleFactor else: assert self._preservationMode == "size" scaleFactorX = scale scaleFactorY = scale # Now, holding the scaling factor constant, compute the # size of the src box in the original image that will # produce the correctly padded target size targetWidth = int(round(targetDims[0])) + 2*self._padding targetHeight = int(round(targetDims[1])) + 2*self._padding srcWidth = float(targetWidth) / scaleFactorX srcHeight = float(targetHeight) / scaleFactorY # Compute the exact coordinates of the source box if self._fillFromImageWherePossible: origCenterX = float(bbox[0] + bbox[2]) * 0.5 origCenterY = float(bbox[1] + bbox[3]) * 0.5 halfWidth = srcWidth * 0.5 halfHeight = srcHeight * 0.5 srcBox = (int(round(origCenterX - halfWidth)), int(round(origCenterY - halfHeight)), int(round(origCenterX + halfWidth)), int(round(origCenterY + halfHeight))) # take into account clipping off the image boundary clipBox = (max(srcBox[0], 0), max(srcBox[1], 0), min(srcBox[2], image.size[0]), min(srcBox[3], image.size[1])) clipOffset = (clipBox[0] - srcBox[0], clipBox[1] - srcBox[1]) else: # extend the bbox to include padding pixels on all sides paddedBBox = (int(bbox[0] - self._padding/scaleFactorX), int(bbox[1] - self._padding/scaleFactorY), int(bbox[2] + self._padding/scaleFactorX), int(bbox[3] + self._padding/scaleFactorY)) # take into account clipping off the image boundary clipBox = (max(paddedBBox[0], 0), max(paddedBBox[1], 0), min(paddedBBox[2], image.size[0]), min(paddedBBox[3], image.size[1])) # The srcBox is the correct aspect ratio, and either taller or wider than the # bbox, but not both. srcBox = (0, 0, srcWidth, srcHeight) clipBoxWidth = clipBox[2] - clipBox[0] clipBoxHeight = clipBox[3] - clipBox[1] clipOffset = (int((srcWidth - clipBoxWidth)/2), int((srcHeight - clipBoxHeight)/2)) # Copy the source rect croppedImage = image.crop(clipBox) croppedImage.load() # New development croppedImage.putalpha(Image.new(mode='L', size=croppedImage.size, color=255)) if self._fillValue is None: [gray, alpha] = image.split() hist = numpy.array(gray.histogram(alpha), dtype='float') mean = (hist * self._histWeights).sum() / hist.sum() if mean < 127.5: fillValue = 255 else: fillValue = 0 else: fillValue = self._fillValue # Paste into a new image newImage = Image.new(mode='LA', size=(srcBox[2]-srcBox[0], srcBox[3]-srcBox[1]), color=fillValue) newImage.paste(croppedImage, clipOffset) # Resize the cropped image to the (padded) target size scaledImage = newImage.resize((targetWidth, targetHeight), self._resizingFilter) # Convert and save the scaled image as the output assert scaledImage.mode == 'LA' newImages += [scaledImage] # Dump debugging images to disk if self._dumpDebugImages: self._handleDebug(scaledImage, scaleIdx) return [newImages]
def process(self, image): """ Performs the following operations: 1. Locates the original bounding box of the image as defined by the image's alpha mask. It is assumed that the alpha mask will consist of a single rectangular, in which case the resulting bbox will be exactly equivalent to the mask representation. However, if for some reason the positive regions of the alpha mask is not a single rectangle, things will still work. 2. Fit the bounding box to the target dimensions, scaling as needed, and filling in padding regions if needed (if the aspect ratio of the bounding box does not match that of the target dimensions which, in general, will be True.) If padding is needed, we fill from the original image pixels around the bounding box if fillFromImageWherePossible is True and we're not outside the original image bounds, otherwise, we use 'fillValue'. 3. Apply each scale in 'scales' to the resulting cropped image, and pad each side by 'padding' (pulling from the real image pixels when possible, and filling with 'fillValue' where not.) 4. Return the list of cropped images. """ BaseFilter.process(self, image) assert image.mode == "LA" # Pull bbox of the alpha mask if 'tracking' in image.info: bbox = image.info['tracking'] if type(bbox) == type(""): bbox = eval(bbox) else: bbox = image.split()[1].getbbox() # If alpha channel is completely empty, we will end up # with a bbox of 'None'. Nothing much we can do if bbox is None: bbox = (0, 0, image.size[0], image.size[1]) print 'WARNING: empty alpha channel' # Check for malformed box elif bbox[0] >= bbox[2] or bbox[1] >= bbox[3]: bbox = (0, 0, image.size[0], image.size[1]) print 'WARNING: malformed box' # Ascertain the original raw size of the tracking box width = bbox[2] - bbox[0] height = bbox[3] - bbox[1] if self._fillValue is None: [gray, alpha] = image.split() hist = numpy.array(gray.histogram(alpha), dtype='float') mean = (hist * self._histWeights).sum() / hist.sum() if mean < 127.5: fillValue = 255 else: fillValue = 0 elif isinstance(self._fillValue, int): fillValue = self._fillValue else: fillValue = self._fillValue[random.randint(0, len(self._fillValue)-1)] # If we're not going to fill from the rest of the image, we should # apply the alpha from the original image directly. If the original alpha # was a square bounding box, this won't hurt (since we're not filling from # the image). If it was a tight mask, this will prevent it from reverting # back to a square mask. if (self._applyAlpha) and (not self._fillFromImageWherePossible): grayImage, alphaImage = image.split() image = Image.new('L', size=image.size, color=fillValue) image.paste(grayImage, alphaImage) newImages = [] for scaleIdx, scale in enumerate(self._scales): # Target dimensions depend on the scale at which we're operating targetDims = (self._targetDims[0] * scale, self._targetDims[1] * scale) scaleFactorX = float(targetDims[0]) / float(width) scaleFactorY = float(targetDims[1]) / float(height) # Determine the scaling factors needed to map the # bounding box to the target dimensions (prior to # padding be accounted for) if self._preservationMode is None: pass elif self._preservationMode == "aspect": scaleFactor = min(scaleFactorX, scaleFactorY) scaleFactorX = scaleFactor scaleFactorY = scaleFactor else: assert self._preservationMode == "size" scaleFactorX = scale scaleFactorY = scale # Now, holding the scaling factor constant, compute the # size of the src box in the original image that will # produce the correctly padded target size targetWidth = int(round(targetDims[0])) + 2*self._padding targetHeight = int(round(targetDims[1])) + 2*self._padding srcWidth = float(targetWidth) / scaleFactorX srcHeight = float(targetHeight) / scaleFactorY # Compute the exact coordinates of the source box if self._fillFromImageWherePossible: origCenterX = float(bbox[0] + bbox[2]) * 0.5 origCenterY = float(bbox[1] + bbox[3]) * 0.5 halfWidth = srcWidth * 0.5 halfHeight = srcHeight * 0.5 srcBox = (int(round(origCenterX - halfWidth)), int(round(origCenterY - halfHeight)), int(round(origCenterX + halfWidth)), int(round(origCenterY + halfHeight))) # take into account clipping off the image boundary clipBox = (max(srcBox[0], 0), max(srcBox[1], 0), min(srcBox[2], image.size[0]), min(srcBox[3], image.size[1])) #clipOffset = (clipBox[0] - srcBox[0], # clipBox[1] - srcBox[1]) else:
def process(self, image): """ @param 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. assert self.noiseThickness != 0, "ImageSensor parameter noiseThickness cannot be 0" pixels = numpy.array(image.split()[0].getdata(), dtype=int) (imgWidth,imgHeight) = image.size pixels2d = (numpy.array(pixels)).reshape(imgHeight, imgWidth) noiseArrayW = numpy.floor(imgWidth/float(self.noiseThickness)) noiseArrayH = numpy.floor(imgHeight/float(self.noiseThickness)) thickNoise = numpy.random.random((noiseArrayH, noiseArrayW)) thickNoise = 255*(thickNoise < self.noiseLevel) idxW = numpy.array([int(self.noiseThickness*i) for i in xrange(noiseArrayW)]) idxH = numpy.array([int(self.noiseThickness*i) for i in xrange(noiseArrayH)]) for nt1 in xrange(self.noiseThickness): for nt2 in xrange(self.noiseThickness): submatIdx = numpy.ix_(idxH + nt1, idxW + nt2) if self.doForeground and self.doBackground: pixels2d[submatIdx] ^= thickNoise elif self.doForeground: pixels2d[submatIdx] = (pixels2d[submatIdx]^thickNoise) | pixels2d[submatIdx] elif self.doBackground: pixels2d[submatIdx] = (pixels2d[submatIdx]^thickNoise) & pixels2d[submatIdx] pixels2d = numpy.abs(pixels2d) pixels = pixels2d.reshape(1,imgWidth*imgHeight)[0] # ----------------------------------------------------------------------- # 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 * 255 mask = numpy.array(alpha.getdata(), dtype=int) != self.background 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 ValueError("This image mode not supported") # write out the new pixels #from dbgp.client import brk; brk(port=9049) newimage = Image.new(image.mode, image.size) #newimage.putdata([uint(p) for p in pixels]) newimage.putdata(pixels.tolist()) 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): """ @param 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 process(self, image): """ @param 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. assert self.noiseThickness != 0, "ImageSensor parameter noiseThickness cannot be 0" pixels = numpy.array(image.split()[0].getdata(), dtype=int) (imgWidth, imgHeight) = image.size pixels2d = (numpy.array(pixels)).reshape(imgHeight, imgWidth) noiseArrayW = numpy.floor(imgWidth / float(self.noiseThickness)) noiseArrayH = numpy.floor(imgHeight / float(self.noiseThickness)) thickNoise = numpy.random.random((noiseArrayH, noiseArrayW)) thickNoise = 255 * (thickNoise < self.noiseLevel) idxW = numpy.array( [int(self.noiseThickness * i) for i in xrange(noiseArrayW)]) idxH = numpy.array( [int(self.noiseThickness * i) for i in xrange(noiseArrayH)]) for nt1 in xrange(self.noiseThickness): for nt2 in xrange(self.noiseThickness): submatIdx = numpy.ix_(idxH + nt1, idxW + nt2) if self.doForeground and self.doBackground: pixels2d[submatIdx] ^= thickNoise elif self.doForeground: pixels2d[submatIdx] = (pixels2d[submatIdx] ^ thickNoise ) | pixels2d[submatIdx] elif self.doBackground: pixels2d[submatIdx] = (pixels2d[submatIdx] ^ thickNoise ) & pixels2d[submatIdx] pixels2d = numpy.abs(pixels2d) pixels = pixels2d.reshape(1, imgWidth * imgHeight)[0] # ----------------------------------------------------------------------- # 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 * 255 mask = numpy.array(alpha.getdata(), dtype=int) != self.background 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 ValueError("This image mode not supported") # write out the new pixels #from dbgp.client import brk; brk(port=9049) newimage = Image.new(image.mode, image.size) #newimage.putdata([uint(p) for p in pixels]) newimage.putdata(pixels.tolist()) 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 _processImage(self, image, bbox): """Return a single image, or a list containing one or more images. @param image -- The image to process. """ BaseFilter.process(self, image) inWidth, inHeight = image.size # Get output dims and buffers (cached) outWidth, outHeight, inBuffer, outBuffer, mask = self._prepare( image.size) # Ask the sub-class the build the filter bank self._buildFilterBank() inputOffset = 0 outputOffset = 0 data = image.split()[0] inputVector = numpy.asarray(data, dtype=numpy.float32) inputVector.shape = (inHeight, inWidth) # If we are using "color-key" mode, then detect the value of # the upper-left pixel and use it as the value of # 'offImagePixelValue' if self._offImagePixelValue in ('colorKey', u'colorKey'): offImagePixelValue = inputVector[0, 0] else: offImagePixelValue = self._offImagePixelValue result = [] # Compute the convolution responses # Determine proper input/output dimensions outputSize = outHeight * outWidth * self._outputPlaneCount # Locate correct portion of output outputVector = numpy.zeros( (outHeight, outWidth, self._outputPlaneCount), dtype=numpy.float32) outputVector.shape = (self._outputPlaneCount, outHeight, outWidth) # Compute the bounding box to use for our C implementation imageBox = numpy.array([0, 0, inWidth, inHeight], dtype=numpy.int32) ## --- DEBUG CODE ---- #global id #o = inputVector #f = os.path.abspath('convolution_input_%d.txt' % id) #print f #numpy.savetxt(f, o) #id += 1 ##from dbgp.client import brk; brk(port=9019) ## --- DEBUG CODE END ---- # Call the fast convolution C code self._convolve(inputVector, bbox, imageBox, outputVector, offImagePixelValue, inBuffer, outBuffer) outputVector = numpy.rollaxis(outputVector, 0, 3) outputVector = outputVector.reshape(outWidth * outHeight, self._outputPlaneCount).flatten() assert outputVector.dtype == numpy.float32 locationCount = len(outputVector) / self._outputPlaneCount response = outputVector.reshape(locationCount, self._outputPlaneCount) ## --- DEBUG CODE ---- #global id #o = outputVector.flatten() ##print outputVector.shape, len(o) #f = os.path.abspath('convolution_output_%d.txt' % id) #print f #numpy.savetxt(f, o) #id += 1 ##from dbgp.client import brk; brk(port=9019) ## --- DEBUG CODE END ---- # Convert the reponses to images result = [] for i in range(response.shape[1]): newImage = Image.new('L', (outWidth, outHeight)) #data = (self._gainConstant * 255.0 * response[:,i]).clip(min=0.0, max=255.0).astype(numpy.uint8) data = (255.0 * response[:, i]).clip(min=0.0, max=255.0).astype(numpy.uint8) newImage.putdata([uint(p) for p in data]) newImage.putalpha(mask) result.append(newImage) return (result, outputVector)
def _processImage(self, image, bbox): """Return a single image, or a list containing one or more images. @param image -- The image to process. """ BaseFilter.process(self, image) inWidth, inHeight = image.size # Get output dims and buffers (cached) outWidth, outHeight, inBuffer, outBuffer, mask = self._prepare(image.size) # Ask the sub-class the build the filter bank self._buildFilterBank() inputOffset = 0 outputOffset = 0 data = image.split()[0] inputVector = numpy.asarray(data, dtype=numpy.float32) inputVector.shape = (inHeight, inWidth) # If we are using "color-key" mode, then detect the value of # the upper-left pixel and use it as the value of # 'offImagePixelValue' if self._offImagePixelValue in ('colorKey', u'colorKey'): offImagePixelValue = inputVector[0, 0] else: offImagePixelValue = self._offImagePixelValue result = [] # Compute the convolution responses # Determine proper input/output dimensions outputSize = outHeight * outWidth * self._outputPlaneCount # Locate correct portion of output outputVector = numpy.zeros((outHeight, outWidth, self._outputPlaneCount), dtype=numpy.float32) outputVector.shape = (self._outputPlaneCount, outHeight, outWidth) # Compute the bounding box to use for our C implementation imageBox = numpy.array([0, 0, inWidth, inHeight], dtype=numpy.int32) ## --- DEBUG CODE ---- #global id #o = inputVector #f = os.path.abspath('convolution_input_%d.txt' % id) #print f #numpy.savetxt(f, o) #id += 1 ##from dbgp.client import brk; brk(port=9019) ## --- DEBUG CODE END ---- # Call the fast convolution C code self._convolve(inputVector, bbox, imageBox, outputVector, offImagePixelValue, inBuffer, outBuffer) outputVector = numpy.rollaxis(outputVector, 0, 3) outputVector = outputVector.reshape(outWidth * outHeight, self._outputPlaneCount).flatten() assert outputVector.dtype == numpy.float32 locationCount = len(outputVector) / self._outputPlaneCount response = outputVector.reshape(locationCount, self._outputPlaneCount) ## --- DEBUG CODE ---- #global id #o = outputVector.flatten() ##print outputVector.shape, len(o) #f = os.path.abspath('convolution_output_%d.txt' % id) #print f #numpy.savetxt(f, o) #id += 1 ##from dbgp.client import brk; brk(port=9019) ## --- DEBUG CODE END ---- # Convert the reponses to images result = [] for i in range(response.shape[1]): newImage = Image.new('L', (outWidth, outHeight)) #data = (self._gainConstant * 255.0 * response[:,i]).clip(min=0.0, max=255.0).astype(numpy.uint8) data = (255.0 * response[:,i]).clip(min=0.0, max=255.0).astype(numpy.uint8) newImage.putdata([uint(p) for p in data]) newImage.putalpha(mask) result.append(newImage) return (result, outputVector)
def process(self, image): """ @param image -- The image to process. Returns a single image, or a list containing one or more images. """ BaseFilter.process(self, image) # If no background image, just return the input image as-is if self.bgPath is None: return image # --------------------------------------------------------------------------- # Open the background image(s) if we haven't done so already if self.bgImgs is None: # If given a relative path, make it relative to the vision data directory if not os.path.isabs(self.bgPath): basePath = os.path.abspath(os.curdir) basePath = os.path.split(basePath) while (basePath[0]): if basePath[1] == 'vision': break basePath = os.path.split(basePath[0]) # Did we find the vision directory? if basePath[1] == 'vision': fullPath = VisionUtils.findData( os.path.join(basePath[0], 'vision'), self.bgPath, 'backgound', 'background images', True) #basePath = os.path.join(basePath[0], 'vision', 'data') else: fullPath = self.bgPath else: fullPath = self.bgPath # If given a filename, we only have 1 image if os.path.isfile(fullPath): self.bgImgs = [Image.open(fullPath).convert('LA')] # Else, open up all images in this directory else: self.bgImgs = [] w = os.walk(fullPath) while True: try: dirpath, dirnames, filenames = w.next() except StopIteration: break # Don't enter directories that begin with '.' for d in dirnames[:]: if d.startswith('.'): dirnames.remove(d) dirnames.sort() # Ignore files that begin with '.' filenames = [f for f in filenames if not f.startswith('.')] filenames.sort() imageFilenames = [ os.path.join(dirpath, f) for f in filenames ] # Process each image for filename in imageFilenames: self.bgImgs.append(Image.open(filename).convert('L')) # Keep a cache of all images, scaled to the input image size self.scaledBGImgs = [x.copy() for x in self.bgImgs] # Pick a background at random. idx = self._rng.randint(0, len(self.bgImgs) - 1) bgImg = self.scaledBGImgs[idx] # --------------------------------------------------------------------------- # re-scale the background to the source image if necessary if bgImg.size != image.size: bgImg = self.scaledBGImgs[idx] = self.bgImgs[idx].resize( image.size, Image.ANTIALIAS) # --------------------------------------------------------------------------- # 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) # --------------------------------------------------------------------------- # Paste the image onto the background newImage = bgImg.copy() newImage.paste(image, (0, 0), mask) # Put an "all-on" alpha channel because we now want the network to consider the entire # image newImage.putalpha(ImageChops.constant(newImage, 255)) return newImage
def process(self, image): """ @param image -- The image to process. Returns a single image, or a list containing one or more images. """ BaseFilter.process(self, image) # If no background image, just return the input image as-is if self.bgPath is None: return image # --------------------------------------------------------------------------- # Open the background image(s) if we haven't done so already if self.bgImgs is None: # If given a relative path, make it relative to the vision data directory if not os.path.isabs(self.bgPath): basePath = os.path.abspath(os.curdir) basePath = os.path.split(basePath) while(basePath[0]): if basePath[1] == 'vision': break basePath = os.path.split(basePath[0]) # Did we find the vision directory? if basePath[1] == 'vision': fullPath = VisionUtils.findData(os.path.join(basePath[0], 'vision'), self.bgPath, 'backgound', 'background images', True) #basePath = os.path.join(basePath[0], 'vision', 'data') else: fullPath = self.bgPath else: fullPath = self.bgPath # If given a filename, we only have 1 image if os.path.isfile(fullPath): self.bgImgs = [Image.open(fullPath).convert('LA')] # Else, open up all images in this directory else: self.bgImgs = [] w = os.walk(fullPath) while True: try: dirpath, dirnames, filenames = w.next() except StopIteration: break # Don't enter directories that begin with '.' for d in dirnames[:]: if d.startswith('.'): dirnames.remove(d) dirnames.sort() # Ignore files that begin with '.' filenames = [f for f in filenames if not f.startswith('.')] filenames.sort() imageFilenames = [os.path.join(dirpath, f) for f in filenames] # Process each image for filename in imageFilenames: self.bgImgs.append(Image.open(filename).convert('L')) # Keep a cache of all images, scaled to the input image size self.scaledBGImgs = [x.copy() for x in self.bgImgs] # Pick a background at random. idx = self._rng.randint(0, len(self.bgImgs)-1) bgImg = self.scaledBGImgs[idx] # --------------------------------------------------------------------------- # re-scale the background to the source image if necessary if bgImg.size != image.size: bgImg = self.scaledBGImgs[idx] = self.bgImgs[idx].resize(image.size, Image.ANTIALIAS) # --------------------------------------------------------------------------- # 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) # --------------------------------------------------------------------------- # Paste the image onto the background newImage = bgImg.copy() newImage.paste(image, (0,0), mask) # Put an "all-on" alpha channel because we now want the network to consider the entire # image newImage.putalpha(ImageChops.constant(newImage, 255)) return newImage
def process(self, image): """ Performs the following operations: 1. Locates the original bounding box of the image as defined by the image's alpha mask. It is assumed that the alpha mask will consist of a single rectangular, in which case the resulting bbox will be exactly equivalent to the mask representation. However, if for some reason the positive regions of the alpha mask is not a single rectangle, things will still work. 2. Fit the bounding box to the target dimensions, scaling as needed, and filling in padding regions if needed (if the aspect ratio of the bounding box does not match that of the target dimensions which, in general, will be True.) If padding is needed, we fill from the original image pixels around the bounding box if fillFromImageWherePossible is True and we're not outside the original image bounds, otherwise, we use 'fillValue'. 3. Apply each scale in 'scales' to the resulting cropped image, and pad each side by 'padding' (pulling from the real image pixels when possible, and filling with 'fillValue' where not.) 4. Return the list of cropped images. """ BaseFilter.process(self, image) assert image.mode == "LA" # Pull bbox of the alpha mask if 'tracking' in image.info: bbox = image.info['tracking'] if type(bbox) == type(""): bbox = eval(bbox) else: bbox = image.split()[1].getbbox() # If alpha channel is completely empty, we will end up # with a bbox of 'None'. Nothing much we can do if bbox is None: bbox = (0, 0, image.size[0], image.size[1]) print 'WARNING: empty alpha channel' # Check for malformed box elif bbox[0] >= bbox[2] or bbox[1] >= bbox[3]: bbox = (0, 0, image.size[0], image.size[1]) print 'WARNING: malformed box' # Ascertain the original raw size of the tracking box width = bbox[2] - bbox[0] height = bbox[3] - bbox[1] if self._fillValue is None: [gray, alpha] = image.split() hist = numpy.array(gray.histogram(alpha), dtype='float') mean = (hist * self._histWeights).sum() / hist.sum() if mean < 127.5: fillValue = 255 else: fillValue = 0 elif isinstance(self._fillValue, int): fillValue = self._fillValue else: fillValue = self._fillValue[random.randint(0, len(self._fillValue)-1)] # If we're not going to fill from the rest of the image, we should # apply the alpha from the original image directly. If the original alpha # was a square bounding box, this won't hurt (since we're not filling from # the image). If it was a tight mask, this will prevent it from reverting # back to a square mask. if (self._applyAlpha) and (not self._fillFromImageWherePossible): grayImage, alphaImage = image.split() image = Image.new('L', size=image.size, color=fillValue) image.paste(grayImage, alphaImage) newImages = [] for scaleIdx, scale in enumerate(self._scales): # Target dimensions depend on the scale at which we're operating targetDims = (self._targetDims[0] * scale, self._targetDims[1] * scale) scaleFactorX = float(targetDims[0]) / float(width) scaleFactorY = float(targetDims[1]) / float(height) # Determine the scaling factors needed to map the # bounding box to the target dimensions (prior to # padding be accounted for) if self._preservationMode is None: pass elif self._preservationMode == "aspect": scaleFactor = min(scaleFactorX, scaleFactorY) scaleFactorX = scaleFactor scaleFactorY = scaleFactor else: assert self._preservationMode == "size" scaleFactorX = scale scaleFactorY = scale # Now, holding the scaling factor constant, compute the # size of the src box in the original image that will # produce the correctly padded target size targetWidth = int(round(targetDims[0])) + 2*self._padding targetHeight = int(round(targetDims[1])) + 2*self._padding srcWidth = float(targetWidth) / scaleFactorX srcHeight = float(targetHeight) / scaleFactorY # Compute the exact coordinates of the source box if self._fillFromImageWherePossible: origCenterX = float(bbox[0] + bbox[2]) * 0.5 origCenterY = float(bbox[1] + bbox[3]) * 0.5 halfWidth = srcWidth * 0.5 halfHeight = srcHeight * 0.5 srcBox = (int(round(origCenterX - halfWidth)), int(round(origCenterY - halfHeight)), int(round(origCenterX + halfWidth)), int(round(origCenterY + halfHeight))) # take into account clipping off the image boundary clipBox = (max(srcBox[0], 0), max(srcBox[1], 0), min(srcBox[2], image.size[0]), min(srcBox[3], image.size[1])) #clipOffset = (clipBox[0] - srcBox[0], # clipBox[1] - srcBox[1]) else: # extend the bbox to include padding pixels on all sides paddedBBox = (int(bbox[0] - self._padding/scaleFactorX), int(bbox[1] - self._padding/scaleFactorY), int(bbox[2] + self._padding/scaleFactorX), int(bbox[3] + self._padding/scaleFactorY)) # take into account clipping off the image boundary clipBox = (max(paddedBBox[0], 0), max(paddedBBox[1], 0), min(paddedBBox[2], image.size[0]), min(paddedBBox[3], image.size[1])) # The srcBox is the correct aspect ratio, and either taller or wider than the # bbox, but not both. srcBox = (0, 0, srcWidth, srcHeight) clipBoxWidth = clipBox[2] - clipBox[0] clipBoxHeight = clipBox[3] - clipBox[1] #clipOffset = (int((srcWidth - clipBoxWidth)/2), # int((srcHeight - clipBoxHeight)/2)) # Copy the source rect croppedImage = image.crop(clipBox) croppedImage.load() # New development croppedImage.putalpha(Image.new(mode='L', size=croppedImage.size, color=255)) # Scale the cropped image. At last one dimension of this cropped image # should be the target size. xFactor = float(targetWidth) / croppedImage.size[0] yFactor = float(targetHeight) / croppedImage.size[1] scaleFactor = min(xFactor, yFactor) if scaleFactor >= 1: resizingFilter = Image.BICUBIC else: resizingFilter = Image.ANTIALIAS scaledImage = croppedImage.resize((int(round(scaleFactor * croppedImage.size[0])), int(round(scaleFactor * croppedImage.size[1]))), resizingFilter) clipOffset = (int((targetWidth - scaledImage.size[0]) / 2), int((targetHeight - scaledImage.size[1]) / 2)) # Paste into a new image newImage = Image.new(mode='LA', size=(targetWidth, targetHeight), color=fillValue) newImage.paste(scaledImage, clipOffset) # Resize the cropped image to the (padded) target size # Convert and save the scaled image as the output assert newImage.mode == 'LA' newImages += [newImage] # Dump debugging images to disk if self._dumpDebugImages: self._handleDebug(newImage, scaleIdx) return [newImages]
def process(self, image): """ @param 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]