def __init__(self, image, background, dpi, precision=16, deskew=True, contrast=10): self.contrast = contrast self.image = image self.dpi = dpi self.width, self.height = image.size self.precision = precision self.deskew = deskew self.samples = PixelSampler(image, dpi, precision) self.background = background self.sections = self._find_sections()
class MultiPartImage(object): """Object for handling images that contain multiple subimages. This is used, for example, to detect and access multiple photos that were scanned simultaneously in a flat-bed scanner. """ def __init__(self, image, background, dpi, precision=16, deskew=True, contrast=10): self.contrast = contrast self.image = image self.dpi = dpi self.width, self.height = image.size self.precision = precision self.deskew = deskew self.samples = PixelSampler(image, dpi, precision) self.background = background self.sections = self._find_sections() def __iter__(self): for section in self.sections: image = self.image.crop((section.left, section.top, section.right, section.bottom)) if self.deskew: skew = SkewedImage(image, self.background, self.contrast) image = skew.correct() yield image def __len__(self): return len(self.sections) def _find_sections(self): sections = [] for (x, y, red, green, blue) in self.samples: # Skip if the sample is background or is already in a section. if self.background.matches(red, green, blue, self.contrast): continue if True in (section.contains(x, y) for section in sections): continue # Find contiguous samples. This works like a 4-way flood fill, but # instead of changing the color we just collect the coordinates. seeds = [(x, y)] pixels = set(seeds) for coords in iter(seeds): for x, y, r, g, b in self.samples.around(*coords): if (x, y) not in pixels: pixels.add((x, y)) if not self.background.matches(r, g, b, self.contrast): seeds.append((x, y)) new_section = ImageSection(pixels) if True in (s.merge_if_overlapping(new_section) for s in sections): continue sections.append(new_section) # Filter out sections smaller than 1 square inch before returning. return [s for s in sections if s > self.dpi ** 2]
def __init__(self, image, background, contrast=10): self.image = image self.width, self.height = image.size self.background = background self.contrast = contrast sampler = PixelSampler(image, dpi=1, precision=1) self.sides = ( Left(sampler), Top(sampler), Right(sampler), Bottom(sampler), )
def load_from_image(self, image, dpi): """Determine background stats by examining a blank scan. """ sampler = PixelSampler(image, dpi, precision=4) reds, greens, blues = zip(*[sample[2:] for sample in sampler]) self.medians = { 'red': numpy.median(reds), 'green': numpy.median(greens), 'blue': numpy.median(blues), } self.std_devs = { 'red': numpy.std(reds), 'green': numpy.std(greens), 'blue': numpy.std(blues), } return self
class MultiPartImage(object): """Object for handling images that contain multiple subimages. This is used, for example, to detect and access multiple photos that were scanned simultaneously in a flat-bed scanner. """ def __init__(self, image, background, dpi, precision=16, deskew=True, contrast=10): self.contrast = contrast self.image = image self.dpi = dpi self.width, self.height = image.size self.precision = precision self.deskew = deskew self.samples = PixelSampler(image, dpi, precision) self.background = background self.sections = self._find_sections() def __iter__(self): for section in self.sections: image = self.image.crop( (section.left, section.top, section.right, section.bottom)) if self.deskew: skew = SkewedImage(image, self.background, self.contrast) image = skew.correct() yield image def __len__(self): return len(self.sections) def _find_sections(self): sections = [] for (x, y, red, green, blue) in self.samples: # Skip if the sample is background or is already in a section. if self.background.matches(red, green, blue, self.contrast): continue if True in (section.contains(x, y) for section in sections): continue # Find contiguous samples. This works like a 4-way flood fill, but # instead of changing the color we just collect the coordinates. seeds = [(x, y)] pixels = set(seeds) for coords in iter(seeds): for x, y, r, g, b in self.samples.around(*coords): if (x, y) not in pixels: pixels.add((x, y)) if not self.background.matches(r, g, b, self.contrast): seeds.append((x, y)) new_section = ImageSection(pixels) if True in (s.merge_if_overlapping(new_section) for s in sections): continue sections.append(new_section) # Filter out sections smaller than 1 square inch before returning. return [s for s in sections if s > self.dpi**2]