def image_tint(path: str, tint: str) -> Image: src = Image.open(path) if src.mode not in ("RGB", "RGBA"): raise TypeError(f"Unsupported source image mode: {src.mode}") src.load() tr, tg, tb = getrgb(tint) tl = getcolor(tint, "L") # tint color's overall luminosity if not tl: tl = 1 # avoid division by zero tl = float(tl) # compute luminosity preserving tint factors sr, sg, sb = map(lambda tv: tv / tl, (tr, tg, tb)) # per component # adjustments # create look-up tables to map luminosity to adjusted tint # (using floating-point math only to compute table) luts = (tuple(map(lambda lr: int(lr * sr + 0.5), range(256))) + tuple(map(lambda lg: int(lg * sg + 0.5), range(256))) + tuple(map(lambda lb: int(lb * sb + 0.5), range(256)))) l = grayscale(src) # 8-bit luminosity version of whole image if Image.getmodebands(src.mode) < 4: merge_args: tuple = (src.mode, (l, l, l) ) # for RGB verion of grayscale else: # include copy of src image's alpha layer a = Image.new("L", src.size) a.putdata(src.getdata(3)) merge_args = (src.mode, (l, l, l, a)) # for RGBA verion of grayscale luts += tuple(range(256)) # for 1:1 mapping of copied alpha values image = Image.merge(*merge_args).point(luts) new_image = Image.new("RGBA", image.size, "WHITE") # Create a white rgba background new_image.paste(image, (0, 0), image) return new_image
def image_tint(image, tint=None): if tint is None: return image if image.mode not in ['RGB', 'RGBA']: image = image.convert('RGBA') tr, tg, tb = ImageColor.getrgb(tint) tl = ImageColor.getcolor(tint, "L") # tint color's overall luminosity if not tl: tl = 1 # avoid division by zero tl = float(tl) # compute luminosity preserving tint factors sr, sg, sb = map(lambda tv: tv / tl, (tr, tg, tb) ) # per component adjustments # create look-up tables to map luminosity to adjusted tint # (using floating-point math only to compute table) luts = (tuple(map(lambda lr: int(lr * sr + 0.5), range(256))) + tuple(map(lambda lg: int(lg * sg + 0.5), range(256))) + tuple(map(lambda lb: int(lb * sb + 0.5), range(256)))) l = ImageOps.grayscale(image) # 8-bit luminosity version of whole image if Image.getmodebands(image.mode) < 4: merge_args = (image.mode, (l, l, l)) # for RGB verion of grayscale else: # include copy of image's alpha layer a = Image.new("L", image.size) a.putdata(image.getdata(3)) merge_args = (image.mode, (l, l, l, a)) # for RGBA verion of grayscale luts += tuple(range(256)) # for 1:1 mapping of copied alpha values return Image.merge(*merge_args).point(luts)
def image_tint(src, tint=None): r = lambda: random.randint(0,255) tint = tint or '#{:02X}{:02X}{:02X}'.format(r(), r(), r()) if Image.isStringType(src): # file path? src = Image.open(src) if src.mode not in ['RGB', 'RGBA']: raise TypeError('Unsupported source image mode: {}'.format(src.mode)) src.load() tr, tg, tb = ImageColor.getrgb(tint) tl = ImageColor.getcolor(tint, "L") # tint color's overall luminosity if not tl: tl = 1 # avoid division by zero tl = float(tl) # compute luminosity preserving tint factors sr, sg, sb = map(lambda tv: tv/tl, (tr, tg, tb)) # per component adjustments # create look-up tables to map luminosity to adjusted tint # (using floating-point math only to compute table) luts = (map(lambda lr: int(lr*sr + 0.5), range(256)) + map(lambda lg: int(lg*sg + 0.5), range(256)) + map(lambda lb: int(lb*sb + 0.5), range(256))) l = ImageOps.grayscale(src) # 8-bit luminosity version of whole image if Image.getmodebands(src.mode) < 4: merge_args = (src.mode, (l, l, l)) # for RGB verion of grayscale else: # include copy of src image's alpha layer a = Image.new("L", src.size) a.putdata(src.getdata(3)) merge_args = (src.mode, (l, l, l, a)) # for RGBA verion of grayscale luts += range(256) # for 1:1 mapping of copied alpha values return (Image.merge(*merge_args).point(luts), tint)
def image_tint(image, tint=None): if tint is None: return image if image.mode not in ['RGB', 'RGBA']: image = image.convert('RGBA') tr, tg, tb = ImageColor.getrgb(tint) tl = ImageColor.getcolor(tint, "L") # tint color's overall luminosity if not tl: tl = 1 # avoid division by zero tl = float(tl) # compute luminosity preserving tint factors sr, sg, sb = map(lambda tv: tv / tl, (tr, tg, tb)) # per component adjustments # create look-up tables to map luminosity to adjusted tint # (using floating-point math only to compute table) luts = (tuple(map(lambda lr: int(lr * sr + 0.5), range(256))) + tuple(map(lambda lg: int(lg * sg + 0.5), range(256))) + tuple(map(lambda lb: int(lb * sb + 0.5), range(256)))) l = ImageOps.grayscale(image) # 8-bit luminosity version of whole image if Image.getmodebands(image.mode) < 4: merge_args = (image.mode, (l, l, l)) # for RGB verion of grayscale else: # include copy of image's alpha layer a = Image.new("L", image.size) a.putdata(image.getdata(3)) merge_args = (image.mode, (l, l, l, a)) # for RGBA verion of grayscale luts += tuple(range(256)) # for 1:1 mapping of copied alpha values return Image.merge(*merge_args).point(luts)
def _is_multichannel(mode: str) -> bool: """Returns true if the color mode uses more than one channel. We need an easy way to test for this to, for example, figure out which dimension to rotate when we encounter an exif rotation flag. I didn't find a good way to do this using pillow, so instead we have a local list of all (currently) supported modes. If somebody comes across a better way to do this, in particular if it automatically grabs available modes from pillow a PR is very welcome :) Parameters ---------- mode : str A valid pillow mode string Returns ------- is_multichannel : bool True if the image uses more than one channel to represent a color, False otherwise. """ multichannel = { "BGR;15": True, "BGR;16": True, "BGR;24": True, "BGR;32": True, } if mode in multichannel: return multichannel[mode] return Image.getmodebands(mode) > 1
def image_tint(im, tint='#ff0000'): src = Image.new('RGB', im.size) src.paste(im) tr, tg, tb = getrgb(tint) tl = getcolor(tint, "L") # tint color's overall luminosity if not tl: tl = 1 # avoid division by zero tl = float(tl) # compute luminosity preserving tint factors sr, sg, sb = map(lambda tv: tv / tl, (tr, tg, tb)) # per component adjustments # create look-up tables to map luminosity to adjusted tint # (using floating-point math only to compute table) luts = (list(map(lambda lr: int(lr * sr + 0.5), range(256))) + list(map(lambda lg: int(lg * sg + 0.5), range(256))) + list(map(lambda lb: int(lb * sb + 0.5), range(256)))) l = grayscale(src) # 8-bit luminosity version of whole image if Image.getmodebands(src.mode) < 4: merge_args = (src.mode, (l, l, l)) # for RGB verion of grayscale else: # include copy of src image's alpha layer a = Image.new("L", src.size) a.putdata(src.getdata(3)) merge_args = (src.mode, (l, l, l, a)) # for RGBA verion of grayscale luts += range(256) # for 1:1 mapping of copied alpha values return Image.merge(*merge_args).point(luts)
def image_tint(src, tint='#fffab5'): if Image.isStringType(src): # file path? src = Image.open(src) if src.mode not in ['RGB', 'RGBA']: raise TypeError('Unsupported source image mode: {}'.format(src.mode)) src.load() tr, tg, tb = getrgb(tint) tl = getcolor(tint, "L") # tint color's overall luminosity if not tl: tl = 1 # avoid division by zero tl = float(tl) # compute luminosity preserving tint factors sr, sg, sb = map(lambda tv: tv/tl, (tr, tg, tb)) # per component # adjustments # create look-up tables to map luminosity to adjusted tint # (using floating-point math only to compute table) luts = (tuple(map(lambda lr: int(lr*sr + 0.5), range(256))) + tuple(map(lambda lg: int(lg*sg + 0.5), range(256))) + tuple(map(lambda lb: int(lb*sb + 0.5), range(256)))) l = grayscale(src) # 8-bit luminosity version of whole image if Image.getmodebands(src.mode) < 4: merge_args = (src.mode, (l, l, l)) # for RGB verion of grayscale else: # include copy of src image's alpha layer a = Image.new("L", src.size) a.putdata(src.getdata(3)) merge_args = (src.mode, (l, l, l, a)) # for RGBA verion of grayscale luts += tuple(range(256)) # for 1:1 mapping of copied alpha values return Image.merge(*merge_args).point(luts)
def image_tint(src, tint="#ffffff"): # From https://stackoverflow.com/a/12310820 if src.mode not in ["RGB", "RGBA"]: raise TypeError("Unsupported source image mode: {}".format(src.mode)) src.load() tr, tg, tb = getrgb(tint) tl = getcolor(tint, "L") if not tl: tl = 1 tl = float(tl) sr, sg, sb = map(lambda tv: tv / tl, (tr, tg, tb)) luts = (tuple(map(lambda lr: int(lr * sr + 0.5), range(256))) + tuple(map(lambda lg: int(lg * sg + 0.5), range(256))) + tuple(map(lambda lb: int(lb * sb + 0.5), range(256)))) l = grayscale(src) if Image.getmodebands(src.mode) < 4: merge_args = (src.mode, (l, l, l)) else: a = Image.new("L", src.size) a.putdata(src.getdata(3)) luts += tuple(range(256)) return Image.merge(*merge_args).point(luts)
def image_tint(self, source_path, tint='#ffffff'): ''' Take an image from a path and convert it to a tinted string for sprite coloration. :param source_path: sting path to image :param tint: string color code in hex :return: string of modified image ''' img_source = Image.open(source_path) # Get the image from specified path tint_red, tint_green, tint_blue = getrgb(tint) # Get color tint of each color tint_lum = getcolor(tint, "L") # Tint color luminosity if tint_lum == 0: # Avoid division by 0 tint_lum = 1 tint_lum = float(tint_lum) # Compute luminosity preserving tint factors sr, sg, sb = map(lambda tv: tv / tint_lum, (tint_red, tint_green, tint_blue)) # per component adjustments # create look-up tables to map luminosity to adjusted tint # (using floating-point math only to compute table) luts = (list(map(lambda lr: int(lr * sr + 0.5), range(256))) + list(map(lambda lg: int(lg * sg + 0.5), range(256))) + list(map(lambda lb: int(lb * sb + 0.5), range(256)))) l = grayscale(img_source) # 8-bit luminosity version of whole image if Image.getmodebands(img_source.mode) < 4: merge_args = (img_source.mode, (l, l, l)) # for RGB verion of grayscale else: # include copy of img_source image's alpha layer a = Image.new("L", img_source.size) a.putdata(img_source.getdata(3)) merge_args = (img_source.mode, (l, l, l, a)) # for RGBA verion of grayscale luts += range(256) # for 1:1 mapping of copied alpha values return Image.merge(*merge_args).point(luts) # Return string of image
def check(mode, *result): signature = ( Image.getmodebase(mode), Image.getmodetype(mode), Image.getmodebands(mode), Image.getmodebandnames(mode), ) assert signature == result
def check(mode, *result): signature = ( Image.getmodebase(mode), Image.getmodetype(mode), Image.getmodebands(mode), Image.getmodebandnames(mode), ) self.assertEqual(signature, result)
def averageColorUnlessIsBackground(img, key_color, key_thres, key_ratio): count = 0 avgc = MapFold(Averager, Image.getmodebands(img.mode)) for px in imagePixels(img): avgc.accept(px) distances = map(lambda ab: abs(ab[0] - ab[1]), zip(px, key_color)) if sum(distances) < key_thres: count += 1 return map(int, avgc.finish()) if count < key_ratio*(img.width*img.height) else None
def averageColor(img, key_color, thres): def dist(a, b): return abs(a - b) #< color distance averager = MapFold(Averager, Image.getmodebands(img.mode)) n_inthres = 0 for pix in imagePixels(img): averager.accept(pix) dists = map(lambda ab: dist(ab[0], ab[1]), zip(key_color, pix)) if sum(dists) < thres: n_inthres += 1 return (averager.finish(), n_inthres)
def averageColor(img, keyc) -> Tuple[tuple, int]: def dist(a, b): return abs(a - b) #< color distance averager = MapFold(Averager, Image.getmodebands(img.mode)) n_thres = 0 for y in range(0, img.height): for x in range(0, img.width): rgb = img.getpixel((x, y)) averager.accept(rgb) dists = map(lambda ab: dist(ab[0], ab[1]), zip(keyc.color, rgb) ) if sum(dists) > keyc.thres: n_thres += 1 return (averager.finish(), n_thres)
def image_tint(image, tint='#ffffff'): """ Function to merge two images without alpha Parameters: image (str): Path to the image tint (str): Hex code for the tint Returns: Image object for further use """ image = image.convert('RGBA') image.load() tr, tg, tb = getrgb(tint) tl = getcolor(tint, "L") # tint color's overall luminosity tl = 1 if not tl else tl # avoid division by zero tl = float(tl) # compute luminosity preserving tint factors sr, sg, sb = map(lambda tv: tv / tl, (tr, tg, tb)) # per component # adjustments # create look-up tables to map luminosity to adjusted tint # (using floating-point math only to compute table) luts = (tuple(map(lambda lr: int(lr * sr + 0.5), range(256))) + tuple(map(lambda lg: int(lg * sg + 0.5), range(256))) + tuple(map(lambda lb: int(lb * sb + 0.5), range(256)))) lum = grayscale(image) # 8-bit luminosity version of whole image if Image.getmodebands(image.mode) < 4: merge_args = (image.mode, (lum, lum, lum) ) # for RGB verion of grayscale else: # include copy of image image's alpha layer a = Image.new("L", image.size) a.putdata(image.getdata(3)) merge_args = (image.mode, (lum, lum, lum, a) ) # for RGBA verion of grayscale luts += tuple(range(256)) # for 1:1 mapping of copied alpha values return Image.merge(*merge_args).point(luts)
def color(mode): bands = Image.getmodebands(mode) if bands == 1: return 1 else: return tuple(range(1, bands + 1))
def channelHistogram(img) -> Tuple: n_channels = Pillow.getmodebands(img.mode) hist = img.histogram() return tuple(hist[i:i + 256] for i in range(0, n_channels * 256, 256))
def ingest_data(self, uploadSession_id, imageDir): ''' task for the ingest route, to ingest the data an upload sessions points to ''' import voxel_globe.ingest.models as IngestModels import numpy from voxel_globe.tools.camera import save_krt uploadSession = IngestModels.UploadSession.objects.get(id=uploadSession_id); #directories = uploadSession.directory.all(); #imageDirectory = directories.filter(name='image') #metaDirectory = directories.filter(name='meta') imageCollection = voxel_globe.meta.models.ImageCollection.create(name="Generic Upload %s (%s)" % (uploadSession.name, uploadSession_id), service_id = self.request.id); imageCollection.save(); r = numpy.eye(3); t = [0, 0, 0]; gpsList = [] gpsList2 = [] for d in glob(os.path.join(imageDir, '*'+os.path.sep), False): files = glob(os.path.join(d, '*'), False); files.sort() for f in files: self.update_state(state='PROCESSING', meta={'stage':'File %s of %d' % (f, len(files))}) zoomifyName = f[:-4] + '_zoomify' pid = Popen(['vips', 'dzsave', f, zoomifyName, '--layout', 'zoomify']) pid.wait(); #convert the slashes to URL slashes relFilePath = urllib.pathname2url(os.path.relpath(f, env['VIP_IMAGE_SERVER_ROOT'])); basename = os.path.split(f)[-1] relZoomPath = urllib.pathname2url(os.path.relpath(zoomifyName, env['VIP_IMAGE_SERVER_ROOT'])); with open(f, 'rb') as fid: magic = fid.read(4) image_info = {} if magic == '49492A00'.decode('hex') or \ magic == '4D4D002A'.decode('hex'): logger.debug('Tifffile: %s', f) from tifffile import TiffFile with TiffFile(f) as image: if image.pages[0].dtype == 's': image_info['dtype'] = numpy.dtype('S') else: image_info['dtype'] = numpy.dtype(image.pages[0].dtype) image_info['bps'] = image.pages[0].bits_per_sample image_info['height'] = image.pages[0].shape[0] #Yep, y,x,z order image_info['width'] = image.pages[0].shape[1] try: image_info['bands'] = image.pages[0].shape[2] except IndexError: image_info['bands'] = 1 else: logger.debug('Pil: %s', f) from PIL import Image with Image.open(f) as image: #The getmode* commands do not give you the REAL datatypes. I need the #REAL (numpy in this case) bps, not some random PIL designation image_info['dtype'] = numpy.dtype(Image._MODE_CONV[image.mode][0]) #probably doesn't work well for bool... Oh well image_info['bps'] = image_info['dtype'].itemsize*8 image_info['width'] = image.size[0] #Yep, x,y order image_info['height'] = image.size[1] image_info['bands'] = Image.getmodebands(image.mode) img = voxel_globe.meta.models.Image.create( name="Generic Upload %s (%s) Frame %s" % (uploadSession.name, uploadSession_id, basename), imageWidth=image_info['width'], imageHeight=image_info['height'], numberColorBands=image_info['bands'], pixelFormat=image_info['dtype'].char, fileFormat='zoom', imageUrl='%s://%s:%s/%s/%s/' % (env['VIP_IMAGE_SERVER_PROTOCOL'], env['VIP_IMAGE_SERVER_HOST'], env['VIP_IMAGE_SERVER_PORT'], env['VIP_IMAGE_SERVER_URL_PATH'], relZoomPath), originalImageUrl='%s://%s:%s/%s/%s' % (env['VIP_IMAGE_SERVER_PROTOCOL'], env['VIP_IMAGE_SERVER_HOST'], env['VIP_IMAGE_SERVER_PORT'], env['VIP_IMAGE_SERVER_URL_PATH'], relFilePath), service_id = self.request.id); img.save(); imageCollection.images.add(img); origin = [0,0,0]; logger.debug('Origin is: %s' % origin) k = numpy.eye(3); k[0,2] = image_info['width']/2; k[1,2] = image_info['height']/2; save_krt(self.request.id, img, k, r, t, origin); voxel_globe.meta.models.Scene.create(name="Generic origin %s (%s)" % (uploadSession.name, uploadSession_id), service_id = self.request.id, geolocated=False, origin='POINT(%0.12f %0.12f %0.12f)' % \ (0,0,0)).save() uploadSession.delete()