The Barnsley Fern
The implementation of the well-known fractal algorithm "Barnsley's Fern", which generates an image of a fern using a system of iterable functions, is considered.
Introduction
The Barnsley Fern algorithm is an example of using the Iterated Function System (IFS) to generate fractals. It was proposed by mathematician Michael Barnsley and allows you to create a realistic image of a fern leaf by applying simple affine transformations with a certain probability.
A fractal is constructed by repeatedly applying random affine transformations to a point on the plane. Each of the four transformations corresponds to a specific part of the plant (stem, left branch, right branch, and tip), and the probabilities of choosing these transformations determine the characteristic appearance of the fern.
This algorithm is widely used as an educational example in fractal theory and computer graphics due to its clarity and mathematical beauty.
# Установка необходимого пакета
import Pkg; Pkg.add("Images")
using Images
The main part
Defining the structure BarnsleyFern
mutable struct defines a mutable data structure in which all parameters and the current state of our fractal will be stored.
mutable struct BarnsleyFern
# размер изображения по ширине и высоте в пикселях
width::Int
height::Int
# цвет, которым будет рисоваться папоротник
color::RGB
# текущие координаты точки x и y
x::Float64
y::Float64
# двумерный массив (матрица) пикселей изображения
fern::Matrix{RGB}
# Конструктор структуры. Вызывается при создании нового объекта BarnsleyFern()
function BarnsleyFern(width, height, color = RGB(0.0, 1.0, 0.0), bgcolor = RGB(0.0, 0.0, 0.0))
# Создаём пустое изображение размером width на height,
# заполняя его фоновым цветом bgcolor
img = [bgcolor for x in 1:width, y in 1:height]
# Вычисляем начальные координаты центральной точки в пикселях:
# cx вычисляется с учётом диапазона значений x от -2.182 до 2.6558 (примерно 4.8378)
cx = Int(floor(2.182 * (width - 1) / 4.8378) + 1)
# cy вычисляется с учётом диапазона значений y от 0 до 9.9983
cy = Int(floor(9.9983 * (height - 1) / 9.9983) + 1)
# Устанавливаем первый пиксель в начальной точке
img[cx, cy] = color
# Создаём новый экземпляр структуры BarnsleyFern
# с указанными параметрами и инициализированной матрицей изображения
return new(width, height, color, 0.0, 0.0, img)
end
end
Structure BarnsleyFern It contains information about the size of the image, the current position of the point, the color of the rendering, and the pixel matrix itself. The constructor creates a black background rectangle and sets the starting point of the fern growth in the lower central area of the drawing area.
Defining a point transformation
A function that performs one iteration of the algorithm: selects one of the four affine transformations and applies it to the current coordinates of the point (f.x, f.y), then converts the new real coordinates to discrete pixel coordinates and colors the corresponding pixel in the image.
function transform(f::BarnsleyFern)
# Генерируем случайное число от 0 до 99 (включительно)
r = rand(0:99)
# В зависимости от значения r выбирается одно из 4 аффинных преобразований:
# Вероятности подобраны так, чтобы получился реалистичный вид папоротника:
# 1% — вертикальное сжатие (ствол)
# 85% — крупные листья сверху (главное преобразование)
# 7% — маленькие листья слева
# 7% — маленькие листья справа
if r < 1
# Превращение точки в корневую часть ствола
f.x = 0.0
f.y = 0.16 * f.y
elseif r < 86
# Главное преобразование: формирование основной массы листвы
f.x = 0.85 * f.x + 0.04 * f.y
f.y = -0.04 * f.x + 0.85 * f.y + 1.6
elseif r < 93
# Формирование левой стороны листвы
f.x = 0.2 * f.x - 0.26 * f.y
f.y = 0.23 * f.x + 0.22 * f.y + 1.6
else
# Формирование правой стороны листвы
f.x = -0.15 * f.x + 0.28 * f.y
f.y = 0.26 * f.x + 0.24 * f.y + 0.44
end
#########################################################################
# Переход от декартовых координат к индексам матрицы изображения
# Так как область значений (x ∈ [-2.182, 2.6558], y ∈ [0, 9.9983])
# нужно правильно смасштабировать координаты и перевести их в номера пикселей
# Для координаты x:
# минимальное значение x=-2.182 должно соответствовать первому столбцу (индекс 1)
# максимальное значение x=2.6558 → ширина-1
cx = Int(floor((f.x + 2.182) * (f.width - 1) / 4.8378) + 1)
# Для координаты y:
# в системе координат экрана ось Y направлена вниз, поэтому необходимо
# выполнить преобразование координат (отражение относительно горизонтальной оси)
# y=0 → последняя строка height
# y=9.9983 → первая строка 1
cy = Int(floor((9.9983 - f.y) * (f.height - 1) / 9.9983) + 1)
# Проверяем границы изображения перед установкой пикселя
if 1 <= cx <= f.width && 1 <= cy <= f.height
# Устанавливаем пиксель по новым координатам в заданный цвет
f.fern[cx, cy] = f.color
end
end
Function transform() simulates a random IFS process. At each step, she randomly selects one of the four affine transformations, changes the coordinates of the current point, and writes this point on the image.
To maintain the proportions when moving from the function definition area () to the pixel matrix, scaling factors and shifts are used:
- For X:
cx = floor((x + 2.182) × (ширина − 1) ÷ 4.8378) - For Y:
cy = floor((9.9983 − y) × (высота − 1) ÷ 9.9983)where the mirroring takes place
Performing iterations and displaying the result
Creating an instance of our 500×500 pixel fractal
const fern = BarnsleyFern(500, 500)
We run a million iterations – each step applies one of the affine transformations and adds a point to the corresponding pixel of the image.
for _ in 1:1000000
transform(fern)
end
We send back the result as a transposed matrix of pixels. This is due to the difference in the orientation of the axes in the screen and mathematical coordinate systems.
fern.fern'
This block of code starts the generation of a fractal image. It takes a million iteration steps, then we turn to the contents of the field. .fern and we transpose the matrix for correct display in graphics libraries.
Conclusion
We have analyzed in detail the implementation of the Barnsley Fern algorithm in the Julia programming language. It demonstrates the use of the iterable Function System (IFS) and allows you to visually see the fractal nature of self-similar objects.
The code creates a color image in the form of a matrix of RGB values, which can be further used or visualized in various ways.
This approach is useful for educational purposes, for understanding the principles of fractals, as well as in practical programming when working with recursive graphical objects and modeling natural structures.
The example was developed using materials from Rosetta Code
