Skip to content

Instantly share code, notes, and snippets.

@dmishin
Created April 29, 2016 18:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dmishin/56238588f712628fd9ec25c7498c51fb to your computer and use it in GitHub Desktop.
Save dmishin/56238588f712628fd9ec25c7498c51fb to your computer and use it in GitHub Desktop.
Unwrap imgage pixels into a 1-dimensional array along the Hilbert's curve, then convert it to sound using SOX
#!/usr/bin/env python
from __future__ import print_function, division
import os.path
from numpy import array, hstack, vstack, clip
from PIL import Image
import numpy as np
import subprocess # need the subprocess module
from tempfile import mkdtemp
import shutil
#SOX_EXEC = r"C:\Program Files\sox-14-4-2\sox.exe"
SOX_EXEC = r"sox"
def ilog2(x):
log = 0
while x > 1:
log += 1
x = x // 2
return log
def hilbert_indices(N):
m = array([[0]], dtype=np.int)
for i in range(N):
d = 4**i
m1 = vstack( (hstack( (m.T, m.T[::-1, ::-1] + 3*d )),
hstack( (m+d, m+2*d) )
)
)
m = m1
return m
def saveSound(sound, ofile, rate):
if sound.dtype != np.uint8:
sound = sound.astype(np.uint8)
tempdir = mkdtemp()
try:
fname = os.path.join(tempdir, "audio.raw")
with open(fname, "wb") as rawfile:
sound.tofile( rawfile )
print("saved temp file", fname)
args = [SOX_EXEC,
"-t", "RAW",
'-e','signed-integer', # input encode as signed ints
'-L', # input little endin
'-c', '1', # mono
'-b', '8', # input bits per sample
'-r', str(rate),
fname,
ofile]
print ("args:", " ".join(args))
subprocess.check_call( args )
finally:
shutil.rmtree(tempdir)
print ("Removed temp directory")
def hilbertImage2audio( filename, ofile, rate=44100 ):
#load mage
img = Image.open( filename )
if img.mode != "L":
raise ValueError("Image must be grayscale")
arr = np.asarray(img)
del img
if len(arr.shape) == 3:
w,h,chans = arr.shape
else:
w,h = arr.shape
chans = 1
if chans != 1: raise ValueError("Image must be grayscale")
if w!=h: raise ValueError("Image not square")
if (w-1)&w != 0: raise ValueError("Image sides must be powers of 2")
arr = arr.astype(np.uint8)
arr -= 127
n= ilog2(w)
indices = hilbert_indices( n )
sound = np.zeros( (w*h,), dtype = np.uint8 )
sound[ indices ] = arr
del arr
saveSound(sound, ofile, rate)
if __name__=="__main__":
import sys
try:
imgfile = sys.argv[1]
audiofile = sys.argv[2]
except IndexError:
print("Usage: hilbert_image2audio.py IMAGE_FILE AUDIO_FILE")
exit(1)
hilbertImage2audio(imgfile, audiofile)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment