Skip to content

Instantly share code, notes, and snippets.

@empet
Last active December 16, 2023 11:15
Show Gist options
  • Save empet/a191261d6cc78f03c9259e8416fb0bcb to your computer and use it in GitHub Desktop.
Save empet/a191261d6cc78f03c9259e8416fb0bcb to your computer and use it in GitHub Desktop.
Using an image as orbit trap for plotting a Julia set ¶
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"id": "04424857",
"metadata": {},
"source": [
"## <center> Using an image as orbit trap for plotting a Julia set </center>"
]
},
{
"cell_type": "markdown",
"id": "05288571",
"metadata": {},
"source": [
"[Orbit trap](https://en.wikipedia.org/wiki/Orbit_trap) is a method to plot a [Julia set](https://en.wikipedia.org/wiki/Julia_set). Here is implemented an algorithm for orbit trap defined by a raster image (bitmap). It works as follows:\n",
"\n",
"The Julia fractal is included in a rectangular region, `[A, B] x [C,D]`, from the complex plane. \n",
"Over this rectangle is defined a meshgrid of resolution `Nrow x Ncol`. The trapping set is\n",
"another rectangle, `[a,b] x [c,d]`, included in or overlapping the first one, chosen by user through experimentation. On the latter rectangle, theoretically is defined a meshgrid of the same resolution as the image resolution, to ensure a one-to-one correspondence between the points of the meshgrid and the image pixels.\n",
" \n",
"For each meshgrid point $z$ in the fractal rectangle one computes the iterates, $f^n(z)$, and tests are performed to detect escape from the disk, $D(0, 2)$, as for any Julia set, but it is also tested for each point of an orbit, whether it entered the trap (the rectangle `[a,b]x[c,d]`). If this is a case, and (i,j) are the indices of the nearest point/pixel in the trap, to the first trapped point, then the fractal image at the position of the orbit starting point is colored with that pixel color.\n",
"\n",
"This code works both for images with removed background (i.e. images with transparent background, RGBA(0,0,0,0)), as well as for general images.\n",
"\n",
"If the background is removed, and the orbit is in fact trapped, but the first orbit point in the trap corresponds to a transparent pixel (i.e. it is not a pixel on the shape represented by that image), it is considered as an untrapped point (see the function `istrapped`).\n",
"\n",
"Below the first Julia set has been generated using an image with transparent background, while the second one with its original background. "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "71187bfd",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "raw",
"id": "825cd6c7",
"metadata": {},
"source": [
"using Images, Interpolations\n",
"\n",
"function get_indices(z::Complex, nrow::Int, ncol::Int; \n",
" imgrectangle=(a=-0.25, b=0.7, c=-0.25, d=0.7))\n",
" a, b, c, d = imgrectangle\n",
" idxrow = floor(Int, 1.5+ (nrow-1)*(d-imag(z))/(d-c)) \n",
" idxcol = floor(Int, 1.5+ (ncol-1)*(real(z)-a)/(b-a))\n",
" return idxrow, idxcol\n",
"end \n",
"\n",
"function istrapped(img::Matrix{T}, i::Int, j::Int) where T\n",
" 1 <= i <=size(img, 1) && 1 <= j <= size(img, 2) && (img[i, j] != RGBA(0,0,0,0)) \n",
"end \n",
"\n",
"f(z::Complex; c=-0.8+0.156im)=z^2+c \n",
"\n",
"function iteratef(z::Complex, img::Matrix{T}; maxiter=512) where T\n",
" n=0\n",
" i, j = get_indices(z, size(img)...;)\n",
" while (n < maxiter && abs(z) < 2) && (n < 2 || !istrapped(img, i, j ))\n",
" z = f(z)\n",
" n += 1\n",
" i, j = get_indices(z, size(img)...;)\n",
" if istrapped(img, i, j)\n",
" return img[i, j]\n",
" end\n",
" end\n",
"end \n",
"\n",
"function Juliafractal(img::Matrix{T}; \n",
" fractrectangle=(xmin=-1.55, xmax=1.55, ymin=-1.4, ymax=1.4),\n",
" Nrow=1000, Ncol=1000, maxiter=1024,\n",
" bgcolor=RGB{N0f8}(1.0,1.0, 1.0)) where T\n",
" A, B, C, D = fractrectangle\n",
" frimg = fill(bgcolor, 1:Nrow, 1:Ncol)\n",
" for l in axes(frimg, 2)\n",
" for k in axes(frimg, 1)\n",
" z = Complex(A+(B-A)*(l-1)/(Ncol-1), D-(D-C)*(k-1)/(Nrow-1)) \n",
" vr = iteratef(z, img; maxiter=maxiter) \n",
" if vr != nothing\n",
" frimg[k, l] = vr\n",
" end \n",
" end\n",
" end\n",
" return interpolate(frimg, BSpline(Linear()), OnGrid())\n",
"end \n",
"\n",
"img = load(\"imgs/ai-younglady.png\") \n",
"fritp = Juliafractal(img; bgcolor=RGB{N0f8}(1,0.953,0.91))\n",
"save(\"img-trap-ai-lady.jpg\", fritp)"
]
},
{
"cell_type": "markdown",
"id": "580a7800",
"metadata": {},
"source": [
"%%html\n",
"<img src=\"https://github.com/empet/Datasets/blob/master/Images/img-trap-ylady.jpg?raw=true\">"
]
},
{
"cell_type": "markdown",
"id": "5ca4756a",
"metadata": {},
"source": [
"%%html\n",
"<img src=\"https://github.com/empet/Datasets/blob/master/Images/img-trap-yladybg.jpg?raw=true\">"
]
},
{
"cell_type": "markdown",
"id": "9dc04842",
"metadata": {},
"source": [
"$f(z)=z^2+0.272$:"
]
},
{
"cell_type": "markdown",
"id": "1ef74f36",
"metadata": {},
"source": [
"%%html\n",
"<img src=\"https://github.com/empet/Datasets/blob/master/Images/sunfl-deg2-m025-039.jpg?raw=true\">"
]
},
{
"cell_type": "markdown",
"id": "fe8895f6",
"metadata": {},
"source": [
"Julia set generated by a three degree map, $f(z)=z^3-0.505-0.32i$. The upper-right image is the orbit trap."
]
},
{
"cell_type": "markdown",
"id": "f026c5ae",
"metadata": {},
"source": [
"%%html\n",
"<img src=\"https://github.com/empet/Datasets/blob/master/Images/sunflower-deg3.png?raw=true\"> "
]
},
{
"cell_type": "markdown",
"id": "08909398",
"metadata": {},
"source": [
"Varying the area of the orbit trap:"
]
},
{
"cell_type": "markdown",
"id": "66db15c6",
"metadata": {},
"source": [
"%%html\n",
"<img src=\"https://github.com/empet/Datasets/blob/master/Images/sunflower-franimop.gif?raw=true\">"
]
},
{
"cell_type": "markdown",
"id": "fd5f4b13",
"metadata": {},
"source": [
"%%html\n",
"<img src=\"https://github.com/empet/Datasets/blob/master/Images/aiboy-franimop.gif?raw=true\">"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1a5a4c02",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"@webio": {
"lastCommId": null,
"lastKernelId": null
},
"kernelspec": {
"display_name": "Julia 1.9.0",
"language": "julia",
"name": "julia-1.9"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "1.9.0"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment