|
|
- #!/usr/bin/env python
-
- from PIL import Image, ImageOps
- import wave, math, array, argparse, sys, timeit
-
- def parser():
- parser = argparse.ArgumentParser()
-
- # Specified command options and its helps message
-
- parser.add_argument ("INPUT_FILE", help="Name of the image to be converted.")
- parser.add_argument ("-r", "--rotate", help="Rotate image 90 degrees.", action='store_true')
- parser.add_argument ("-i", "--invert", help="Invert image colors.", action='store_true')
- parser.add_argument ("-o", "--output", help="Name of the output wav file. Default value: out.wav).")
- parser.add_argument ("-b", "--bottom", help="Bottom frequency range. Default value: 200.", type=int)
- parser.add_argument ("-t", "--top", help="Top frequency range. Default value: 20000.", type=int)
- parser.add_argument ("-p", "--pixels", help="Pixels per second. Default value: 30.", type=int)
- parser.add_argument ("-s", "--sampling", help="Sampling rate. Default value: 44100.", type=int)
-
- # Create "arguments" object based on user input
- arguments = parser.parse_args()
-
- # Default values
-
- min_freq = 200
- max_freq = 20000
- sampling_rate = 44100
- pixels = 30
- output = "out.wav"
- rotate = False
- invert = False
-
- # Check arguments values
- if arguments.output:
- output = arguments.output
- if arguments.bottom:
- min_freq = arguments.bottom
- if arguments.top:
- max_freq = arguments.top
- if arguments.pixels:
- pixels = arguments.pixels
- if arguments.sampling:
- sampling_rate = arguments.sampling
- if arguments.rotate:
- rotate = True
- if arguments.invert:
- invert = True
-
- print ("------------------------------------ Simple Image To Sound Script ------------------------------------\n")
- print ('Input file: %s.' % arguments.INPUT_FILE)
- print ('Frequency range: %d - %d.' % (min_freq, max_freq))
- print ('Pixels per second: %d.' % pixels)
- print ('Sampling rate: %d.' % sampling_rate)
- print ('Rotate Image: %s.' % ('Yes' if rotate else 'No'))
-
- return (arguments.INPUT_FILE, output, min_freq, max_freq, pixels, sampling_rate, rotate, invert)
-
- def convert (INPUT_FILE, output, min_freq, max_freq, pixels, sampling_rate, rotate, invert):
- image = Image.open (INPUT_FILE).convert ('L')
-
- # rotate image if requested
- if rotate:
- image = image.rotate (90)
-
- # invert image if requested
- if invert:
- image = ImageOps.invert (image)
-
- output = wave.open (output, 'w')
- output.setparams ((1, 2, sampling_rate, 0, 'NONE', 'not compressed'))
-
- freq_range = max_freq - min_freq
- interval = freq_range / image.size[1]
-
- samples = sampling_rate // pixels
- data = array.array ('h')
-
- # Converting process start
- time_start = timeit.default_timer()
-
- for x in range (image.size[0]):
- row = []
- for y in range (image.size[1]):
- yinv = image.size[1] - y - 1
- amplitude = image.getpixel ((x,y))
- if (amplitude > 0):
- row.append (gen_wave (yinv * interval + min_freq, amplitude, samples, sampling_rate))
-
- for i in range(samples):
- for j in row:
- try:
- data[i + x * samples] += j[i]
- except (IndexError):
- data.insert (i + x * samples, j[i])
- except (OverflowError):
- if j[i] > 0:
- data[i + x * samples] = 32767
- else:
- data[i + x * samples] = -32768
-
- sys.stdout.write ("Conversion progress: %d%% \r" % (float(x) / image.size[0] * 100))
- sys.stdout.flush()
-
- output.writeframes (data.tobytes())
- output.close()
-
- # Converting process end
- time_end = timeit.default_timer()
-
- print ("Conversion progress: 100%")
- print ("Success. Completed in %d seconds." % int(time_end - time_start))
-
- def gen_wave (frequency, amplitude, samples, sampling_rate):
- cycles = samples * frequency / sampling_rate
- wave = []
- for i in range(samples):
- x = math.sin (float (cycles) * 2 * math.pi * i / float (samples)) * float (amplitude)
- wave.append (int (math.floor (x)))
- return wave
-
- if __name__ == '__main__':
- input_choice = parser()
- convert (*input_choice)
|