Computer Graphics & Algorithms
Visualizing complex systems through mathematical computing: from rasterizing primitives to generating recursive fractals.
Project Overview
Computer graphics bridges the gap between abstract mathematics and visual perception. This project explores fundamental algorithms for rendering images from code.
It includes a low-level implementation of Rasterization (converting vector shapes into pixels) and a high-performance visualizer for the Mandelbrot Set, optimizing complex number calculations using NumPy vectorization.
Key Concepts Implemented
Vectorization
Optimized the Mandelbrot generation by operating on entire 2D grids of complex numbers simultaneously, replacing slow Python loops with C-optimized NumPy arrays.
Rasterization
Implemented a scan-line algorithm logic to determine whether pixels lie within a mathematically defined triangle, manually handling anti-aliasing and edge cases.
Fractal Recursion
Visualized chaotic behavior where simple iterative rules ($z = z^2 + c$) give rise to infinitely complex boundary structures.
Source Code
1. Mandelbrot Fractal (`p5_hw5.py`)
Generates high-resolution visualizations of the Mandelbrot set.
#!/usr/bin/env python3
#before I begin, I want to say that first I will plot the mandelbrot via pyplot and then make a ps file with the exact scaling (image) of the part that I zoomed in the pyplot.
import numpy as np
import matplotlib.pyplot as plt
#function of mandelbrot
def mandelbrot(c, max_iter):
z = 0
for n in range(max_iter):
if abs(z) > 2:
return n
z = z*z +c
return max_iter
def mandelbrotset(xmin, xmax, ymin,ymax, width, height, max_iter):
x = np.linspace(xmin,xmax, width)
y = np.linspace(ymin, ymax, height)
mset = np.zeros((height,width))
for i in range(height):
for j in range(width):
c = complex(x[j],y[i])
mset[i,j] = mandelbrot(c, max_iter)
return mset
width, height = 512, 384
max_iter = 250
xmin, xmax, ymin, ymax = -0.74625,-0.73875,0.10125,0.11375
print("Generating Mandelbrot: ")
print(f"Re axis: [{xmin},{xmax}] (range: {xmax - xmin})")
print(f"Im axis: [{ymin},{ymax}] (range: {ymax - ymin})")
print(f"Grid: {width}x{height}, Max iterations: {max_iter}\n")
mandelbrot_image = mandelbrotset(xmin,xmax,ymin,ymax,width,height,max_iter)
plt.imshow(mandelbrot_image, extent=[xmin,xmax,ymin,ymax], cmap = 'hot')
plt.colorbar()
plt.title('mandelbrot visualization')
plt.xlabel('Re(c)')
plt.ylabel('Im(c)')
plt.savefig("p5_hw5.ps")
plt.show()
2. Triangle Rasterization (`p4_hw5.py`)
Low-level implementation of drawing a triangle pixel-by-pixel.
#!/usr/bin/env python3
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
X, Y = 512, 409
lw = 20
base_x1, base_y1 = 0, 0
base_x2, base_y2 = 400, 0
top_x, top_y = 400, 300
slope = 3 / 4
color = (0, 0, 255)
bg_color = (255, 255, 255)
offset = 48
half_lw = lw//2
total_offset = offset+half_lw
save_name = "p4_hw5_rt345_raster.tif"
hyp_thickness = int(lw/0.8) #cos of angle is 0.8)
#Setting white canvas
pvals = np.full((X, Y, 3), bg_color, dtype='uint8')
# Draw
for x in range(X):
for y in range(Y):
rel_x = x-total_offset
rel_y = y-total_offset
y_hyp = slope * rel_x
if (0 <= rel_y <= lw) or (y_hyp - hyp_thickness <= rel_y <= y_hyp) or (top_x - lw <= rel_x <= top_x):
if rel_y <= slope * rel_x and rel_x <= top_x and rel_y >= 0:
pvals[x, y, :] = color
plotarr = np.flipud(pvals.transpose(1, 0, 2))
f1, ax1 = plt.subplots()
ax1.imshow(plotarr, interpolation='none')
ax1.axis('off')
plt.show()
# Save image
im = Image.fromarray(plotarr, 'RGB')
im.save(save_name)
print(f'Image saved to {save_name}')
input("\nPress Enter to exit...\n")