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

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.