├── images ├── screenshot1.jpg ├── screenshot2.jpg ├── screenshot3.jpg └── screenshot4.jpg ├── CMakeLists.txt ├── .gitignore ├── README.md └── chaos-game.cpp /images/screenshot1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaybosamiya/chaos-game/HEAD/images/screenshot1.jpg -------------------------------------------------------------------------------- /images/screenshot2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaybosamiya/chaos-game/HEAD/images/screenshot2.jpg -------------------------------------------------------------------------------- /images/screenshot3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaybosamiya/chaos-game/HEAD/images/screenshot3.jpg -------------------------------------------------------------------------------- /images/screenshot4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaybosamiya/chaos-game/HEAD/images/screenshot4.jpg -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | project( chaos-game ) 3 | find_package( OpenCV REQUIRED ) 4 | add_executable( chaos-game chaos-game ) 5 | target_link_libraries( chaos-game ${OpenCV_LIBS} ) 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### CMake ### 2 | CMakeCache.txt 3 | CMakeFiles 4 | CMakeScripts 5 | Makefile 6 | cmake_install.cmake 7 | install_manifest.txt 8 | 9 | build/ 10 | 11 | ### Linux ### 12 | *~ 13 | 14 | # temporary files which can be created if a process still has a handle open of a deleted file 15 | .fuse_hidden* 16 | 17 | # KDE directory preferences 18 | .directory 19 | 20 | # Linux trash folder which might appear on any partition or disk 21 | .Trash-* 22 | 23 | 24 | ### C++ ### 25 | # Compiled Object files 26 | *.slo 27 | *.lo 28 | *.o 29 | *.obj 30 | 31 | # Precompiled Headers 32 | *.gch 33 | *.pch 34 | 35 | # Compiled Dynamic libraries 36 | *.so 37 | *.dylib 38 | *.dll 39 | 40 | # Fortran module files 41 | *.mod 42 | 43 | # Compiled Static libraries 44 | *.lai 45 | *.la 46 | *.a 47 | *.lib 48 | 49 | # Executables 50 | *.exe 51 | *.out 52 | *.app 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Chaos Game 2 | ========== 3 | 4 | > Play the chaos game to create awesome fractal images 5 | 6 | Screenshots 7 | ----------- 8 | 9 | ![](images/screenshot1.jpg) 10 | 11 | ![](images/screenshot2.jpg) 12 | 13 | ![](images/screenshot3.jpg) 14 | 15 | ![](images/screenshot4.jpg) 16 | 17 | Video Demo 18 | ---------- 19 | 20 | It has come to my notice that Yu-Jie Lin has made a nice video showing the features of this program, which can be seen on youtube [here](https://www.youtube.com/watch?v=9gt72c9ni5w). 21 | 22 | How it works 23 | ------------ 24 | 25 | The tool takes takes multiple points as input from the user. Then, it assigns the centroid of these points as the initial point. Then, it iterates moving towards a random point, moving in a ratio of `r` taken as input. 26 | 27 | Usage 28 | ----- 29 | 30 | ```bash 31 | ./chaos-game 32 | ``` 33 | 34 | + Left Click: Add new point 35 | + Right Click: Define starting point 36 | + Keypress x: Delete latest point 37 | + Keypress f: Run the chaos game 38 | + Keypress c: Toggle colouring 39 | + Keypress q: Quit 40 | 41 | 42 | Build process 43 | ------------- 44 | 45 | ```bash 46 | mkdir build 47 | cd build 48 | cmake .. 49 | make 50 | ``` 51 | 52 | Requirements 53 | ------------ 54 | 55 | + OpenCV 2.x 56 | + CMake 2.8 or above 57 | 58 | License 59 | ------- 60 | 61 | This software is licensed under the [MIT License](http://jay.mit-license.org/2016) 62 | -------------------------------------------------------------------------------- /chaos-game.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace cv; 9 | using namespace std; 10 | 11 | const char * window_name = "Chaos game (c) Jay Bosamiya"; 12 | int max_iterations = (int)1e5; 13 | int display_every = (int)1e2; 14 | 15 | vector point_set; 16 | Point centre; 17 | int r100 = 50; 18 | bool colouring_on = true; 19 | 20 | void display_fractal(); 21 | void display_points(); 22 | void recalculate_centre(); 23 | 24 | void delete_point() { 25 | if ( point_set.size() >= 1 ) { 26 | point_set.pop_back(); 27 | } 28 | recalculate_centre(); 29 | display_points(); 30 | } 31 | 32 | void recalculate_centre() { 33 | centre = Point(0,0); 34 | for ( vector::iterator it = point_set.begin() ; it != point_set.end() ; it++ ) { 35 | centre += *it; 36 | } 37 | centre = centre * (1.0/point_set.size()); 38 | } 39 | 40 | void waiter(int delay = 0) { 41 | start_of_waiter: 42 | char c = waitKey(delay); 43 | switch (c) { 44 | case 'f': 45 | display_fractal(); 46 | break; 47 | case 'c': 48 | colouring_on = !colouring_on; 49 | display_fractal(); 50 | break; 51 | case 'q': 52 | exit(0); 53 | break; 54 | case 'x': 55 | delete_point(); 56 | break; 57 | default: 58 | if (delay == 0) { 59 | goto start_of_waiter; 60 | } 61 | break; 62 | } 63 | } 64 | 65 | void create_fractal(Mat &img, Point p) { 66 | if ( point_set.size() < 1 ) { 67 | return; 68 | } 69 | 70 | if ( display_every < 1 ) { 71 | display_every = 1; 72 | } 73 | 74 | RNG rng; 75 | double r = r100 / 100.0; 76 | 77 | vector colour_palette; 78 | colour_palette.push_back(Vec3b(173, 35, 35)); 79 | colour_palette.push_back(Vec3b(42, 75, 215 )); 80 | colour_palette.push_back(Vec3b(29, 105, 20 )); 81 | colour_palette.push_back(Vec3b(129, 74, 25 )); 82 | colour_palette.push_back(Vec3b(129, 38, 192 )); 83 | colour_palette.push_back(Vec3b(160, 160, 160 )); 84 | colour_palette.push_back(Vec3b(129, 197, 122 )); 85 | colour_palette.push_back(Vec3b(157, 175, 255 )); 86 | colour_palette.push_back(Vec3b(41, 208, 208 )); 87 | colour_palette.push_back(Vec3b(255, 146, 51 )); 88 | colour_palette.push_back(Vec3b(255, 238, 51 )); 89 | colour_palette.push_back(Vec3b(233, 222, 187 )); 90 | colour_palette.push_back(Vec3b(255, 205, 243 )); 91 | 92 | for ( int i = 0 ; i < max_iterations ; i++ ) { 93 | int selection = rng.uniform(0, point_set.size()); 94 | Point towards = point_set[selection]; 95 | p = r*p + (1-r)*towards; 96 | 97 | if ( colouring_on && selection < colour_palette.size() ) { 98 | img.at(p)[0] = colour_palette[selection][0]; 99 | img.at(p)[1] = colour_palette[selection][1]; 100 | img.at(p)[2] = colour_palette[selection][2]; 101 | } else { 102 | img.at(p)[0] = 255; 103 | img.at(p)[1] = 255; 104 | img.at(p)[2] = 255; 105 | } 106 | 107 | if ( i % display_every == 0 ) { 108 | imshow(window_name, img); 109 | waiter(1); 110 | } 111 | } 112 | } 113 | 114 | void display_fractal() { 115 | Mat display_image(600, 600, CV_8UC3, Scalar(0,0,0)); 116 | 117 | if ( point_set.size() < 1 ) { 118 | waiter(); 119 | return; 120 | } 121 | 122 | create_fractal(display_image, centre); 123 | 124 | waiter(); 125 | } 126 | 127 | void display_points() { 128 | Mat display_image(600, 600, CV_8UC3, Scalar(0,0,0)); 129 | 130 | for ( vector::iterator it = point_set.begin() ; it != point_set.end() ; it++ ) { 131 | circle(display_image, *it, 5, Scalar(255,255,255), -1, 8); 132 | } 133 | if ( point_set.size() >= 1 ) { 134 | circle(display_image, centre, 5, Scalar(0,255,0), -1, 8); 135 | circle(display_image, *(point_set.rbegin()), 5, Scalar(0,0,255), -1, 8); 136 | } 137 | 138 | imshow(window_name, display_image); 139 | waiter(); 140 | } 141 | 142 | void on_mouse(int event, int x, int y, int, void*) { 143 | if( event == EVENT_LBUTTONDOWN ) { 144 | point_set.push_back(Point(x, y)); 145 | recalculate_centre(); 146 | display_points(); 147 | } else if ( event == EVENT_RBUTTONDOWN ) { 148 | centre = Point(x, y); 149 | display_points(); 150 | } 151 | } 152 | 153 | int main( int argc, char** argv ) { 154 | namedWindow(window_name, CV_WINDOW_AUTOSIZE); 155 | 156 | cout << "Usage:\n" 157 | "\tLeft Click: Add new point\n" 158 | "\tRight Click: Define starting point\n" 159 | "\tKeypress x: Delete latest point\n" 160 | "\tKeypress f: Run the chaos game\n" 161 | "\tKeypress c: Toggle colouring\n" 162 | "\tKeypress q: Quit\n"; 163 | 164 | setMouseCallback(window_name, on_mouse); 165 | createTrackbar("r*100: ", window_name, &r100, 100, NULL); 166 | createTrackbar("Draw speed: ", window_name, &display_every, 100, NULL); 167 | display_points(); 168 | 169 | return 0; 170 | } 171 | --------------------------------------------------------------------------------