Logo elodees  elodees

A caring AI for a better world













Only alphabetic characters accented or not as well as the space are accepted

Logo IA




Image enhancement and restoration





No account yet ?

Sign up to access all content




Tensorflow playground


Face Enhancement



Face pipeline


Global Restoration



Pipeline


Bringing-Old-Photos-Back-to-Life

License: MITLicenseMIT  Copyright (c) Microsoft Corporation.


GitHub





Tested in Anaconda and Python 3.7

import cv2
import math
import numpy as np
from matplotlib import pyplot as plt
 
def apply_mask(matrix, mask, fill_value):
 
    masked = np.ma.array(matrix, mask=mask, fill_value=fill_value)
 
    return masked.filled()
 
def apply_threshold(matrix, low_value, high_value):
 
    low_mask = matrix < low_value
 
    matrix = apply_mask(matrix, low_mask, low_value)
 
    high_mask = matrix > high_value
 
    matrix = apply_mask(matrix, high_mask, high_value)
 
    return matrix
 
def simplest_cb(img, percent):
 
    assert img.shape[2] == 3
 
    assert percent > 0 and percent < 100
 
    half_percent = percent / 200.0
 
    channels = cv2.split(img)
 
    out_channels = []
 
    for channel in channels:
 
        assert len(channel.shape) == 2
 
        height, width = channel.shape
 
        vec_size = width * height
 
        flat = channel.reshape(vec_size)
 
        assert len(flat.shape) == 1
 
        flat = np.sort(flat)
 
        n_cols = flat.shape[0]
 
        low_val  = flat[math.floor(n_cols * half_percent)]
 
        high_val = flat[math.ceil( n_cols * (1.0 - half_percent))]
 
        thresholded = apply_threshold(channel, low_val, high_val)
 
        normalized = cv2.normalize(thresholded, thresholded.copy(), 0, 255, cv2.NORM_MINMAX)
 
        out_channels.append(normalized)
 
    return cv2.merge(out_channels)
 
if __name__ == '__main__':
 
    img = cv2.imread(r'pexels-collis-3056059.jpg')
 
    out = simplest_cb(img, 1)
 
 
    plt.imshow(cv2.cvtColor(img.astype('uint8'), cv2.COLOR_BGR2RGB))
    plt.axis('off')
    plt.title('Original image')
    plt.show()
 
    plt.imshow(cv2.cvtColor(out.astype('uint8'), cv2.COLOR_BGR2RGB))
    plt.axis('off')
    plt.title('Image enhancement and restoration')
    plt.show()
 
    cv2.imwrite('pexels-collis-3056059-Image-enhancement-and-restoration.jpg', out)
 


image-enhancement-and-restoration

License: MITLicenseMIT  Copyright (c) 2016-2018 Plotly, Inc


GitHub



Original image

Free image provided by pexel.com

Image enhancement and restoration

Free image provided by pexel.com








Tested in Anaconda and Python 3.7

import cv2
import numpy as np
import matplotlib.pyplot as plt
 
import os
 
input_path = (r'Input')
output_path = (r'Output')
 
def faded(image):
    """
    Method: algorithm to fix the faded image
    Returns: the fixed image
    """
 
    image_copy = image.copy() # copy image
    h, w, d = image.shape # get height, width, depth of the image
    copy_h, copy_w = h, w # make a copy of the height and width
 
    def find_thresh():
        """
        Method: Finds the thresh of the image. It creates an empty black canvas and uses canny to find the edges.
                Once the edges are found, it runs through threshhold to make it clearer.
                It then finds the contours of the image using the thresh.
 
        Returns: the drawn contours of the image on the black canvas.
        """
 
        # creates an empty black canvas (same size as the original image)
        # this will be used to draw the contours on
        black_canvas = np.zeros((h, w, d), np.uint8)
 
        # uses canny to detect edges on the image - this will find the edges
        edge = cv2.Canny(image, 90, 170)
 
        # uses threshold with the canny edges to make it clearer - it uses  a light value (127)
        thresh = cv2.threshold(edge, 127, 255, cv2.THRESH_BINARY)[1]
 
        # finds all the contours of the threshold
        contours = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[0]
 
        # draws white contours on the empty blank canvas
        # setting the stroke to 3 will lead to easier border detection
        return cv2.drawContours(black_canvas, contours, -1, (255, 255, 255), 3)
 
    def create_kernels():
        """
        Method: creates the horizontal and vertical kernels
        Returns: the horizontal & vertical kernel
        """
 
        # creates the horizontal kernel - this will be used to find the horizontal lines in the faded border
        horizontal = cv2.getStructuringElement(cv2.MORPH_RECT, (150, 1))
 
        # creates the vertical kernel - this will be used to find the vertical lines in the faded border
        vertical = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 150))
 
        # Returns the horizontal & vertical kernel
        return horizontal, vertical
 
    def kernel_lines(horizontal, vertical, canvas):
        """
        Method: finds the horizontal & vertical lines on the canvas (the lines of the faded border)
        Params:
            horizontal: the horizontal kernal
            vertical: the vertical kernal
            canvas: the canvas that has the threshold and contours drawn from findThresh()
        Returns: the horizontal & vertical lines
        """
 
        # finds the horizontal lines in the canvas border using morphologyEx
        horizontal_lines = cv2.morphologyEx(canvas, cv2.MORPH_OPEN, horizontal)
 
        # finds the vertical lines in the canvas border using morphologyEx
        vertical_lines = cv2.morphologyEx(canvas, cv2.MORPH_OPEN, vertical)
 
        # the horizontal & vertical lines
        return horizontal_lines, vertical_lines
 
    def find_borders(canvas):
        """
        Method: finds the full rectangle border of the damaged faded image
        Params:
            canvas: the canvas that has the threshold and contours drawn from findThresh()
        Returns:
            Returns the faded border outline contours found in the gray image
            using (RETR_EXTERNAL) to retrieve the extreme outer contours
            using (CHAIN_APPROX_SIMPLE) to compress horizontal & vertical to only leave their end points
            [0] at the end to only get the contour and not the hierarchy
         """
 
        # gets the horizontal & vertical kernal from create_kernels()
        horizontal, vertical = create_kernels()
 
        # gets the horizontal & vertical lines from kernel_lines()
        horizontal_lines, vertical_lines = kernel_lines(horizontal, vertical, canvas)
 
        # add the horizontal & vertical lines using bitwise_and to form a rectangle border
        # bitwise_and is used to find both the horizontal & vertical lines which are ON
        border = cv2.bitwise_and(horizontal_lines, vertical_lines)
 
        # change the border to gray to use findContours
        border_gray = cv2.cvtColor(border, cv2.COLOR_BGR2GRAY)
 
        # returns the faded rectangle border contours found in the gray image
        return cv2.findContours(border_gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
 
    def find_border_points(contours):
        """
        Method: finds the 4 rectangle (top, left, bottom, right) border points of the contours
        Params:
            contours: has the faded rectangle border outline of the image from find_borders()
        Returns: the 4 points (top, left, bottom, right) of the faded border outline
        """
 
        border_points = [] # stores the border points
        for c in contours: # loop through contours
            (x, y, w, h) = cv2.boundingRect(c) # get the bounding rect for each counter
            border_points.append([x,y, x+w,y+h]) # appends the intersecting points
 
        left, top = np.min(border_points, axis=0)[:2] # gets the left and top points
        right, bottom = np.max(border_points, axis=0)[2:] # gets the right and bottom points
 
        # returns the 4 points of the border outline
        return top, left, bottom, right
 
    def fix_image(top_left, bottom_right):
        """
        Method: Fixes the faded image. It does so by cropping out the faded border section
                using the 4 border points from the original image. I then add a black contrast to the cropped canvas
        Params:
            top_left: the top left point of the border
            bottom_right: the bottom right point of the border
        """
 
        # gets a cropped section of the original image using the top_left, bottom_right points
        cropped_image = image_copy[4 + top_left[0]: - 3 + bottom_right[0], 2 + top_left[1]: -2 + bottom_right[1]]
 
        # store height, width, depth of the cropped image
        crop_h, crop_w, crop_d = cropped_image.shape
 
        # dark contrast to add to the black canvas
        dark_contrast = 33
 
        # create black canvas using the cropped image size
        # this canvas now stores the faded border and we add the dark_contrast to make it darker
        fixed_cropped_image_canvas = np.zeros((crop_h, crop_w, crop_d), np.uint8) + dark_contrast
 
        # subtracting the cropped_image from the fixed_cropped_image_canvas
        fixed_border_image = cv2.subtract(cropped_image, fixed_cropped_image_canvas)
 
        # setting the faded border region in the image_copy to the fixed border region
        image_copy[4 + top_left[0]: - 3 + bottom_right[0], 2 + top_left[1]: -2 + bottom_right[1]] = fixed_border_image
 
    def blend_image(top, left, bottom, right):
        """
        Method: blends the harsh rectangle border using inpaint
        Params:
            top: the top point of the border
            left: the left point of the border
            bottom: the bottom point of the border
            right: the right point of the border
        """
 
        # fixes the image (changes the image_copy)
        fix_image((top, left), (bottom, right))
 
        # creating black canvas the same size of the original image
        # this is used to blend the harsh border lines when the image is fixed
        blend_canvas = np.zeros((copy_h, copy_w, d), np.uint8)
 
        # draw a rectangle on the blend canvas using the 4 points (top, left, bottom, right)
        # fill the rectangle to white with a stroke of 7 - this helps to get a better region neighbourhood for inpaint
        cv2.rectangle(blend_canvas, (left, top), (right, bottom), (255, 255, 255), 7)
 
        # change the blend canvas to gray
        blend_gray = cv2.cvtColor(blend_canvas, cv2.COLOR_BGR2GRAY)
 
        # use inpaint to restore the selected region in the image using the region neighbourhood
        return cv2.inpaint(image_copy, blend_gray, 3, cv2.INPAINT_TELEA)
 
    canvas = find_thresh() # finds the thresh
    contours = find_borders(canvas) #  finds the border contours
    top, left, bottom, right = find_border_points(contours) # get the faded rectangle border points
    return blend_image(top, left, bottom, right) # return the fixed image
 
 
def damaged(image):
    """
    Method: fixes the damaged image by using fastNlMeansDenoisingColored
            this will remove all the noise from the image and smoothen it
    Returns: the fixed image
    """
 
    image_copy = image.copy() # copy image
    denoised_image = cv2.fastNlMeansDenoisingColored(image_copy, None, 9, 9, 7, 21)
 
    # return the denoised_image in gray
    return cv2.cvtColor(denoised_image, cv2.COLOR_BGR2GRAY)
 
def find_image_algorithm(img):
    """
    Method: finds which fixing algorithm to use depending on the image histogram by finding
            the highest spike (BLUE, GREEN, RED) in the x_axis
    Returns: the fixed image
    """
 
    def maximum(blue, green, red):
        """
        Method: finds the maximum x_axis of the blue, green, red histogram
        Returns: the maximum x_axis
        """
        return max([blue, green, red])
 
    def find_highest_spike():
        indices = list(range(0, 256)) # make a list of range 0 to 256
 
        # set all variables to Array of size 3 and fill it with None
        # the size is set to 3 because of BGR (Blue, Green, Red)
 
        # colors - used to store the calcHistogram of each BGR
        # colors_val - used to store the ravel of each BGR histogram
        # colors_zipped - used to store the zipped value of colors_val
        # colors_index - used to store the sorted zipped colors for x, y values
 
        colors = colors_val = colors_index = colors_zipped = [None] * 3
 
        # loop 3 times to caluclate the Blue, Green, Red
        for i in range(3):
            colors[i] = cv2.calcHist([img], [i], None, [256], [0, 256])
            colors_val[i] = colors[i].ravel()
            colors_zipped[i] = zip(colors_val[i], indices)
            colors_sorted = sorted(colors_zipped[i], reverse=True)
            colors_index[i] = [(x, y) for y, x in colors_sorted]
 
        # index of highest peak in histogram for the blue, green red
        blue_index = colors_index[0][0][0] # [0][0] to get the blue and [0] to get the x_axis
        green_index = colors_index[1][1][0] # [1][1] to get the green and [0] to get the x_axis
        red_index = colors_index[2][2][0] # [2][2] to get the red and [0] to get the x_axis
 
        # return the highest index
        return maximum(blue_index, green_index, red_index)
 
    # return the highest_spike value found
    return find_highest_spike()
 
for root, dirs, files in os.walk(input_path):
    for filename in files:
 
        img = cv2.imread(os.path.join(root, filename))
 
        plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
        plt.axis('off')
        plt.title('Originale image')
        plt.show()
 
        # store the highest x_axis value
        highest_x_axis_value = find_image_algorithm(img)
 
        # used to set the average points of color
        points_of_color = 110
        fixed_img = None
 
        # run the faded algorithm if the highest_x_axis_value is greater than the points_of_color
        if (highest_x_axis_value > points_of_color):
 
            fixed_img = damaged(img)
            plt.axis('off')
            plt.title('damaged')
            plt.imshow(fixed_img, cmap='gray')
            plt.show()
 
            cv2.imwrite(os.path.join(output_path, filename), fixed_img)
        else:
 
            fixed_img = faded(img)
            fixed_img = cv2.cvtColor(fixed_img, cv2.COLOR_BGR2RGB)
            plt.axis('off')
            plt.title('faded')
            plt.imshow(fixed_img)
            plt.show()
 
            cv2.imwrite(os.path.join(output_path, filename), fixed_img)
 


Image-Restoration - GitHub



Original image

Free image provided by pexel.com

Image enhancement and restoration

Free image provided by pexel.com


Original image

Free image provided by pexel.com

Image enhancement and restoration

Free image provided by pexel.com


Original image

Free image provided by pexel.com

Image enhancement and restoration

Free image provided by pexel.com










Welcome, my name is Eric Soupet and I am the administrator of the site elodees.com. elodees.com is a state of the art of Artificial Intelligence and aims to be collaborative, you can now offer content such as articles, events, tutorials, ... so don't hesitate !

Platform images credit : Pixabay - Pixabay License | Pexels - Pexels License