xbe.at

Python / Python for ML and AI

Fractal Dimension Analysis of Images using Python

9 min read, 15 sections

Contents
  1. Introduction to Fractal Dimension of Images
  2. Box-Counting Method: Foundation of Fractal Dimension
  3. Calculating Fractal Dimension
  4. Image Preprocessing for Fractal Analysis
  5. Multifractal Analysis
  6. Lacunarity: Complementing Fractal Dimension
  7. Real-Life Example: Analyzing Leaf Structures
  8. Real-Life Example: Terrain Complexity Analysis
  9. Limitations and Considerations
  10. Advanced Techniques: Wavelet-Based Fractal Analysis
  11. Fractal Dimension in Image Segmentation
  12. Fractal Dimension in Texture Synthesis
  13. Future Directions and Research Opportunities
  14. Additional Resources
  15. Conclusion

Introduction to Fractal Dimension of Images

Fractal dimension is a measure of complexity that quantifies how a pattern's detail changes with scale. In image analysis, it can reveal intricate structures not apparent to the naked eye. This concept is particularly useful in fields like medical imaging, texture analysis, and pattern recognition.

import numpy as np
import matplotlib.pyplot as plt
from skimage.io import imread
from skimage.color import rgb2gray

# Load and display an example image
image = imread('fractal_example.jpg')
gray_image = rgb2gray(image)

plt.imshow(gray_image, cmap='gray')
plt.title('Grayscale Image for Fractal Analysis')
plt.show()

Box-Counting Method: Foundation of Fractal Dimension

The box-counting method is a fundamental technique for estimating fractal dimension. It involves covering the image with boxes of varying sizes and counting how many boxes contain part of the fractal pattern. The fractal dimension is derived from the relationship between box size and box count.

def box_count(image, box_size):
    boxes = image.shape[0] // box_size
    count = 0
    for i in range(boxes):
        for j in range(boxes):
            box = image[i*box_size:(i+1)*box_size, j*box_size:(j+1)*box_size]
            if np.any(box):
                count += 1
    return count

# Example usage
sizes = [2, 4, 8, 16, 32, 64]
counts = [box_count(gray_image, size) for size in sizes]

plt.plot(np.log(sizes), np.log(counts), 'o-')
plt.xlabel('Log(Box Size)')
plt.ylabel('Log(Box Count)')
plt.title('Box-Counting Plot')
plt.show()

Calculating Fractal Dimension

The fractal dimension is calculated from the slope of the log-log plot of box counts versus box sizes. A steeper slope indicates a higher fractal dimension, implying a more complex pattern.

from scipy.stats import linregress

# Calculate fractal dimension
slope, intercept, r_value, p_value, std_err = linregress(np.log(sizes), np.log(counts))
fractal_dim = -slope

print(f"Estimated Fractal Dimension: {fractal_dim:.3f}")

# Plot the regression line
plt.plot(np.log(sizes), np.log(counts), 'o', label='Data')
plt.plot(np.log(sizes), intercept + slope*np.log(sizes), 'r', label='Fitted Line')
plt.xlabel('Log(Box Size)')
plt.ylabel('Log(Box Count)')
plt.title('Fractal Dimension Calculation')
plt.legend()
plt.show()

Image Preprocessing for Fractal Analysis

Before applying fractal analysis, images often require preprocessing to enhance features or reduce noise. Common techniques include thresholding, edge detection, and filtering.

from skimage import filters
from skimage.morphology import skeletonize

# Applying Gaussian filter and Otsu's thresholding
filtered_image = filters.gaussian(gray_image, sigma=1)
thresh = filters.threshold_otsu(filtered_image)
binary_image = filtered_image > thresh

# Skeletonization to extract essential structure
skeleton = skeletonize(binary_image)

fig, axes = plt.subplots(1, 3, figsize=(15, 5))
axes[0].imshow(gray_image, cmap='gray')
axes[0].set_title('Original')
axes[1].imshow(binary_image, cmap='gray')
axes[1].set_title('Thresholded')
axes[2].imshow(skeleton, cmap='gray')
axes[2].set_title('Skeletonized')
plt.tight_layout()
plt.show()

Multifractal Analysis

Multifractal analysis extends the concept of fractal dimension to capture the distribution of local scaling properties. It's particularly useful for images with varying complexity across different regions.

def multifractal_spectrum(image, q_values):
    sizes = [2, 4, 8, 16, 32, 64]
    spectrums = []
    for q in q_values:
        counts = []
        for size in sizes:
            count = np.sum(np.power(image[::size, ::size], q))
            counts.append(count)
        slope, _, _, _, _ = linregress(np.log(sizes), np.log(counts))
        tau = -slope
        spectrums.append((q, tau))
    return np.array(spectrums)

q_values = np.linspace(-5, 5, 21)
spectrum = multifractal_spectrum(gray_image, q_values)

plt.plot(spectrum[:, 0], spectrum[:, 1], 'o-')
plt.xlabel('q')
plt.ylabel('τ(q)')
plt.title('Multifractal Spectrum')
plt.grid(True)
plt.show()

Lacunarity: Complementing Fractal Dimension

Lacunarity measures the "gappiness" or texture of a fractal, providing information about the distribution of gaps or holes in an image. It complements fractal dimension by distinguishing between patterns with similar fractal dimensions but different textures.

def lacunarity(image, box_sizes):
    lacunarity_values = []
    for size in box_sizes:
        boxes = np.lib.stride_tricks.sliding_window_view(image, (size, size))
        box_masses = np.sum(boxes, axis=(2, 3))
        lacunarity = np.var(box_masses) / np.mean(box_masses)**2
        lacunarity_values.append(lacunarity)
    return lacunarity_values

box_sizes = [2, 4, 8, 16, 32, 64]
lac_values = lacunarity(gray_image, box_sizes)

plt.plot(box_sizes, lac_values, 'o-')
plt.xscale('log')
plt.yscale('log')
plt.xlabel('Box Size')
plt.ylabel('Lacunarity')
plt.title('Lacunarity Plot')
plt.grid(True)
plt.show()

Real-Life Example: Analyzing Leaf Structures

Fractal dimension analysis can be applied to study the complexity of leaf venation patterns, which can provide insights into plant species identification and environmental adaptations.

# Assuming we have a leaf image loaded as 'leaf_image'
leaf_image = imread('leaf_example.jpg')
gray_leaf = rgb2gray(leaf_image)

# Extract leaf veins using edge detection
from skimage import feature
edges = feature.canny(gray_leaf)

# Calculate fractal dimension
sizes = [2, 4, 8, 16, 32, 64]
counts = [box_count(edges, size) for size in sizes]
slope, _, _, _, _ = linregress(np.log(sizes), np.log(counts))
leaf_fractal_dim = -slope

print(f"Leaf Venation Fractal Dimension: {leaf_fractal_dim:.3f}")

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
ax1.imshow(leaf_image)
ax1.set_title('Original Leaf Image')
ax2.imshow(edges, cmap='gray')
ax2.set_title('Leaf Vein Extraction')
plt.tight_layout()
plt.show()

Real-Life Example: Terrain Complexity Analysis

Fractal dimension can be used to quantify the complexity of terrain, which is valuable in geomorphology, landscape ecology, and urban planning.

# Assuming we have a terrain elevation map as 'terrain_map'
terrain_map = np.random.rand(256, 256)  # Simulated terrain for demonstration

# Calculate fractal dimension
sizes = [2, 4, 8, 16, 32, 64]
counts = [box_count(terrain_map, size) for size in sizes]
slope, _, _, _, _ = linregress(np.log(sizes), np.log(counts))
terrain_fractal_dim = -slope

print(f"Terrain Fractal Dimension: {terrain_fractal_dim:.3f}")

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
im1 = ax1.imshow(terrain_map, cmap='terrain')
ax1.set_title('Terrain Elevation Map')
plt.colorbar(im1, ax=ax1, label='Elevation')

ax2.plot(np.log(sizes), np.log(counts), 'o-')
ax2.set_xlabel('Log(Box Size)')
ax2.set_ylabel('Log(Box Count)')
ax2.set_title('Fractal Dimension Calculation')

plt.tight_layout()
plt.show()

Limitations and Considerations

While fractal dimension analysis is powerful, it has limitations. It can be sensitive to image resolution, noise, and preprocessing methods. Interpretation should consider the context of the image and the specific application.

# Demonstrating sensitivity to resolution
def resolution_sensitivity(image, scales):
    fractal_dims = []
    for scale in scales:
        resized = np.repeat(np.repeat(image, scale, axis=0), scale, axis=1)
        sizes = [2, 4, 8, 16, 32, 64]
        counts = [box_count(resized, size) for size in sizes]
        slope, _, _, _, _ = linregress(np.log(sizes), np.log(counts))
        fractal_dims.append(-slope)
    return fractal_dims

scales = [1, 2, 4, 8]
fd_results = resolution_sensitivity(gray_image, scales)

plt.plot(scales, fd_results, 'o-')
plt.xlabel('Scale Factor')
plt.ylabel('Estimated Fractal Dimension')
plt.title('Fractal Dimension Sensitivity to Resolution')
plt.grid(True)
plt.show()

Advanced Techniques: Wavelet-Based Fractal Analysis

Wavelet transforms offer an alternative approach to fractal analysis, providing localized frequency information and potentially more robust estimates of fractal dimension.

import pywt

def wavelet_fractal_dim(image, wavelet='db4', levels=5):
    coeffs = pywt.wavedec2(image, wavelet, level=levels)
    energies = [np.sum(np.abs(c)**2) for c in coeffs[1:]]
    scales = [2**i for i in range(1, levels+1)]
    
    slope, _, _, _, _ = linregress(np.log(scales), np.log(energies))
    return (2 + slope) / 2

wavelet_fd = wavelet_fractal_dim(gray_image)
print(f"Wavelet-based Fractal Dimension: {wavelet_fd:.3f}")

# Plot wavelet decomposition
coeffs = pywt.wavedec2(gray_image, 'db4', level=3)
titles = ['Approximation', 'Horizontal', 'Vertical', 'Diagonal']
fig, axes = plt.subplots(2, 2, figsize=(12, 12))
for i, (title, coeff) in enumerate(zip(titles, coeffs)):
    axes[i//2, i%2].imshow(coeff, cmap='gray')
    axes[i//2, i%2].set_title(title)
plt.tight_layout()
plt.show()

Fractal Dimension in Image Segmentation

Fractal dimension can be used as a feature for image segmentation, particularly in medical imaging for identifying abnormal tissues or in remote sensing for land cover classification.

from skimage.util import view_as_windows

def local_fractal_dim(image, window_size=64, step=32):
    windows = view_as_windows(image, (window_size, window_size), step=step)
    h, w = windows.shape[:2]
    fd_map = np.zeros((h, w))
    
    for i in range(h):
        for j in range(w):
            window = windows[i, j]
            sizes = [2, 4, 8, 16, 32]
            counts = [box_count(window, size) for size in sizes]
            slope, _, _, _, _ = linregress(np.log(sizes), np.log(counts))
            fd_map[i, j] = -slope
    
    return fd_map

fd_map = local_fractal_dim(gray_image)

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
ax1.imshow(gray_image, cmap='gray')
ax1.set_title('Original Image')
im2 = ax2.imshow(fd_map, cmap='viridis')
ax2.set_title('Local Fractal Dimension Map')
plt.colorbar(im2, ax=ax2, label='Fractal Dimension')
plt.tight_layout()
plt.show()

Fractal Dimension in Texture Synthesis

Fractal dimension can guide the synthesis of textures with specific complexity, useful in computer graphics and material design.

import scipy.ndimage as ndimage

def fractal_noise(size, H):
    x = np.linspace(0, 1, size)
    y = np.linspace(0, 1, size)
    X, Y = np.meshgrid(x, y)
    
    noise = np.zeros((size, size))
    octaves = int(np.log2(size))
    
    for i in range(octaves):
        freq = 2**i
        amp = freq**(-H)
        noise += amp * ndimage.gaussian_filter(np.random.randn(size, size), sigma=1/freq)
    
    return (noise - noise.min()) / (noise.max() - noise.min())

# Generate textures with different fractal dimensions
H_values = [0.3, 0.5, 0.7]
fig, axes = plt.subplots(1, 3, figsize=(15, 5))

for i, H in enumerate(H_values):
    texture = fractal_noise(256, H)
    axes[i].imshow(texture, cmap='gray')
    axes[i].set_title(f'H = {H}, FD ≈ {3 - H:.2f}')
    axes[i].axis('off')

plt.tight_layout()
plt.show()

Future Directions and Research Opportunities

The field of fractal dimension analysis in image processing continues to evolve. Emerging areas include deep learning-based fractal feature extraction, multi-scale fractal analysis, and applications in computer vision tasks like object recognition and scene understanding.

# Conceptual code for a deep learning-based fractal feature extractor
import tensorflow as tf

def fractal_cnn_model():
    model = tf.keras.Sequential([
        tf.keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(64, 64, 1)),
        tf.keras.layers.MaxPooling2D((2, 2)),
        tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
        tf.keras.layers.MaxPooling2D((2, 2)),
        tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
        tf.keras.layers.Flatten(),
        tf.keras.layers.Dense(64, activation='relu'),
        tf.keras.layers.Dense(1, name='fractal_dimension')
    ])
    return model

model = fractal_cnn_model()
model.summary()

# Note: This is a conceptual model and would require training data and implementation details

Additional Resources

For those interested in diving deeper into fractal dimension analysis of images, the following resources are recommended:

  1. ArXiv paper: "Multifractal Analysis of Images: New Connexions Between Analysis and Geometry" by J. Lévy Véhel and P. Mignot (https://arxiv.org/abs/cond-mat/9403023)
  2. ArXiv paper: "Fractal and Multifractal Analysis of PET/CT Images of Metastatic Melanoma Before and After Treatment with Ipilimumab" by L. Karmazyn et al. (https://arxiv.org/abs/1509.05273)
  3. ArXiv paper: "Multifractal Analysis of Multivariate Images Using Gamma Markov Random Field and Dirichlet Process Mixture Models" by N. Wendt et al. (https://arxiv.org/abs/1507.04937)

These papers provide advanced insights into fractal analysis techniques and their applications in various fields, including medical imaging and texture analysis.

Conclusion

Fractal dimension analysis offers a powerful tool for quantifying complexity in images, with applications ranging from medical diagnostics to environmental monitoring. As we've explored, this technique provides insights into image structure that traditional methods may overlook. The combination of fractal analysis with machine learning and advanced signal processing techniques opens up new avenues for image understanding and classification. As research in this field progresses, we can expect to see increasingly sophisticated applications of fractal dimension analysis in various domains of image processing and computer vision.

# Conceptual code for future research direction
def advanced_fractal_analysis(image):
    # Traditional fractal dimension
    fd_traditional = calculate_fractal_dimension(image)
    
    # Wavelet-based fractal analysis
    fd_wavelet = wavelet_fractal_dim(image)
    
    # Deep learning feature extraction
    dl_features = deep_learning_fractal_features(image)
    
    # Multi-scale analysis
    multiscale_fd = multiscale_fractal_analysis(image)
    
    # Combine all features for comprehensive analysis
    comprehensive_features = np.concatenate([
        [fd_traditional, fd_wavelet],
        dl_features,
        multiscale_fd
    ])
    
    return comprehensive_features

# Note: This is pseudocode to illustrate potential future directions

More in Python for ML and AI

  1. Generating Unique Random Numbers in Python7 min

    Understanding how to generate unique random numbers is crucial for various applications, from sampling to simulation. The simplest approach uses Python's...

  2. Exploring the Wait-Time Paradox with Python6 min

    Have you ever wondered why the longer you wait on hold, the more time you expect to keep waiting? This phenomenon is known as the "wait-time paradox," and it...

  3. Generative vs. Discriminative Models in Python10 min

    Generative and discriminative models are two fundamental approaches in machine learning. Generative models learn the joint probability distribution of inputs...

  4. Exploring the P vs NP Problem with Python7 min

    P vs NP is one of the most important unsolved problems in computer science and mathematics. It asks whether every problem whose solution can be quickly...

  5. Genetic Algorithms for Image Blending in Python6 min

    Genetic algorithms are optimization techniques inspired by natural selection. In the context of image combination, they can be used to evolve and blend...

  6. Exploring the Mathematical Thriller Pi Movie Using Python:8 min

    "Pi" is a psychological thriller film directed by Darren Aronofsky. The movie follows Max Cohen, a mathematician who believes he has discovered a 216-digit...