Skip to content

Commit 067d954

Browse files
authored
Add files via upload
1 parent 41e5d2a commit 067d954

File tree

3 files changed

+329
-0
lines changed

3 files changed

+329
-0
lines changed

README.md

+220
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
# GARI
2+
GARI (Genetic Algorithm for Reproducing Images) is a Python project that uses the PyGAD library for reproducing images using the genetic algorithm. GARI reproduces a single image using Genetic Algorithm (GA) by evolving pixel values. This project works with both color and gray images.
3+
4+
For implementing the genetic algorithm, the PyGAD library is used. Check its documentation here: https://pygad.readthedocs.io
5+
6+
**IMPORTANT** *If you are coming for the code of the tutorial [Reproducing Images using a Genetic Algorithm with Python](https://heartbeat.fritz.ai/reproducing-images-using-a-genetic-algorithm-with-python-91fc701ff84), then it has been moved to the [TutorialProject](https://github.com/ahmedfgad/GARI/tree/master/TutorialProject) directory on 18 May 2020.*
7+
8+
# PyGAD Installation
9+
10+
To install [PyGAD](https://pypi.org/project/pygad), simply use pip to download and install the library from [PyPI](https://pypi.org/project/pygad) (Python Package Index). The library lives a PyPI at this page https://pypi.org/project/pygad.
11+
12+
For Windows, issue the following command:
13+
14+
```python
15+
pip install pygad
16+
```
17+
18+
For Linux and Mac, replace `pip` by use `pip3` because the library only supports Python 3.
19+
20+
```python
21+
pip3 install pygad
22+
```
23+
24+
PyGAD is developed in Python 3.7.3 and depends on NumPy for creating and manipulating arrays and Matplotlib for creating figures. The exact NumPy version used in developing PyGAD is 1.16.4. For Matplotlib, the version is 3.1.0.
25+
26+
# Project Steps
27+
28+
The steps to follow in order to reproduce an image are as follows:
29+
30+
- Read an image
31+
- Prepare the fitness function
32+
- Create an instance of the pygad.GA class with the appropriate parameters
33+
- Run PyGAD
34+
- Plot results
35+
- Calculate some statistics
36+
37+
The next sections discusses the code of each of these steps.
38+
39+
## Read an Image
40+
41+
There is an image named `fruit.jpg` in the project which is read according to the next code.
42+
43+
```python
44+
import imageio
45+
import numpy
46+
47+
target_im = imageio.imread('fruit.jpg')
48+
target_im = numpy.asarray(target_im/255, dtype=numpy.float)
49+
```
50+
51+
Here is the read image.
52+
53+
![fruit](https://user-images.githubusercontent.com/16560492/36948808-f0ac882e-1fe8-11e8-8d07-1307e3477fd0.jpg)
54+
55+
Based on the chromosome representation used in the example, the pixel values can be either in the 0-255, 0-1, or any other ranges.
56+
57+
Note that the range of pixel values affect other parameters like the range from which the random values are selected during mutation and also the range of the values used in the initial population. So, be consistent.
58+
59+
## Prepare the Fitness Function
60+
61+
The next code creates a function that will be used as a fitness function for calculating the fitness value for each solution in the population. This function must be a maximization function that accepts 2 parameters representing a solution and its index. It returns a value representing the fitness value.
62+
63+
The fitness value is calculated using the sum of absolute difference between genes values in the original and reproduced chromosomes. The `gari.img2chromosome()` function is called before the fitness function to represent the image as a vector because the genetic algorithm can work with 1D chromosomes.
64+
65+
For more information about preparing the fitness function in PyGAD, please read the [PyGAD's documentation](https://pygad.readthedocs.io).
66+
67+
```python
68+
target_chromosome = gari.img2chromosome(target_im)
69+
70+
def fitness_fun(solution, solution_idx):
71+
fitness = numpy.sum(numpy.abs(target_chromosome-solution))
72+
73+
# Negating the fitness value to make it increasing rather than decreasing.
74+
fitness = numpy.sum(target_chromosome) - fitness
75+
return fitness
76+
```
77+
78+
## Create an Instance of the `pygad.GA` Class
79+
80+
It is very important to use random mutation and set the `mutation_by_replacement` to `True`. Based on the range of pixel values, the values assigned to the `init_range_low`, `init_range_high`, `random_mutation_min_val`, and `random_mutation_max_val` parameters should be changed.
81+
82+
If the image pixel values range from 0 to 255, then set `init_range_low` and `random_mutation_min_val` to 0 as they are but change `init_range_high` and `random_mutation_max_val` to 255.
83+
84+
Feel free to change the other parameters or add other parameters. Please check the [PyGAD's documentation](https://pygad.readthedocs.io) for the full list of parameters.
85+
86+
```python
87+
import pygad
88+
89+
ga_instance = pygad.GA(num_generations=20000,
90+
num_parents_mating=10,
91+
fitness_func=fitness_fun,
92+
sol_per_pop=20,
93+
num_genes=target_im.size,
94+
init_range_low=0.0,
95+
init_range_high=1.0,
96+
mutation_percent_genes=0.01,
97+
mutation_type="random",
98+
mutation_by_replacement=True,
99+
random_mutation_min_val=0.0,
100+
random_mutation_max_val=1.0)
101+
```
102+
103+
## Run PyGAD
104+
105+
Simply, call the `run()` method to run PyGAD.
106+
107+
```python
108+
ga_instance.run()
109+
```
110+
111+
## Plot Results
112+
113+
After the `run()` method completes, the fitness values of all generations can be viewed in a plot using the `plot_result()` method.
114+
115+
```python
116+
ga_instance.plot_result()
117+
```
118+
119+
Here is the plot after 20,000 generations.
120+
121+
![Fitness Values](https://user-images.githubusercontent.com/16560492/82232124-77762c00-992e-11ea-9fc6-14a1cd7a04ff.png)
122+
123+
## Calculate Some Statistics
124+
125+
Here is some information about the best solution.
126+
127+
```python
128+
# Returning the details of the best solution.
129+
solution, solution_fitness, solution_idx = ga_instance.best_solution()
130+
print("Fitness value of the best solution = {solution_fitness}".format(solution_fitness=solution_fitness))
131+
print("Index of the best solution : {solution_idx}".format(solution_idx=solution_idx))
132+
133+
if ga_instance.best_solution_generation != -1:
134+
print("Best fitness value reached after {best_solution_generation} generations.".format(best_solution_generation=ga_instance.best_solution_generation))
135+
136+
result = gari.chromosome2img(solution, target_im.shape)
137+
matplotlib.pyplot.imshow(result)
138+
matplotlib.pyplot.title("PyGAD & GARI for Reproducing Images")
139+
matplotlib.pyplot.show()
140+
```
141+
142+
# Evolution by Generation
143+
144+
The solution reached after the 20,000 generations is shown below.
145+
146+
![solution](https://user-images.githubusercontent.com/16560492/82232405-e0f63a80-992e-11ea-984f-b6ed76465bd1.png)
147+
148+
After more generations, the result can be enhanced like what shown below.
149+
150+
![solution](https://user-images.githubusercontent.com/16560492/82232345-cf149780-992e-11ea-8390-bf1a57a19de7.png)
151+
152+
The results can also be enhanced by changing the parameters passed to the constructor of the `pygad.GA` class.
153+
154+
Here is an example of input image and how it is evolved after some iterations.
155+
156+
<h1>Generation 0</h1>
157+
158+
![solution_0](https://user-images.githubusercontent.com/16560492/36948589-b47276f0-1fe5-11e8-8efe-0cd1a225ea3a.png)
159+
160+
<h1>Generation 1,000</h1>
161+
162+
![solution_1000](https://user-images.githubusercontent.com/16560492/36948823-16f490ee-1fe9-11e8-97db-3e8905ad5440.png)
163+
164+
<h1>Generation 2,500</h1>
165+
166+
![solution_2500](https://user-images.githubusercontent.com/16560492/36948832-3f314b60-1fe9-11e8-8f4a-4d9a53b99f3d.png)
167+
168+
<h1>Generation 4,500</h1>
169+
170+
![solution_4500](https://user-images.githubusercontent.com/16560492/36948837-53d1849a-1fe9-11e8-9b36-e9e9291e347b.png)
171+
172+
<h1>Generation 7,000</h1>
173+
174+
![solution_7000](https://user-images.githubusercontent.com/16560492/36948852-66f1b176-1fe9-11e8-9f9b-460804e94004.png)
175+
176+
<h1>Generation 8,500</h1>
177+
178+
![solution_8500](https://user-images.githubusercontent.com/16560492/36948865-7fbb5158-1fe9-11e8-8c04-8ac3c1f7b1b1.png)
179+
180+
<h1>Generation 20,000</h1>
181+
182+
![solution](https://user-images.githubusercontent.com/16560492/82232405-e0f63a80-992e-11ea-984f-b6ed76465bd1.png)
183+
184+
# For More Information
185+
186+
There are different resources that can be used to get started with the building CNN and its Python implementation.
187+
188+
## Tutorial: Reproduce Images with Genetic Algorithm
189+
190+
In 1 May 2019, I wrote a tutorial discussing this project. The tutorial is titled [**Reproducing Images using a Genetic Algorithm with Python**](https://www.linkedin.com/pulse/reproducing-images-using-genetic-algorithm-python-ahmed-gad) which is published at Heartbeat. Check it at these links:
191+
192+
- [Heartbeat](https://heartbeat.fritz.ai/reproducing-images-using-a-genetic-algorithm-with-python-91fc701ff84): https://heartbeat.fritz.ai/reproducing-images-using-a-genetic-algorithm-with-python-91fc701ff84
193+
- [LinkedIn](https://www.linkedin.com/pulse/reproducing-images-using-genetic-algorithm-python-ahmed-gad): https://www.linkedin.com/pulse/reproducing-images-using-genetic-algorithm-python-ahmed-gad
194+
195+
[![Tutorial Cover Image](https://miro.medium.com/max/2560/1*47K2h_Zz6SQVMHW2NL-WsQ.jpeg)](https://heartbeat.fritz.ai/reproducing-images-using-a-genetic-algorithm-with-python-91fc701ff84)
196+
197+
## Book: Practical Computer Vision Applications Using Deep Learning with CNNs
198+
199+
You can also check my book cited as [**Ahmed Fawzy Gad 'Practical Computer Vision Applications Using Deep Learning with CNNs'. Dec. 2018, Apress, 978-1-4842-4167-7**](https://www.amazon.com/Practical-Computer-Vision-Applications-Learning/dp/1484241665) which discusses neural networks, convolutional neural networks, deep learning, genetic algorithm, and more.
200+
201+
Find the book at these links:
202+
203+
- [Amazon](https://www.amazon.com/Practical-Computer-Vision-Applications-Learning/dp/1484241665)
204+
- [Springer](https://link.springer.com/book/10.1007/978-1-4842-4167-7)
205+
- [Apress](https://www.apress.com/gp/book/9781484241660)
206+
- [O'Reilly](https://www.oreilly.com/library/view/practical-computer-vision/9781484241677)
207+
- [Google Books](https://books.google.com.eg/books?id=xLd9DwAAQBAJ)
208+
209+
![Fig04](https://user-images.githubusercontent.com/16560492/78830077-ae7c2800-79e7-11ea-980b-53b6bd879eeb.jpg)
210+
211+
# Contact Us
212+
213+
214+
* [LinkedIn](https://www.linkedin.com/in/ahmedfgad)
215+
* [Amazon Author Page](https://amazon.com/author/ahmedgad)
216+
* [Heartbeat](https://heartbeat.fritz.ai/@ahmedfgad)
217+
* [Paperspace](https://blog.paperspace.com/author/ahmed)
218+
* [KDnuggets](https://kdnuggets.com/author/ahmed-gad)
219+
* [TowardsDataScience](https://towardsdatascience.com/@ahmedfgad)
220+
* [GitHub](https://github.com/ahmedfgad)

example.py

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import numpy
2+
import imageio
3+
import gari
4+
import pygad
5+
import matplotlib.pyplot
6+
7+
"""
8+
GARI (Genetic Algorithm for Reproducing Images) is a Python project that uses the PyGAD library for reproducing images using the genetic algorithm. GARI reproduces a single image using Genetic Algorithm (GA) by evolving pixel values.
9+
10+
For implementing the genetic algorithm, the PyGAD library is used. Check its documentation here: https://pygad.readthedocs.io
11+
12+
This project works with both color and gray images without any modifications.
13+
14+
This project is implemented using Python 3.5 by Ahmed Fawzy Gad.
15+
Contact info:
16+
17+
https://www.linkedin.com/in/ahmedfgad/
18+
"""
19+
20+
# Reading target image to be reproduced using Genetic Algorithm (GA).
21+
target_im = imageio.imread('fruit.jpg')
22+
target_im = numpy.asarray(target_im/255, dtype=numpy.float)
23+
24+
# Target image after enconding. Value encoding is used.
25+
target_chromosome = gari.img2chromosome(target_im)
26+
27+
def fitness_fun(solution, solution_idx):
28+
"""
29+
Calculating the fitness value for a solution in the population.
30+
The fitness value is calculated using the sum of absolute difference between genes values in the original and reproduced chromosomes.
31+
32+
solution: Current solution in the population to calculate its fitness.
33+
solution_idx: Index of the solution within the population.
34+
"""
35+
36+
fitness = numpy.sum(numpy.abs(target_chromosome-solution))
37+
38+
# Negating the fitness value to make it increasing rather than decreasing.
39+
fitness = numpy.sum(target_chromosome) - fitness
40+
return fitness
41+
42+
def callback(ga_instance):
43+
print("Generation = {gen}".format(gen=ga_instance.generations_completed))
44+
print("Fitness = {fitness}".format(fitness=ga_instance.best_solution()[1]))
45+
46+
if ga_instance.generations_completed % 500 == 0:
47+
matplotlib.pyplot.imsave('solution_'+str(ga_instance.generations_completed)+'.png', gari.chromosome2img(ga_instance.best_solution()[0], target_im.shape))
48+
49+
ga_instance = pygad.GA(num_generations=20000,
50+
num_parents_mating=10,
51+
fitness_func=fitness_fun,
52+
sol_per_pop=20,
53+
num_genes=target_im.size,
54+
init_range_low=0.0,
55+
init_range_high=1.0,
56+
mutation_percent_genes=0.01,
57+
mutation_type="random",
58+
mutation_by_replacement=True,
59+
random_mutation_min_val=0.0,
60+
random_mutation_max_val=1.0,
61+
callback_generation=callback)
62+
63+
ga_instance.run()
64+
65+
# After the generations complete, some plots are showed that summarize the how the outputs/fitenss values evolve over generations.
66+
ga_instance.plot_result()
67+
68+
# Returning the details of the best solution.
69+
solution, solution_fitness, solution_idx = ga_instance.best_solution()
70+
print("Fitness value of the best solution = {solution_fitness}".format(solution_fitness=solution_fitness))
71+
print("Index of the best solution : {solution_idx}".format(solution_idx=solution_idx))
72+
73+
if ga_instance.best_solution_generation != -1:
74+
print("Best fitness value reached after {best_solution_generation} generations.".format(best_solution_generation=ga_instance.best_solution_generation))
75+
76+
result = gari.chromosome2img(solution, target_im.shape)
77+
matplotlib.pyplot.imshow(result)
78+
matplotlib.pyplot.title("PyGAD & GARI for Reproducing Images")
79+
matplotlib.pyplot.show()

gari.py

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import numpy
2+
import functools
3+
import operator
4+
5+
def img2chromosome(img_arr):
6+
"""
7+
Represents the image as a 1D vector.
8+
9+
img_arr: The image to be converted into a vector.
10+
11+
Returns the vector.
12+
"""
13+
14+
return numpy.reshape(a=img_arr, newshape=(functools.reduce(operator.mul, img_arr.shape)))
15+
16+
def chromosome2img(vector, shape):
17+
"""
18+
Converts a 1D vector into an array.
19+
20+
vector: The vector to be converted into an array.
21+
shape: The shape of the target array.
22+
23+
Returns the array.
24+
"""
25+
26+
# Check if the vector can be reshaped according to the specified shape.
27+
if len(vector) != functools.reduce(operator.mul, shape):
28+
raise ValueError("A vector of length {vector_length} into an array of shape {shape}.".format(vector_length=len(vector), shape=shape))
29+
30+
return numpy.reshape(a=vector, newshape=shape)

0 commit comments

Comments
 (0)