Skip to content

Commit

Permalink
Add Mona Lisa example
Browse files Browse the repository at this point in the history
  • Loading branch information
Vincent Riva committed Mar 30, 2019
1 parent 8c014f9 commit b186aa6
Show file tree
Hide file tree
Showing 12 changed files with 238 additions and 0 deletions.
Empty file added docs/mona/assets/.gitkeep
Empty file.
Binary file added docs/mona/assets/mona.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions docs/mona/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Project</title>
</head>

<body>
<script type="text/javascript" src="main.min.js?5f8809b705534f2937d1"></script></body>

</html>
1 change: 1 addition & 0 deletions docs/mona/main.min.js

Large diffs are not rendered by default.

45 changes: 45 additions & 0 deletions docs/mona/src/app/js/core/Canvas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Promise } from 'bluebird';

class Canvas {
public readonly width: number;
public readonly height: number;
private canvas: HTMLCanvasElement;
public readonly context: CanvasRenderingContext2D;
private image: HTMLImageElement;
constructor(width: number, height: number) {
this.width = width;
this.height = height;
this.canvas = document.createElement('canvas');
this.canvas.width = width;
this.canvas.height = height;
this.context = this.canvas.getContext('2d');
document.body.appendChild(this.canvas);
}

init(imageURI: string) {
return new Promise(resolve => {
const image = new Image();
image.addEventListener('load', () => {
this.image = image;
this.context.drawImage(image, 0, 0, this.width / 2, this.height);
resolve();
});
image.src = imageURI;
});
}

clear() {
this.context.clearRect(0, 0, this.width, this.height);
if (this.image) {
this.context.drawImage(this.image, 0, 0, this.width / 2, this.height);
}
}

showImage() {
if (this.image) {
this.context.drawImage(this.image, 0, 0, this.width / 2, this.height);
}
}
}

export default new Canvas(1000, 1000);
37 changes: 37 additions & 0 deletions docs/mona/src/app/js/core/Color.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
export default class Color {
public r: number;
public g: number;
public b: number;
public a: number;

constructor(r: number, g: number, b: number, a: number) {
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}

static random(): Color {
const r = this.rand(0, 255);
const g = this.rand(0, 255);
const b = this.rand(0, 255);
const a = Math.random();
return new Color(r, g, b, a);
}

static rand(min: number, max: number) {
return Math.floor(Math.random() * (max - min)) + min;
}

toRGBA() {
return `rgba(${this.r}, ${this.g}, ${this.b}, ${this.a})`;
}

difference(color: Color) {
const dR = Math.abs(this.r - color.r) / 255;
const dG = Math.abs(this.g - color.g) / 255;
const dB = Math.abs(this.b - color.b) / 255;
const dA = Math.abs(this.a - color.a);
return ((dR + dG + dB + dA) * 100) / 4;
}
}
105 changes: 105 additions & 0 deletions docs/mona/src/app/js/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import App from './utils/App';
// @ts-ignore
import { Population, Blueprint, Gene, Chromosome, GenomeEvent, GenomeEventType } from 'genome.js';
import Canvas from './core/Canvas';
import Color from './core/Color';

const app = new App();

// @ts-ignore
app.isReady().then(async () => {
await Canvas.init('./assets/mona.jpg');

const blueprint = new Blueprint();
blueprint.addConstant(Canvas.width / 2);
blueprint.addConstant(Canvas.height);
blueprint.add(20);
blueprint.add(256, 3);

const population = new Population(3000, blueprint);

population.setMutationRate(0.02);
population.setCutOff(0.5);

population.setFitnessCalculation((genes: Gene[], constants: Gene[]) => {
let fitness = 1;
const x = Math.floor(constants[0].get());
const y = Math.floor(constants[1].get());
const radius = Math.floor(genes[0].get()) + 1;
const r = Math.floor(genes[1].get());
const g = Math.floor(genes[2].get());
const b = Math.floor(genes[3].get());
// console.log(x - radius, y - radius, x + radius, y + radius);
// console.log(Canvas.width / 2, Canvas.height);

const pixels = Canvas.context.getImageData(x - radius, y - radius, radius * 2, radius * 2).data;
const color = new Color(r, g, b, 255);

for (let i = 0; i < pixels.length; i += 4) {
const pixelColor = new Color(pixels[i + 0], pixels[i + 1], pixels[i + 2], pixels[i + 3]);
if (color.difference(pixelColor) <= 5) {
fitness += 1;
}
}
return fitness;
});
GenomeEvent.on(GenomeEventType.GENOME_EVENT_POPULATION_CREATED, (chromosomes: Chromosome[]) => {
chromosomes.map((chromosome: Chromosome) => {
console.log(chromosome.getGenes()[0].get());
});
});

GenomeEvent.on(GenomeEventType.GENOME_EVENT_GENERATION_BEGIN, (chromosomes: Chromosome[]) => {
const bestChromosome = chromosomes[0];
Canvas.clear();

chromosomes.map((chromosome: Chromosome) => {
const genes = chromosome.getGenes();
const constants = chromosome.getConstants();
const x = Math.floor(constants[0].get());
const y = Math.floor(constants[1].get());
const radius = Math.floor(genes[0].get()) + 1;
const r = Math.floor(genes[1].get());
const g = Math.floor(genes[2].get());
const b = Math.floor(genes[3].get());

Canvas.context.beginPath();
Canvas.context.fillStyle = `rgba(${r}, ${g}, ${b}, 1)`;
Canvas.context.arc(x + Canvas.width / 2, y, radius, 0, Math.PI * 2, true);
Canvas.context.fill();
});
Canvas.showImage();
console.log(`Generation ${population.getGenerationNumber()} : ${bestChromosome.getFitness()}`);
});

GenomeEvent.on(GenomeEventType.GENOME_EVENT_GENERATION_FINISH, (chromosomes: Chromosome[]) => {
const bestChromosome = chromosomes[0];

const pixelsOriginal = Canvas.context.getImageData(0, 0, Canvas.width / 2, Canvas.height).data;
const pixelsGenetic = Canvas.context.getImageData(Canvas.width / 2, 0, Canvas.width, Canvas.height).data;

let sumCorrectPixels = 0;
for (let i = 0; i < pixelsOriginal.length; i += 4) {
const pixelOriginal = new Color(
pixelsOriginal[i + 0],
pixelsOriginal[i + 1],
pixelsOriginal[i + 2],
pixelsOriginal[i + 3],
);
const pixelGenetic = new Color(
pixelsGenetic[i + 0],
pixelsGenetic[i + 1],
pixelsGenetic[i + 2],
pixelsGenetic[i + 3],
);

if (pixelOriginal.difference(pixelGenetic) <= 5) {
sumCorrectPixels += 1;
}
}

console.log(`Percentage: ${(sumCorrectPixels * 100) / ((Canvas.width / 2) * Canvas.height)}%`);
});

population.run(100);
});
12 changes: 12 additions & 0 deletions docs/mona/src/app/js/utils/App.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import '../../scss/app.scss';
import * as Promise from 'bluebird';

export default class App {
isReady() {
return new Promise((resolve, reject) => {
document.addEventListener('readystatechange', () => {
if (document.readyState === 'complete') resolve();
});
});
}
}
10 changes: 10 additions & 0 deletions docs/mona/src/app/scss/app.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}

canvas {
height: 100%;
width: 100%;
}
Empty file.
Binary file added docs/mona/src/app/static/mona.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions docs/mona/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Project</title>
</head>

<body>
</body>

</html>

0 comments on commit b186aa6

Please sign in to comment.