2
\$\begingroup\$

In mathematics, the Thue–Morse sequence, or Prouhet–Thue–Morse sequence, is the binary sequence (an infinite sequence of 0s and 1s) obtained by starting with 0 and successively appending the Boolean complement of the sequence obtained thus far.

Wikipedia Page

I wanted to create images using the Thue–Morse sequence, my idea is very simple, since the sequence is binary, group each eight bits into a byte, and then each three bytes into a pixel, and then make the list of pixels two-dimensional, done.

It is indeed that simple, but the result is of low contrast, so I increased contrast after the image was created.

enter image description here


Code

import numpy as np
from PIL import Image, ImageEnhance
from typing import List


def abbabaab(n: int) -> str:
    return "".join(str(i.bit_count() % 2) for i in range(n))


def Thue_Morse(n: int) -> str:
    s = [0]
    for _ in range(n):
        s += [i ^ 1 for i in s]
    return "".join(map(str, s))


def abbabaab_list(n: int) -> List[int]:
    return [i.bit_count() % 2 for i in range(n)]


def abbabaab_array(n: int) -> np.array:
    bits = np.unpackbits(np.arange(n).view(np.uint8))
    bits = bits.reshape((n, bits.shape[0] // n))
    return np.sum(bits, axis=1) % 2


def Thue_Morse_array(n: int) -> np.array:
    s = np.array([False], dtype=bool)
    for _ in range(n):
        s = np.concatenate([s, s ^ True])
    return s


def log2_ceil(n: int) -> int:
    log = n.bit_length()
    return log - (1 << log - 1 == n)


def Thue_Morse_image(width: int, height: int) -> Image:
    total = width * height * 24
    pixels = Thue_Morse_array(log2_ceil(total))[:total].reshape((total // 8, 8))
    pixels = np.sum(pixels * 1 << np.arange(8)[::-1], axis=1)
    img = Image.fromarray(pixels.reshape((height, width, 3)).astype(np.uint8))
    return ImageEnhance.Contrast(img).enhance(4)


def Thue_Morse_grayscale(width: int, height: int) -> Image:
    total = width * height
    pixels = Thue_Morse_array(log2_ceil(total))[:total].reshape((height, width))
    return Image.fromarray(pixels)


def main(width: str, height: str, path: str, grayscale: str = '') -> None:
    [Thue_Morse_image, Thue_Morse_grayscale][bool(grayscale)](int(width), int(height)).save(path)


if __name__ == "__main__":
    import sys

    main(*sys.argv[1:])

As you can see I have found three ways to generate the sequence, and this is the first time I have utilized NumPy thoroughly to do something.

How can it be improved?


Edit

I removed a bug where the array generation will run for one extra iteration if the number is extractly a power of 2. I also added a grayscale version of image creation function.

enter image description here

\$\endgroup\$

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.