User:Jasper van Loenen/Prototyping/svgMovie: Difference between revisions
No edit summary |
No edit summary |
||
(4 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
Converting a video to an animated svg file. | __NOINDEX__ | ||
Converting a YouTube video to an animated svg file. | |||
[[Media:Svg.svg|Example]] (this svg seems to work only in Chrome... (not Firefox)) | [[Media:Svg.svg|Example]] (this svg seems to work only in Chrome... (not Firefox)) | ||
<source lang="python"> | |||
import Image, os, sys | |||
#set some initial values which can be overwritten using arguments | |||
frameStep = 10 #the image will animate from frame to frame. To decrease load/filesize it will use every Nth frame | |||
gridSize = 20.0 #how many blocks | |||
tweenSpeed = (1.0 / 24.0) * frameStep #it calculates the relative FPS | |||
# Download the video given as the first argument, if no argument is found: die | |||
if len(sys.argv)<=1: | |||
print "Error: this script takes a single YouTube URL as argument!" | |||
exit() | |||
else: | |||
if len(sys.argv) > 2: | |||
gridSize = sys.argv[2] | |||
if len(sys.argv) > 3: | |||
frameStep = sys.argv[3] | |||
#create a temp folder to save the video and such (clear if already exists) | |||
os.system("rm -r tmp") | |||
os.system("mkdir tmp") | |||
os.system("youtube-dl -quiet -o tmp/video.%\(ext\)s "+sys.argv[1]) | |||
# Check if the file was downloaded and get a path to it. If no file found, clear temp folder and die | |||
files = os.listdir("tmp/") | |||
if len(files)==0: | |||
if os.listdir("tmp/"): | |||
os.system("rm -r tmp") | |||
print "Error: the tmp folder is empty." | |||
print "I guess something went wrong while downloading the video :(" | |||
exit() | |||
else: | |||
totalFrames = len(files) | |||
vidPath = "tmp/"+files[0] | |||
# Split the audio and save it seperately for possible later use | |||
os.system("ffmpeg -i "+vidPath+" tmp/audio.wav") | |||
# Render the frames to images | |||
os.system("ffmpeg -i "+vidPath+" -f image2 tmp/originalFrame-%06d.png") | |||
os.system("convert -sample 10% -sample 1000% tmp/originalFrame-%06d.png tmp/newFrame-%06d.png") | |||
class GridBlock: | |||
def __init__(self, _x, _y, _width, _height, _number) : | |||
self.x = _x | |||
self.y = _y | |||
self.w = _width | |||
self.h = _height | |||
self.number = _number | |||
self.firstRun = True | |||
self.blockFrame = 0; | |||
self.prevR, self.prevG, self.prevB = 0, 0, 0 | |||
self.blockOutput = "<rect id=\"block"+str(self.number)+"\" x=\""+str(self.x)+"\" y=\""+str(self.y)+"\" width=\""+str(self.w)+"\" height=\""+str(self.h)+"\" style=\"fill:black\">\n" | |||
return | |||
def updateColor(self, im): | |||
source = im.split() | |||
totalR, totalG, totalB = 0, 0, 0 | |||
totalChecked = 0 | |||
totalR, totalG, totalB = 0, 0, 0 | |||
for xPos in range(self.x, int(self.x+self.w)): | |||
for yPos in range(self.y, int(self.y+self.h)): | |||
pix = im.getpixel((xPos,yPos)) | |||
totalR += pix[0] | |||
totalG += pix[1] | |||
totalB += pix[2] | |||
totalChecked+=1 | |||
currR = totalR / totalChecked | |||
currG = totalG / totalChecked | |||
currB = totalB / totalChecked | |||
if self.firstRun==True: | |||
self.prevR = currR | |||
self.prevG = currG | |||
self.prevB = currB | |||
self.firstRun = False | |||
self.blockOutput += "\t<animateColor attributeName=\"fill\" attributeType=\"CSS\"\n\tfrom=\"rgb("+str(self.prevR)+", "+str(self.prevG)+", "+str(self.prevB)+")\" to=\"rgb("+str(currR)+", "+str(currG)+", "+str(currB)+")\" begin=\""+str(self.blockFrame*tweenSpeed)+"s\" dur=\""+str(tweenSpeed)+"s\" fill=\"freeze\"/>\n" | |||
self.prevR = currR | |||
self.prevG = currG | |||
self.prevB = currB | |||
self.blockFrame+=1 | |||
return | |||
def endOutput(self): | |||
self.blockOutput += "</rect>\n\n" | |||
return | |||
gridWidth = 0 | |||
gridHeight = 0 | |||
blocksList = [] | |||
formattedCurrFrame = "" | |||
W, H = 0, 1 | |||
frameImg = Image.open("tmp/originalFrame-000001.png") | |||
if gridSize > frameImg.size[W]: | |||
gridSize = frameImg.size[W] | |||
elif gridSize > frameImg.size[H]: | |||
gridSize = frameImg.size[H] | |||
elif gridSize < 1: | |||
gridSize = 1 | |||
gridWidth = frameImg.size[W] / gridSize; | |||
gridHeight = frameImg.size[H] / gridSize; | |||
index = 0; | |||
for y in xrange(0, frameImg.size[H], int(gridHeight)): | |||
for x in xrange(0, frameImg.size[W], int(gridWidth)): | |||
if index < gridSize*gridSize: | |||
blocksList.append(GridBlock(x, y, gridWidth, gridHeight, index)) | |||
index+=1 | |||
#There must be a more efficient way to do the following, didn't look it up yet | |||
for currFrame in xrange(1, totalFrames+1, frameStep): | |||
if currFrame < 10: | |||
formattedCurrFrame = "00000" + str(currFrame) | |||
elif currFrame < 100: | |||
formattedCurrFrame = "0000" + str(currFrame) | |||
elif currFrame < 1000: | |||
formattedCurrFrame = "000" + str(currFrame) | |||
elif currFrame < 10000: | |||
formattedCurrFrame = "00" + str(currFrame) | |||
elif currFrame < 100000: | |||
formattedCurrFrame = "0" + str(currFrame) | |||
else: | |||
formattedCurrFrame = ""+str(currFrame) | |||
frameImg = Image.open("tmp/originalFrame-"+formattedCurrFrame+".png") | |||
frameImg.load() | |||
index = 0 | |||
for i in xrange(0, len(blocksList)): | |||
blocksList[i].updateColor(frameImg) | |||
svgOut = "<?xml version=\"1.0\" standalone=\"no\"?>\n<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">"; | |||
svgOut += "\n\n<svg width=\""+str(frameImg.size[0])+"\" height=\""+str(frameImg.size[1])+"\" version=\"1.1\"\nxmlns=\"http://www.w3.org/2000/svg\">\n\n"; | |||
for i in xrange(0, len(blocksList)): | |||
blocksList[i].endOutput() | |||
svgOut += blocksList[i].blockOutput | |||
svgOut += "</svg>" | |||
# Output the results so they can be piped into another script | |||
print "Saving svg file..." | |||
outputFile = open("result.svg", "w") | |||
outputFile.write(svgOut) | |||
outputFIle.close() | |||
# Clean up by deleting the downloaded video and generated images | |||
os.system("rm -r tmp") | |||
print "All done!" | |||
</source> |
Latest revision as of 01:31, 14 March 2012
Converting a YouTube video to an animated svg file.
Example (this svg seems to work only in Chrome... (not Firefox))
import Image, os, sys
#set some initial values which can be overwritten using arguments
frameStep = 10 #the image will animate from frame to frame. To decrease load/filesize it will use every Nth frame
gridSize = 20.0 #how many blocks
tweenSpeed = (1.0 / 24.0) * frameStep #it calculates the relative FPS
# Download the video given as the first argument, if no argument is found: die
if len(sys.argv)<=1:
print "Error: this script takes a single YouTube URL as argument!"
exit()
else:
if len(sys.argv) > 2:
gridSize = sys.argv[2]
if len(sys.argv) > 3:
frameStep = sys.argv[3]
#create a temp folder to save the video and such (clear if already exists)
os.system("rm -r tmp")
os.system("mkdir tmp")
os.system("youtube-dl -quiet -o tmp/video.%\(ext\)s "+sys.argv[1])
# Check if the file was downloaded and get a path to it. If no file found, clear temp folder and die
files = os.listdir("tmp/")
if len(files)==0:
if os.listdir("tmp/"):
os.system("rm -r tmp")
print "Error: the tmp folder is empty."
print "I guess something went wrong while downloading the video :("
exit()
else:
totalFrames = len(files)
vidPath = "tmp/"+files[0]
# Split the audio and save it seperately for possible later use
os.system("ffmpeg -i "+vidPath+" tmp/audio.wav")
# Render the frames to images
os.system("ffmpeg -i "+vidPath+" -f image2 tmp/originalFrame-%06d.png")
os.system("convert -sample 10% -sample 1000% tmp/originalFrame-%06d.png tmp/newFrame-%06d.png")
class GridBlock:
def __init__(self, _x, _y, _width, _height, _number) :
self.x = _x
self.y = _y
self.w = _width
self.h = _height
self.number = _number
self.firstRun = True
self.blockFrame = 0;
self.prevR, self.prevG, self.prevB = 0, 0, 0
self.blockOutput = "<rect id=\"block"+str(self.number)+"\" x=\""+str(self.x)+"\" y=\""+str(self.y)+"\" width=\""+str(self.w)+"\" height=\""+str(self.h)+"\" style=\"fill:black\">\n"
return
def updateColor(self, im):
source = im.split()
totalR, totalG, totalB = 0, 0, 0
totalChecked = 0
totalR, totalG, totalB = 0, 0, 0
for xPos in range(self.x, int(self.x+self.w)):
for yPos in range(self.y, int(self.y+self.h)):
pix = im.getpixel((xPos,yPos))
totalR += pix[0]
totalG += pix[1]
totalB += pix[2]
totalChecked+=1
currR = totalR / totalChecked
currG = totalG / totalChecked
currB = totalB / totalChecked
if self.firstRun==True:
self.prevR = currR
self.prevG = currG
self.prevB = currB
self.firstRun = False
self.blockOutput += "\t<animateColor attributeName=\"fill\" attributeType=\"CSS\"\n\tfrom=\"rgb("+str(self.prevR)+", "+str(self.prevG)+", "+str(self.prevB)+")\" to=\"rgb("+str(currR)+", "+str(currG)+", "+str(currB)+")\" begin=\""+str(self.blockFrame*tweenSpeed)+"s\" dur=\""+str(tweenSpeed)+"s\" fill=\"freeze\"/>\n"
self.prevR = currR
self.prevG = currG
self.prevB = currB
self.blockFrame+=1
return
def endOutput(self):
self.blockOutput += "</rect>\n\n"
return
gridWidth = 0
gridHeight = 0
blocksList = []
formattedCurrFrame = ""
W, H = 0, 1
frameImg = Image.open("tmp/originalFrame-000001.png")
if gridSize > frameImg.size[W]:
gridSize = frameImg.size[W]
elif gridSize > frameImg.size[H]:
gridSize = frameImg.size[H]
elif gridSize < 1:
gridSize = 1
gridWidth = frameImg.size[W] / gridSize;
gridHeight = frameImg.size[H] / gridSize;
index = 0;
for y in xrange(0, frameImg.size[H], int(gridHeight)):
for x in xrange(0, frameImg.size[W], int(gridWidth)):
if index < gridSize*gridSize:
blocksList.append(GridBlock(x, y, gridWidth, gridHeight, index))
index+=1
#There must be a more efficient way to do the following, didn't look it up yet
for currFrame in xrange(1, totalFrames+1, frameStep):
if currFrame < 10:
formattedCurrFrame = "00000" + str(currFrame)
elif currFrame < 100:
formattedCurrFrame = "0000" + str(currFrame)
elif currFrame < 1000:
formattedCurrFrame = "000" + str(currFrame)
elif currFrame < 10000:
formattedCurrFrame = "00" + str(currFrame)
elif currFrame < 100000:
formattedCurrFrame = "0" + str(currFrame)
else:
formattedCurrFrame = ""+str(currFrame)
frameImg = Image.open("tmp/originalFrame-"+formattedCurrFrame+".png")
frameImg.load()
index = 0
for i in xrange(0, len(blocksList)):
blocksList[i].updateColor(frameImg)
svgOut = "<?xml version=\"1.0\" standalone=\"no\"?>\n<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">";
svgOut += "\n\n<svg width=\""+str(frameImg.size[0])+"\" height=\""+str(frameImg.size[1])+"\" version=\"1.1\"\nxmlns=\"http://www.w3.org/2000/svg\">\n\n";
for i in xrange(0, len(blocksList)):
blocksList[i].endOutput()
svgOut += blocksList[i].blockOutput
svgOut += "</svg>"
# Output the results so they can be piped into another script
print "Saving svg file..."
outputFile = open("result.svg", "w")
outputFile.write(svgOut)
outputFIle.close()
# Clean up by deleting the downloaded video and generated images
os.system("rm -r tmp")
print "All done!"