def calc_fitness_one( self, image_path ): #function for calculating fitness of one particular image orig_image = pc.rel_path( self.orig_image) #composing absolute path name for original image art_image = pc.rel_path( image_path) #composing absolute path name for current child orig_pixels = Image.open( orig_image).load() #getting array of pixels of original image art_pixels = Image.open( art_image).load() #getting array of pixels of current child image fitness = 0 #initially, fitness is 0 ( height, width ) = self.image_size #writing down height and width of images in pixels for i in range(height): #considering every possible pixel coordinates for j in range(width): orig_pixel = orig_pixels[ i, j] #writing down pixels of original image art_pixel = art_pixels[ i, j] #writing down pixels of current children image x = math.sqrt(((orig_pixel[0] - art_pixel[0])**2) + ((orig_pixel[1] - art_pixel[1])**2) + ((orig_pixel[2] - art_pixel[2])** 2)) #first of all writing down constant x as #square root of sum of squares of RGB values differences var = 30 #then define variance value for NORMAL DISTRIBUTION fitness += (1 / (var * math.sqrt(math.pi * 2))) * (math.e**(( (x / var)**2) * (-0.5))) #adding to fitness score NORMAL DISTRIBUTION value of x #I decided to choose NORMAL DISTRIBUTION because when pixels #difference is very small it is not so critical. Otherwise, our eyes #cannot build illusion of similarity. return fitness
def crossover(self, child_id, parents): #function for making crossover between parents child = Image.new( "RGB", self.image_size, "white" ) #creating child with undetermined pixels, let them be white child_pixels = child.load() #getting pixels of the child parents_pixels = [] #array of arrays of pixels of parents for i in range(self.parents_cnt): #traversing parents paths cur_path = pc.rel_path( parents[i]) #composing absolute path of some parent cur_pixels = Image.open( cur_path).load() #getting pixels of some parent parents_pixels.append( cur_pixels) #appending this array of pixels into one array ( height, width ) = self.image_size #writing down height and width of images in pixels figure_size = random.randint( self.min_figure_size, self.max_figure_size ) #we divide pixels into small squares and put into the #child this square of random parent #so we take random square side between pre-defined values for i in range(0, height, figure_size): #traversing all pixels coordinates for j in range( 0, width, figure_size ): #with period of square side value, because we will color #not one pixel, but a bunch of pixels of the child parent_id = random.randint(0, self.parents_cnt - 1) #taking random parent for k in range(i, min( height, i + figure_size)): #traversing current square coordinates for l in range(j, min(width, j + figure_size)): child_pixels[k, l] = parents_pixels[parent_id][ k, l] #coloring this square of randomly taken parent into child incomplete_path = "image" + str((self.generation + 1) * self.size + child_id) #we accumulate all images, because perodically #'permission denied' issue arises, so we calculate #image number of next generation, which will newborn child #have complete_path = pc.rel_path( incomplete_path) #compose absolute path for newborn child child.save(complete_path, "png") #save child image into that path return incomplete_path
def init_population(): #function for creating initial images paths = [] #array for defining absolute paths to initial images for i in range(len(initial_population)): cur_path = pc.rel_path( i ) #composing absolute path to the initial image number i (numbering from 0) paths.append( cur_path) #insert composed path into array of absolute paths cur_color = initial_population[ i] #taking pre-defined color for initial image number i new_image = Image.new( "RGB", image_size, cur_color) #creating new image with pre-defined size and color new_image.save(cur_path, "png") #saving created image with the composed path return paths
def mutate_one(self, image, max_disturbance ): #function for making mutation of one particular child path = pc.rel_path( image) #getting absolute path to the current child image to_be_mutated_image = Image.open(path) image_pixels = to_be_mutated_image.load( ) #getting array of pixels of the current child image ( height, width ) = self.image_size #getting height and width in pixels of child image rand_pixel_x = random.randint(0, height - 1) #taking random coordinates rand_pixel_y = random.randint(0, width - 1) (red, green, blue) = image_pixels[ rand_pixel_x, rand_pixel_y] #taking pixel of current child at random coordinates rand_red = random.randint( max(0, red - max_disturbance), min(255, red + max_disturbance)) #calculating new color RGB values rand_green = random.randint(max(0, green - max_disturbance), min(255, green + max_disturbance)) #as explained in rand_blue = random.randint( max(0, blue - max_disturbance), min(255, blue + max_disturbance)) #TODO max_disturbance CONSTANT #TODO IN main.py figure_size = random.randint( self.min_figure_size, self.max_figure_size ) #TODO SEE EXPLANATION OF max_figure_size CONSTANT IN figure_center_x = random.randint(figure_size, height - figure_size - 1) #TODO main.py figure_center_y = random.randint(figure_size, width - figure_size - 1) figure_pixels = Figure(figure_center_x, figure_center_y, figure_size, self.image_size).calculate_pixels() #getting array of pixels of figure with the help of 'Figure' class for coordinates in figure_pixels: image_pixels[coordinates] = ( rand_red, rand_green, rand_blue ) #painting figure on top of children (mutation) to_be_mutated_image.save(path, "png") #saving mutated child to its path
def resize_image( ): #function for compressing or stretching original image till the size with which we will work path = pc.rel_path(orig_image) #taking absolute path of the original image image = Image.open(path) image = image.resize(image_size) #changing size of the original image image.save(path) #saving changes into the file system