--- /dev/null
+[flake8]
+ignore = E203
+max-line-length = 88
--- /dev/null
+MIT License
+
+Copyright (c) 2022 Georgios Atheridis
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
--- /dev/null
+<h1 align="center">Mandelbrot Image Renderer</h1>
+
+<p align="center">
+ <img width="600"
+ alt="Mandelbrot Image Renderer"
+ src="https://imgur.com/M4IIXNp.png">
+</p>
+
+## Installation
+
+To install the latest version just type `$ pip install git+https://github.com/atheridis/mandelbrot-python.git`
+in your terminal. The program has a bunch of different options, type `$ mandelbrot --help`
+to see all of the options.
+
+You may also clone this repository and install it from there.
+```
+$ git clone https://github.com/atheridis/mandelbrot-python.git
+$ cd mandelbrot-python
+$ pip install .
+```
+
+## How to use
+
+Just by typing `$ mandelbrot` will create an 1080p image of the mandelbrot set inside
+the directory you are currently in. You also have a number of options to choose from.
+
+* `$ mandelbrot -r 1440` will make the image have a width of 1440 pixels.
+* `$ mandelbrot --scale 1` will make the image a square. The default is 16/9
+* `$ mandelbrot -s 100` The depth which each point will check wether it is in the set or not.
+* `$ mandelbrot -c -0.745428 0.113009 -l 0.0001` Will center at x=-0.745428 y=0.113009, with the x axis having a total length of 0.0001
+* `$ mandelbrot -r 480 -v -f 350 -z 0.9` Will produce a video of resolution 480p, containing 350 frames (at 24fps) and each frame will reduce the x axis length to 0.9 times the previous. Since this code is running on Python, it is quite slow. A lower quality video is advised.
+
+
+## OLD PROJECT
+
+This is one of many of my older projects which I have decided to turn it into a package and upload it to github.
+
+++ /dev/null
-from numba import njit, prange
-import numpy as np
-from PIL import Image
-import cv2
-import os
-import time
-import colorsys
-
-
-def hsv2rgb(h,s,v):
- return list(round(i * 255) for i in colorsys.hsv_to_rgb(h,s,v))
-
-def colour(n):
- if n:
- hue = n/100
- sat = 1
- value = 1
- return hsv2rgb(hue, sat, value)
- return 0
-
-@njit(parallel=True, fastmath=True)
-def mandelbrot(c, steps):
- z = c
- for n in prange(steps):
- if z.real * z.real + z.imag * z.imag > 4:
- return n
- z = z*z + c
- return 0
-
-@njit(parallel=True, fastmath=True)
-def mandelbrot_set(xmin, xmax, ymin, ymax, width, height, steps):
- x = np.linspace(xmin, xmax, width)
- y = np.linspace(ymin, ymax, height)
- z = np.empty((width,height))
-
- for i in prange(width):
- for j in prange(height):
- z[i,j] = mandelbrot(x[i] + 1j*y[j], steps)
-
- return z
-
-# settings
-res = 1080 # height
-scale = 16/9 # width / height
-steps = 50 # search depth
-
-# render video
-video = False
-max_frames = 480
-z_speed = 0.9 # zoom speed
-
-
-center = np.array([0, 0]) # center coordinates
-x_length = 4 # length of x axis
-
-
-##############################################
-# NOTHING TO EDIT BELOW THIS line
-##############################################
-axis_length = (x_length, x_length/scale)
-
-re_axis = (center[0] - axis_length[0] / 2,
- center[0] + axis_length[0] / 2)
-
-im_axis = (center[1] - axis_length[1] / 2,
- center[1] + axis_length[1] / 2)
-
-resolution = (int(scale*res), int(res))
-
-
-if video:
- out = cv2.VideoWriter(f'Mandel0_{time.time()}.avi',
- cv2.VideoWriter_fourcc(*'DIV4'),
- 24, resolution)
-
-frame = 1
-while True:
- if video:
- print(f"On frame {frame} out of {max_frames}")
-
- c = mandelbrot_set(re_axis[0], re_axis[1], im_axis[0], im_axis[1], resolution[0], resolution[1], steps)
-
-
- data = np.zeros((resolution[1], resolution[0], 3), dtype=np.uint8)
-
-
- for row in range(resolution[1]):
- if not video:
- print(f"On row {row} out of {resolution[1]}")
- for col in range(resolution[0]):
- data[row,col] = colour(c[col,row])
-
- image = Image.fromarray(data)
-
- if not video:
- image.save(f"i_{center[0]}+{center[1]}i_{steps}_{axis_length[0]}.png")
-
- if video:
- image.save("screen.png")
- img = cv2.imread("screen.png")
- os.remove("screen.png")
- out.write(img)
-
- axis_length = (z_speed * axis_length[0],
- z_speed * axis_length[1])
-
- re_axis = (center[0] - axis_length[0] / 2,
- center[0] + axis_length[0] / 2)
- im_axis = (center[1] - axis_length[1] / 2,
- center[1] + axis_length[1] / 2)
-
- frame += 1
-
- if frame > max_frames or not video:
- break
-
-if video:
- out.release()
--- /dev/null
+import argparse
+
+
+def parse_arguments():
+ arg_parser = argparse.ArgumentParser(
+ prog="yorugo-mandelbrot",
+ description="Generates the mandelbrot set",
+ )
+
+ arg_parser.add_argument(
+ "-r",
+ "--resolution",
+ type=int,
+ default=1080,
+ help="Set the height of the image or video in pixels. Default: 1080",
+ )
+ arg_parser.add_argument(
+ "--scale",
+ type=float,
+ default=16 / 9,
+ help="The scale of the image. Width / Height. Default: 16 / 9",
+ )
+ arg_parser.add_argument(
+ "-s",
+ "--steps",
+ type=int,
+ default=50,
+ help="The search depth for the mandelbrot set. Default: 50",
+ )
+
+ arg_parser.add_argument(
+ "-v",
+ "--video",
+ type=bool,
+ action=argparse.BooleanOptionalAction,
+ default=False,
+ help="Render a video instead of an image.",
+ )
+ arg_parser.add_argument(
+ "-f",
+ "--frames",
+ type=int,
+ default=500,
+ help="The number of frames to be rendered into the video. Default: 500",
+ )
+ arg_parser.add_argument(
+ "-z",
+ "--zoom-speed",
+ type=float,
+ default=0.9,
+ help="Zoom speed. Default: 0.9",
+ )
+
+ arg_parser.add_argument(
+ "-c",
+ "--center",
+ type=float,
+ nargs=2,
+ default=(0, 0),
+ help="Center coordinates. Default 0 0",
+ )
+ arg_parser.add_argument(
+ "-l",
+ "--length",
+ type=float,
+ default=4,
+ help="Length of X axis. Default 4",
+ )
+
+ return arg_parser.parse_args()
--- /dev/null
+from .args import parse_arguments
+from .mandelbrot import compute
+
+
+def main():
+ argsv = parse_arguments()
+ compute(
+ argsv.resolution,
+ argsv.scale,
+ argsv.steps,
+ argsv.video,
+ argsv.frames,
+ argsv.zoom_speed,
+ argsv.center,
+ argsv.length,
+ )
+
+
+if __name__ == "__main__":
+ main()
--- /dev/null
+from numba import jit, prange\r
+import numpy as np\r
+from PIL import Image\r
+import cv2\r
+import os\r
+import time\r
+import colorsys\r
+\r
+\r
+def hsv2rgb(h, s, v):\r
+ return list(round(i * 255) for i in colorsys.hsv_to_rgb(h, s, v))\r
+\r
+\r
+def colour(n):\r
+ if n:\r
+ hue = n / 100\r
+ sat = 1\r
+ value = 1\r
+ return hsv2rgb(hue, sat, value)\r
+ return 0\r
+\r
+\r
+@jit\r
+def mandelbrot(c, steps):\r
+ z = c\r
+ for n in prange(steps):\r
+ if z.real * z.real + z.imag * z.imag > 4:\r
+ return n\r
+ z = z * z + c\r
+ return 0\r
+\r
+\r
+@jit\r
+def mandelbrot_set(xmin, xmax, ymin, ymax, width, height, steps):\r
+ x = np.linspace(xmin, xmax, width)\r
+ y = np.linspace(ymin, ymax, height)\r
+ z = np.empty((width, height))\r
+\r
+ for i in prange(width):\r
+ for k in prange(height):\r
+ # Reverse row, since computer images start from (0, 0) on the top left\r
+ z[i, k] = mandelbrot(x[i] + 1j * y[height - (k + 1)], steps)\r
+\r
+ return z\r
+\r
+\r
+def compute(res, scale, steps, video, max_frames, z_speed, center, x_length):\r
+ axis_length = (x_length, x_length / scale)\r
+\r
+ re_axis = (center[0] - axis_length[0] / 2, center[0] + axis_length[0] / 2)\r
+\r
+ im_axis = (center[1] - axis_length[1] / 2, center[1] + axis_length[1] / 2)\r
+\r
+ resolution = (int(scale * res), int(res))\r
+\r
+ if video:\r
+ out = cv2.VideoWriter(\r
+ f"Mandel0_{time.time()}.avi",\r
+ cv2.VideoWriter_fourcc(*"DIV4"),\r
+ 24,\r
+ resolution,\r
+ )\r
+\r
+ frame = 1\r
+ while True:\r
+ if video:\r
+ print(f"On frame {frame} out of {max_frames}")\r
+\r
+ c = mandelbrot_set(\r
+ re_axis[0],\r
+ re_axis[1],\r
+ im_axis[0],\r
+ im_axis[1],\r
+ resolution[0],\r
+ resolution[1],\r
+ steps,\r
+ )\r
+\r
+ data = np.zeros((resolution[1], resolution[0], 3), dtype=np.uint8)\r
+\r
+ for row in range(resolution[1]):\r
+ if not video:\r
+ print(f"On row {row} out of {resolution[1]}")\r
+ for col in range(resolution[0]):\r
+ data[row, col] = colour(c[col, row])\r
+\r
+ image = Image.fromarray(data)\r
+\r
+ if not video:\r
+ image.save(f"i_{center[0]}+{center[1]}i_{steps}_{axis_length[0]}.png")\r
+\r
+ if video:\r
+ image.save("screen.png")\r
+ img = cv2.imread("screen.png")\r
+ os.remove("screen.png")\r
+ out.write(img)\r
+\r
+ axis_length = (z_speed * axis_length[0], z_speed * axis_length[1])\r
+\r
+ re_axis = (center[0] - axis_length[0] / 2, center[0] + axis_length[0] / 2)\r
+ im_axis = (center[1] - axis_length[1] / 2, center[1] + axis_length[1] / 2)\r
+\r
+ frame += 1\r
+\r
+ if frame > max_frames or not video:\r
+ break\r
+\r
+ if video:\r
+ out.release()\r
-llvmlite==0.35.0
-numba==0.52.0
-numpy==1.19.4
-opencv-python==4.4.0.46
-Pillow==8.0.1
+black==22.6.0
+click==8.1.3
+flake8==4.0.1
+llvmlite==0.38.1
+mccabe==0.6.1
+mypy-extensions==0.4.3
+numba==0.55.2
+numpy==1.22.4
+opencv-python==4.6.0.66
+pathspec==0.9.0
+Pillow==9.2.0
+platformdirs==2.5.2
+pycodestyle==2.8.0
+pyflakes==2.4.0
+tomli==2.0.1
--- /dev/null
+from setuptools import setup, find_packages
+
+setup(
+ name="mandelbrot",
+ version="0.0.1",
+ author="Georgios Atheridis",
+ author_email="atheridis@tutamail.com",
+ packages=find_packages(),
+ entry_points={
+ "console_scripts": [
+ "mandelbrot=mandelbrot.main:main",
+ ],
+ },
+ install_requires=[
+ "numba",
+ "Pillow",
+ "numpy",
+ "opencv-python",
+ ],
+)