def __find_chars(img): log_info('__find_chars called') # Convert image to B&W gray = array(img.convert("L")) # Convert image to binary ret, mask = threshold(gray, 180, 255, THRESH_BINARY) image_final = bitwise_and(gray, gray, mask=mask) Image.fromarray(image_final).save('image_final.png') ret, new_img = threshold(image_final, 180, 255, THRESH_BINARY_INV) Image.fromarray(new_img).save('new_img.png') # Idk kernel = getStructuringElement(MORPH_CROSS, (3, 3)) dilated = dilate(new_img, kernel, iterations=1) Image.fromarray(dilated).save('out.png') _, contours, _ = findContours(dilated, RETR_EXTERNAL, CHAIN_APPROX_NONE) coords = [] for contour in contours: # get rectangle bounding contour [x, y, w, h] = boundingRect(contour) # ignore large chars (probably not chars) # if w > 70 and h > 70: # continue coords.append((x, y, w, h)) log_info('__find_chars completed') return coords
def __add_b(img, coords, c): log_info('__add_b started') tmp = img.copy() b = Image.open(f'{bin_path}/Resources/Frying/B.png') for coord in coords: if random(1)[0] < c: resized = b.copy() resized.thumbnail((coord[2], coord[3]), Image.ANTIALIAS) tmp.paste(resized, (int(coord[0]), int(coord[1])), resized) log_info('__add_b completed') return tmp
def __add_lasers(img, coords): log_info('__add_lasers started') if not coords: return img tmp = img.copy() laser = Image.open(f'{bin_path}/Resources/Frying/laser1.png') for coord in coords: tmp.paste(laser, (int(coord[0] - laser.size[0] / 2), int(coord[1] - laser.size[1] / 2)), laser) log_info('__add_lasers completed') return tmp
async def __upload_to_imgur(path, caption): log_info('__upload started') if not isfile(path): log_warn('File to be uploaded not found') return # if path[-3:] == 'mp4': # remove(path) # log_warn('Skipping mp4 upload') # return log_info('Authorizing imgur client') im = Imgur(environ.get('IMGUR_CLIENT_ID'), environ.get('IMGUR_CLIENT_KEY'), environ.get('IMGUR_ACCESS_TOKEN'), environ.get('IMGUR_REFRESH_TOKEN')) for _ in range(5): try: im.upload_image(path=abspath(path), title=caption, album=environ.get('IMGUR_ALBUM')) log_info('Image successfully uploaded') break except Exception: log_warn('Upload failed, refreshing token') im.refresh_access_token() sleep(10) continue else: log_error('Upload failed, proceeding') log_info('Deleting file') remove(path)
def __find_eyes(img): log_info('__find_eyes starting') coords = [] face_cascade = CascadeClassifier( f'{bin_path}/Resources/Classifiers/haarcascade_frontalface.xml') eye_cascade = CascadeClassifier( f'{bin_path}/Resources/Classifiers/haarcascade_eye.xml') gray = array(img.convert("L")) faces = face_cascade.detectMultiScale(gray, 1.3, 5) for (x, y, w, h) in faces: roi_gray = gray[y:y + h, x:x + w] eyes = eye_cascade.detectMultiScale(roi_gray) for (ex, ey, ew, eh) in eyes: coords.append((x + ex + ew / 2, y + ey + eh / 2)) log_info('__find_eyes completed') return coords
async def on_message(message): log_info(f'Message from {message.author}: {message.content}') if message.author == client.user: return # TODO: Enable frying embeds as well if len(message.embeds): print(f'Found {len(message.embeds)} embeds') print(message.embeds[0].url) if len(message.attachments): async with message.channel.typing(): await fry_attachment_helper(message) if message.content.lower().startswith('!ping'): log_info('Ping') await message.channel.send(f'Pong! Latency: {client.latency}')
def __add_emojis(img, m): log_info('__add_emojis started') emojis = ['100', 'OK', 'laugh', 'fire', 'think'] tmp = img.copy() for i in emojis: emoji = Image.open(f'{bin_path}/Resources/Frying/%s.png' % i) for _ in range(int(random(1)[0] * m)): coord = random(2) * array([img.width, img.height]) size = int((img.width / 10) * (random(1)[0] + 1)) + 1 theta = random(1)[0] * 360 resized = emoji.copy() resized = resized.rotate(theta) resized.thumbnail((size, size), Image.ANTIALIAS) tmp.paste(resized, (int(coord[0]), int(coord[1])), resized) log_info('__add_emojis completed') return tmp
def __upload_to_imgur(path, caption): log_info('__upload started') if not isfile(path): log_warn('File to be uploaded not found') return # TODO: Convert to GIF and upload. if path[-3:] == 'mp4': remove(path) log_warn('Skipping mp4 upload') return log_info('Authorizing imgur client') im = Imgur(environ.get('IMGUR_CLIENT_ID'), environ.get('IMGUR_CLIENT_KEY'), environ.get('IMGUR_ACCESS_TOKEN'), environ.get('IMGUR_REFRESH_TOKEN')) for _ in range(5): # noinspection PyBroadException try: im.upload_image(path=abspath(path), title=caption, album=environ.get('IMGUR_ALBUM')) except Exception: log_warn('Upload failed, refreshing token') im.refresh_access_token() sleep(10) continue log_info('Deleting file') remove(path) return
def __add_bulge(img: Image.Image, coords, radius, flatness, h, ior): """ Creates a bulge like distortion to the image :param img: The Image :type img: PIL.Image :param coords: Numpy Array with Coordinates of Centre of Bulge :type coords: numpy.array :param radius: Radius of Bulge :type radius: int :param flatness: Flatness: 1 for Spherical, > 1 for Flat. :type flatness: int :param h: Height of Bulge :type h: int :param ior: Index of Refraction of Bulge Material :type ior: float :return: The Bulged Image :rtype: PIL.Image """ log_info('__add_bulge started') width = img.width height = img.height # noinspection PyTypeChecker img_data = array(img) if width * height > 9000000: return img # Determine range of pixels to be checked (square enclosing bulge) x_min = int(coords[0] - radius) if x_min < 0: x_min = 0 x_max = int(coords[0] + radius) if x_max > width: x_max = width y_min = int(coords[1] - radius) if y_min < 0: y_min = 0 y_max = int(coords[1] + radius) if y_max > height: y_max = height # Make sure that bounds are int and not np array if isinstance(x_min, type(array([]))): x_min = x_min[0] if isinstance(x_max, type(array([]))): x_max = x_max[0] if isinstance(y_min, type(array([]))): y_min = y_min[0] if isinstance(y_max, type(array([]))): y_max = y_max[0] # Array for holding bulged image bulged = copy(img_data) for y in range(y_min, y_max): for x in range(x_min, x_max): ray = array([x, y]) # Find the magnitude of displacement # in the xy plane between the ray and focus s = sqrt(sum(square(ray - coords))) # If the ray is in the centre of the bulge or beyond the radius, # it doesn't need to be modified if not 0 < s < radius: bulged[y][x] = img_data[y][x] continue # Slope of the bulge relative to xy plane at (x, y) of the ray m = -s / (flatness * sqrt(radius**2 - s**2)) # Find the angle between the ray and the normal of the bulge theta = pi / 2 + arctan(1 / m) # Find the magnitude of the angle between # the XY plane and refracted ray using Snell's Law # s >= 0 -> m <= 0 -> arctan(-1/m) > 0, # but ray is below xy plane so we want a negative angle # arctan(-1/m) is therefore negated phi = abs(arctan(1 / m) - arcsin(sin(theta) / ior)) # Find length the ray travels in xy plane before hitting z=0 k = (h + (sqrt(radius**2 - s**2) / flatness)) / sin(phi) # Find intersection point normalized = (coords - ray) / sqrt(sum(square(coords - ray))) intersect = ray + normalized * k # Assign pixel the colour of pixel at intersection if 0 < intersect[0] < width - 1 and 0 < intersect[1] < height - 1: bulged[y][x] = img_data[int(intersect[1])][int(intersect[0])] else: # No light reaching the pixel bulged[y][x] = [0, 0, 0] img = Image.fromarray(bulged) log_info('__add_bulge completed') return img
def fry_image(update, url, number_of_cycles, args): log_info('Starting Image Fry') number_of_emojis = (3 if args['high-fat'] else 1 if args['low-fat'] else 0 if args['no-fat'] else 2) bulge_probability = (0.75 if args['heavy'] else 0 if args['light'] else 0.45) magnitude = 4 if args['deep'] else 1 if args['shallow'] else 2 bio = BytesIO() name = update.message.from_user.first_name bio.name = filename = '%s_%s_%s.png' % (update.message.chat_id, name, update.message.message_id) filepath = f'{bin_path}/temp/{filename}' caption = __get_caption(name, number_of_cycles, args) success, img = __get_image(url) if not success: log_error('Image download failed') return log_info('Image successfully downloaded') img = __fry(img, number_of_cycles, number_of_emojis, bulge_probability, args['chilli'], args['vitamin-b']) log_info('Frying effects starting') fs = [__posterize, __sharpen, __increase_contrast, __colorize] for _ in range(number_of_cycles): shuffle(fs) for f in fs: img = f(img, magnitude) log_info('Frying effects applied') img.save(bio, 'PNG') bio.seek(0) update.message.reply_photo(bio, caption=caption, quote=True) log_info('Image saved and replied') img.save(filepath, 'PNG') __upload_to_imgur(filepath, caption) log_info('Image frying process completed')
def __fry(img, number_of_cycles, number_of_emojis, bulge_probability, laser, vitamin_b): log_info('__fry starting') if laser: log_info('Finding eye coordinates') eye_coords = __find_eyes(img) log_info('Eye coordinates found') img = __add_lasers(img, eye_coords) log_info('Laser eyes added') if vitamin_b: log_info('Finding char coordinates') coords = __find_chars(img) log_info('Char coordinates found') img = __add_b(img, coords, number_of_emojis / 20) log_info('"B"s added') log_info('Starting emoji adding') img = __add_emojis(img, number_of_cycles * number_of_emojis) log_info('emojis added') log_info('Starting bulge adding') w, h = img.width - 1, img.height - 1 for _ in range(number_of_cycles): if random(1)[0] > bulge_probability: continue # __add_bulge(img, coords, radius, flatness, h, ior) img = __add_bulge( img, array([int(w * random(1)), int(h * random(1))]), int(((img.width + img.height) / 10) * (random(1)[0] + 1)), 1 + random(3)[0], 6 + random(2)[0], 1.2 + random(2)[0]) log_info('Bulges added, __fry completed') return img
def __fry(img, number_of_cycles, number_of_emojis, bulge_probability, laser, vitamin_b): log_info('__fry starting') if laser: log_info('Finding eye coordinates') coords = __find_eyes(img) if coords: log_info('Eye coordinates found') img = __add_lasers(img, coords) log_info('Laser eyes added') else: log_info('No eye coordinates found') if vitamin_b: log_info('Finding char coordinates') coords = __find_chars(img) if coords: log_info('Char coordinates found') img = __add_b(img, coords, number_of_emojis / 20) log_info('"B"s added') else: log_info('No char coordinates found') log_info('Adding emojis') img = __add_emojis(img, number_of_cycles * number_of_emojis) log_info('emojis added') log_info('Adding bulges') img = __add_bulges_helper(img, number_of_cycles, bulge_probability) log_info('Bulges added, __fry completed') return img
async def fry_image(message, attachment, number_of_cycles, args, index): log_info('Starting Image Fry') try: data = await attachment.read() img = Image.open(BytesIO(data)) except Exception: log_error('Image download failed') return if img.mode != 'RGB': img = img.convert('RGB') # img.save(filepath) log_info('Image successfully downloaded') number_of_emojis = (3 if args['high-fat'] else 1 if args['low-fat'] else 0 if args['no-fat'] else 2) bulge_probability = (0.75 if args['heavy'] else 0 if args['light'] else 0.45) magnitude = 4 if args['deep'] else 1 if args['shallow'] else 2 caption = __get_caption(message.author.name, number_of_cycles, args) img = __fry(img, number_of_cycles, number_of_emojis, bulge_probability, not args['no-chilli'], args['vitamin-b']) log_info('Frying effects starting') fs = [__posterize, __sharpen, __increase_contrast, __colorize] for _ in range(number_of_cycles): shuffle(fs) for f in fs: img = f(img, magnitude) log_info('Frying effects applied') png, quality = await send_image(message, img, attachment.filename, caption) if not quality: return filename = '%s_%s_%s_%s.' % (message.guild.id if message.guild else 'NONE', message.author.name, message.id, index) + 'png' if png else 'jpg' filepath = path_join(bin_path, 'temp', filename) if png: img.save(filepath, 'PNG', optimize=True) else: img.save(filepath, 'JPEG', optimize=True, quality=quality) log_info('Image saved and replied') await __upload_to_imgur(filepath, caption) log_info('Image frying process completed')