diff --git a/ascii/ascii.py b/ascii/ascii.py index 93fdde2..dac835b 100644 --- a/ascii/ascii.py +++ b/ascii/ascii.py @@ -6,7 +6,7 @@ Author: Mahesh Venkitachalam """ -import sys, random, argparse +import argparse import numpy as np import math @@ -16,22 +16,11 @@ # http://paulbourke.net/dataformats/asciiart/ # 70 levels of gray -gscale1 = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. " +gscale1 = r"$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. " # 10 levels of gray gscale2 = '@%#*+=-:. ' -def getAverageL(image): - """ - Given PIL Image, return average value of grayscale value - """ - # get image as numpy array - im = np.array(image) - # get shape - w,h = im.shape - # get average - return np.average(im.reshape(w*h)) - -def covertImageToAscii(fileName, cols, scale, moreLevels): +def covertImageToAscii(fileName, cols=80, scale=0.43, moreLevels=False): """ Given Image and dims (rows, cols) returns an m*n list of Images """ @@ -40,29 +29,28 @@ def covertImageToAscii(fileName, cols, scale, moreLevels): # open image and convert to grayscale image = Image.open(fileName).convert('L') # store dimensions - W, H = image.size[0], image.size[1] + W, H = image.size print("input image dims: %d x %d" % (W, H)) # compute width of tile - w = W/cols + w = W//cols # compute tile height based on aspect ratio and scale - h = w/scale + h = int(w/scale) # compute number of rows - rows = int(H/h) + rows = int(H / h) print("cols: %d, rows: %d" % (cols, rows)) print("tile dims: %d x %d" % (w, h)) # check if image size is too small if cols > W or rows > H: - print("Image too small for specified cols!") - exit(0) + raise Exception("Image too small for specified cols!") # ascii image is a list of character strings aimg = [] # generate list of dimensions for j in range(rows): - y1 = int(j*h) - y2 = int((j+1)*h) + y1 = j*h + y2 = (j+1)*h # correct last tile if j == rows-1: y2 = H @@ -70,20 +58,20 @@ def covertImageToAscii(fileName, cols, scale, moreLevels): aimg.append("") for i in range(cols): # crop image to tile - x1 = int(i*w) - x2 = int((i+1)*w) + x1 = i*w + x2 = (i+1)*w # correct last tile if i == cols-1: x2 = W # crop image to extract tile img = image.crop((x1, y1, x2, y2)) # get average luminance - avg = int(getAverageL(img)) + avg = int(np.average(img)) # look up ascii char if moreLevels: - gsval = gscale1[int((avg*69)/255)] + gsval = gscale1[(avg*69)//255] else: - gsval = gscale2[int((avg*9)/255)] + gsval = gscale2[(avg*9)//255] # append ascii char to string aimg[j] += gsval @@ -93,43 +81,34 @@ def covertImageToAscii(fileName, cols, scale, moreLevels): # main() function def main(): # create parser - descStr = "This program converts an image into ASCII art." - parser = argparse.ArgumentParser(description=descStr) + parser = argparse.ArgumentParser( + description="This program converts an image into ASCII art.") # add expected arguments parser.add_argument('--file', dest='imgFile', required=True) - parser.add_argument('--scale', dest='scale', required=False) - parser.add_argument('--out', dest='outFile', required=False) - parser.add_argument('--cols', dest='cols', required=False) - parser.add_argument('--morelevels',dest='moreLevels',action='store_true') + parser.add_argument('--scale', dest='scale', default=0.43, type=float) + parser.add_argument('--out', dest='outFile', default='out.txt') + parser.add_argument('--cols', dest='cols', default=80, type=int) + parser.add_argument('--morelevels', dest='moreLevels', action='store_true') # parse args args = parser.parse_args() - - imgFile = args.imgFile + # set output file - outFile = 'out.txt' - if args.outFile: - outFile = args.outFile + outFile = args.outFile # set scale default as 0.43 which suits a Courier font - scale = 0.43 - if args.scale: - scale = float(args.scale) + scale = args.scale # set cols - cols = 80 - if args.cols: - cols = int(args.cols) + cols = args.cols print('generating ASCII art...') # convert image to ascii txt - aimg = covertImageToAscii(imgFile, cols, scale, args.moreLevels) + aimg = covertImageToAscii(args.imgFile, cols, scale, args.moreLevels) # open file - f = open(outFile, 'w') - # write to file - for row in aimg: - f.write(row + '\n') - # cleanup - f.close() + with open(outFile, 'w') as f: + # write to file + f.write('\n'.join(aimg)) + print("ASCII art written to %s" % outFile) # call main diff --git a/autos/as.png b/autos/as.png new file mode 100644 index 0000000..9cc9e66 Binary files /dev/null and b/autos/as.png differ diff --git a/autos/autos.py b/autos/autos.py index be52256..d362ac4 100644 --- a/autos/autos.py +++ b/autos/autos.py @@ -6,7 +6,8 @@ Author: Mahesh Venkitachalam """ -import sys, random, argparse +import argparse +import math, random from PIL import Image, ImageDraw # create spacing/depth example @@ -26,13 +27,13 @@ def createRandomTile(dims): img = Image.new('RGB', dims) draw = ImageDraw.Draw(img) # calculate radius - % of min dimension - r = int(min(*dims)/100) + r = min(*dims) // 100 # radius # number of dots n = 1000 # draw random circles - for i in range(n): + for _ in range(n): # -r is used so circle stays inside - cleaner for tiling - x, y = random.randint(0, dims[0]-r), random.randint(0, dims[1]-r) + x, y = random.randint(0, dims[0]-r), random.randint(0, dims[1]-r) # center fill = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) draw.ellipse((x-r, y-r, x+r, y+r), fill) @@ -46,8 +47,8 @@ def createTiledImage(tile, dims): W, H = dims w, h = tile.size # calculate # of tiles needed - cols = int(W/w) + 1 - rows = int(H/h) + 1 + cols = math.ceil(W / w) + rows = math.ceil(H / h) # paste tiles for i in range(rows): for j in range(cols): @@ -65,7 +66,7 @@ def createDepthMap(dims): # Given a depth map (image) and an input image, create a new image # with pixels shifted according to depth -def createDepthShiftedImage(dmap, img): +def createDepthShiftedImage(dmap, img, period): # size check assert dmap.size == img.size # create shifted image @@ -78,64 +79,55 @@ def createDepthShiftedImage(dmap, img): for j in range(rows): for i in range(cols): xshift = pixD[i, j]/10 - xpos = i - 140 + xshift - if xpos > 0 and xpos < cols: + xpos = i - period + xshift + if 0 < xpos < cols: pixS[i, j] = pixS[xpos, j] # return shifted image return sImg # Given a depth map (image) and an input image, create a new image # with pixels shifted according to depth -def createAutostereogram(dmap, tile): +def createAutostereogram(dmap, tile=None): # convert depth map to single channel if needed if dmap.mode is not 'L': dmap = dmap.convert('L') - # if no tile specified, use random image + # if no tile specified, use np.random image if not tile: tile = createRandomTile((100, 100)) # create an image by tiling img = createTiledImage(tile, dmap.size) - # create shifted image - sImg = img.copy() - # get pixel access - pixD = dmap.load() - pixS = sImg.load() - # shift pixels output based on depth map - cols, rows = sImg.size - for j in range(rows): - for i in range(cols): - xshift = pixD[i, j]/10 - xpos = i - tile.size[0] + xshift - if xpos > 0 and xpos < cols: - pixS[i, j] = pixS[xpos, j] # return shifted image - return sImg + return createDepthShiftedImage(dmap, img, tile.size[0]) # main() function def main(): - # use sys.argv if needed print('creating autostereogram...') # create parser parser = argparse.ArgumentParser(description="Autosterograms...") # add expected arguments parser.add_argument('--depth', dest='dmFile', required=True) - parser.add_argument('--tile', dest='tileFile', required=False) - parser.add_argument('--out', dest='outFile', required=False) + parser.add_argument('--tile', dest='tileFile', default=False) + parser.add_argument('--out', dest='outFile', default=None) # parse args args = parser.parse_args() - # set output file - outFile = 'as.png' - if args.outFile: - outFile = args.outFile - # set tile - tileFile = False - if args.tileFile: - tileFile = Image.open(args.tileFile) # open depth map dmImg = Image.open(args.dmFile) + # set output file + outFile = args.outFile + # set tile + if args.tileFile=='self': + size = dmImg.size[0] // 7, dmImg.size[1] // 7 + tileFile = dmImg.resize(size) + elif args.tileFile: + tileFile = Image.open(args.tileFile) + else: + tileFile = args.tileFile # create stereogram asImg = createAutostereogram(dmImg, tileFile) # write output + if args.outFile is None: + import os.path + outFile = os.path.splitext(os.path.basename(args.dmFile))[0] + '.png' asImg.save(outFile) # call main diff --git a/karplus/ks.py b/karplus/ks.py index 2a398da..1a48e15 100644 --- a/karplus/ks.py +++ b/karplus/ks.py @@ -7,8 +7,8 @@ Author: Mahesh Venkitachalam """ -import sys, os -import time, random +import os +import time import wave, argparse, pygame import numpy as np from collections import deque @@ -24,17 +24,16 @@ # write out WAVE file def writeWAVE(fname, data): # open file - file = wave.open(fname, 'wb') - # WAV file parameters - nChannels = 1 - sampleWidth = 2 - frameRate = 44100 - nFrames = 44100 - # set parameters - file.setparams((nChannels, sampleWidth, frameRate, nFrames, - 'NONE', 'noncompressed')) - file.writeframes(data) - file.close() + with wave.open(fname, 'wb') as file: + # WAV file parameters + nChannels = 1 + sampleWidth = 2 + frameRate = 44100 + nFrames = 44100 + # set parameters + file.setparams((nChannels, sampleWidth, frameRate, nFrames, + 'NONE', 'noncompressed')) + file.writeframes(data) # generate note of given frequency def generateNote(freq): @@ -42,17 +41,17 @@ def generateNote(freq): sampleRate = 44100 N = int(sampleRate/freq) # initialize ring buffer - buf = deque([random.random() - 0.5 for i in range(N)]) + buf = deque(np.random.uniform(-0.5,0.5, size=N)) # plot of flag set if gShowPlot: axline, = plt.plot(buf) # init sample buffer - samples = np.array([0]*nSamples, 'float32') + samples = np.zeros(nSamples, 'float32') for i in range(nSamples): samples[i] = buf[0] avg = 0.995*0.5*(buf[0] + buf[1]) buf.append(avg) - buf.popleft() + buf.popleft() # plot of flag set if gShowPlot: if i % 1000 == 0: @@ -83,8 +82,7 @@ def play(self, fileName): print(fileName + ' not found!') def playRandom(self): """play a random note""" - index = random.randint(0, len(self.notes)-1) - note = list(self.notes.values())[index] + note = np.random.choice(self.notes.values()) note.play() # main() function @@ -94,9 +92,9 @@ def main(): parser = argparse.ArgumentParser(description="Generating sounds with Karplus String Algorithm.") # add arguments - parser.add_argument('--display', action='store_true', required=False) - parser.add_argument('--play', action='store_true', required=False) - parser.add_argument('--piano', action='store_true', required=False) + parser.add_argument('--display', action='store_true', default=False) + parser.add_argument('--play', action='store_true', default=False) + parser.add_argument('--piano', action='store_true', default=False) args = parser.parse_args() # show plot if flag set @@ -108,8 +106,8 @@ def main(): nplayer = NotePlayer() print('creating notes...') - for name, freq in list(pmNotes.items()): - fileName = name + '.wav' + for name, freq in pmNotes.items(): + fileName = name + '.wav' if not os.path.exists(fileName) or args.display: data = generateNote(freq) print('creating ' + fileName + '...') @@ -131,9 +129,8 @@ def main(): try: nplayer.playRandom() # rest - 1 to 8 beats - rest = np.random.choice([1, 2, 4, 8], 1, - p=[0.15, 0.7, 0.1, 0.05]) - time.sleep(0.25*rest[0]) + rest = np.random.choice([1, 2, 4, 8], p=[0.15, 0.7, 0.1, 0.05]) + time.sleep(0.25*rest) except KeyboardInterrupt: exit() diff --git a/karplus/sine.py b/karplus/sine.py index da1a032..e2cc041 100644 --- a/karplus/sine.py +++ b/karplus/sine.py @@ -7,14 +7,13 @@ """ import numpy as np -import wave, math +import wave sRate = 44100 nSamples = sRate * 5 x = np.arange(nSamples)/float(sRate) -vals = np.sin(2.0*math.pi*146.83*x) +vals = np.sin(2.0*np.pi*146.83*x) data = np.array(vals * 32767, 'int16').tostring() -file = wave.open('sine146_83.wav', 'wb') -file.setparams((1, 2, sRate, nSamples, 'NONE', 'uncompressed')) -file.writeframes(data) -file.close() +with wave.open('sine146_83.wav', 'wb') as file: + file.setparams((1, 2, sRate, nSamples, 'NONE', 'uncompressed')) + file.writeframes(data)