# -----------------------------------------------------------------------------
# From https://en.wikipedia.org/wiki/Minkowski–Bouligand_dimension:
#
# In fractal geometry, the Minkowski–Bouligand dimension, also known as
# Minkowski dimension or box-counting dimension, is a way of determining the
# fractal dimension of a set S in a Euclidean space Rn, or more generally in a
# metric space (X, d).
# -----------------------------------------------------------------------------
from PIL import Image
import numpy as np
def fractal_dimension(Z, threshold=0.9):
# Only for 2d image
assert(len(Z.shape) == 2)
# From https://github.com/rougier/numpy-100 (#87)
def boxcount(Z, k):
S = np.add.reduceat(
np.add.reduceat(Z, np.arange(0, Z.shape[0], k), axis=0),
np.arange(0, Z.shape[1], k), axis=1)
# We count non-empty (0) and non-full boxes (k*k)
return len(np.where((S > 0) & (S < k*k))[0])
# Transform Z into a binary array
Z = (Z < threshold)
plt.imshow(Z)
plt.show()
# Minimal dimension of image
p = min(Z.shape)
# Greatest power of 2 less than or equal to p
n = 2**np.floor(np.log(p)/np.log(2))
# Extract the exponent
n = int(np.log(n)/np.log(2))
# Build successive box sizes (from 2**n down to 2**1)
sizes = 2**np.arange(n, 1, -1)
# Actual box counting with decreasing size
counts = []
for size in sizes:
counts.append(boxcount(Z, size))
# Fit the successive log(sizes) with log (counts)
coeffs = np.polyfit(np.log(sizes), np.log(counts), 1)
return -coeffs[0]
fname = 'sierpinski.png'
I = Image.open(fname).convert("L")
I = np.asarray(I)/255
_ = plt.hist(I.ravel()) # 看一下分布
print("Minkowski–Bouligand dimension (computed): ", fractal_dimension(I, 0.05))
print("Haussdorf dimension (theoretical): ", (np.log(3)/np.log(2)))
print(f"min {I[:,:].min()} and max {I[:,:].max()} in the array/image")
Minkowski–Bouligand dimension (computed): 1.4602931559817836
Haussdorf dimension (theoretical): 1.5849625007211563
min 0.0 and max 0.30980392156862746 in the array/image
import numpy as np
import matplotlib.pyplot as plt
def fractal_dimension(Z, threshold=0.9):
# Only for 2d image
assert(len(Z.shape) == 2)
# From https://github.com/rougier/numpy-100 (#87)
def boxcount(Z, k):
S = np.add.reduceat(
np.add.reduceat(Z, np.arange(0, Z.shape[0], k), axis=0),
np.arange(0, Z.shape[1], k), axis=1)
# We count non-empty (0) and non-full boxes (k*k)
return len(np.where((S > 0) & (S < k*k))[0])
# Transform Z into a binary array
Z = (Z < threshold)
plt.imshow(Z)
plt.show()
# Minimal dimension of image
p = min(Z.shape)
# Greatest power of 2 less than or equal to p
n = 2**np.floor(np.log(p)/np.log(2))
# Extract the exponent
n = int(np.log(n)/np.log(2))
# Build successive box sizes (from 2**n down to 2**1)
sizes = 2**np.arange(n, 1, -1)
# Actual box counting with decreasing size
counts = []
for size in sizes:
counts.append(boxcount(Z, size))
# Fit the successive log(sizes) with log (counts)
coeffs = np.polyfit(np.log(sizes), np.log(counts), 1)
return -coeffs[0]
special = [
'https://upload.wikimedia.org/wikipedia/commons/thumb/7/7c/Peano_Sierpinski_carpet_4.svg/440px-Peano_Sierpinski_carpet_4.svg.png',
'https://upload.wikimedia.org/wikipedia/commons/thumb/3/3b/Quadratic_Koch_2.svg/2880px-Quadratic_Koch_2.svg.png',
'https://upload.wikimedia.org/wikipedia/commons/thumb/5/55/Quadratic_Koch.svg/300px-Quadratic_Koch.svg.png'
]
images = [
'https://upload.wikimedia.org/wikipedia/commons/thumb/7/7c/Peano_Sierpinski_carpet_4.svg/440px-Peano_Sierpinski_carpet_4.svg.png',
'https://upload.wikimedia.org/wikipedia/commons/thumb/b/b7/Sierpinski_carpet_3.svg/244px-Sierpinski_carpet_3.svg.png',
'https://upload.wikimedia.org/wikipedia/commons/f/f0/Flocke.PNG',
'https://upload.wikimedia.org/wikipedia/commons/thumb/3/3b/Quadratic_Koch_2.svg/2880px-Quadratic_Koch_2.svg.png',
'https://upload.wikimedia.org/wikipedia/commons/thumb/5/55/Quadratic_Koch.svg/300px-Quadratic_Koch.svg.png'
]
dimensions = [(np.log(3)/np.log(2)), (np.log(3)/np.log(2)), (np.log(4)/np.log(3)), 1.46, 1.5]
for dim, im in zip(dimensions, images):
# load im
x = plt.imread(im)
if im in special:
print("Minkowski–Bouligand dimension (computed): ", fractal_dimension(x[:,:,3], threshold=0.2))
print("theoretical: ", dim)
print(f"min {x[:,:,3].min()} and max {x[:,:,3].max()} in the array/image")
else:
print("Minkowski–Bouligand dimension (computed): ", fractal_dimension(x[:,:,1],threshold=0.2))
print("theoretical: ", dim)
print(f"min {x[:,:,1].min()} and max {x[:,:,1].max()} in the array/image")
/shared-libs/python3.7/py-core/lib/python3.7/site-packages/ipykernel_launcher.py:63: MatplotlibDeprecationWarning: Directly reading images from URLs is deprecated since 3.4 and will no longer be supported two minor releases later. Please open the URL for reading and pass the result to Pillow, e.g. with ``PIL.Image.open(urllib.request.urlopen(url))``.
Minkowski–Bouligand dimension (computed): 1.6442512048599502
theoretical: 1.5849625007211563
min 0.0 and max 0.9803921580314636 in the array/image
Minkowski–Bouligand dimension (computed): 1.4719806750010764
theoretical: 1.5849625007211563
min 0.0 and max 1.0 in the array/image
Minkowski–Bouligand dimension (computed): 1.3215737426881282
theoretical: 1.2618595071429148
min 0.0 and max 1.0 in the array/image
Minkowski–Bouligand dimension (computed): 1.2992066667079616
theoretical: 1.46
min 0.0 and max 1.0 in the array/image
Minkowski–Bouligand dimension (computed): 1.4086046680283932
theoretical: 1.5
min 0.0 and max 0.4901960790157318 in the array/image