|
|
(23 intermediate revisions by the same user not shown) |
Line 5: |
Line 5: |
| Here is my first drawing in class with coding. | | Here is my first drawing in class with coding. |
| my sheep robot. . . funny one | | my sheep robot. . . funny one |
| [[File:Sheep.png |100px|]] | | [[File:Sheep.png |200px|]] |
|
| |
|
|
| |
|
Line 29: |
Line 29: |
| ----Cloud Code---- | | ----Cloud Code---- |
| <pre style="font-size:smaller" > | | <pre style="font-size:smaller" > |
| | <source lang="python"> |
| #cloud | | #cloud |
| width = 400 | | width = 400 |
Line 83: |
Line 84: |
|
| |
|
| </pre> | | </pre> |
| | </source> |
|
| |
|
|
| |
|
Line 107: |
Line 109: |
| [[File:Screen Shot 2558-06-17 at 12.03.18 AM.png]] | | [[File:Screen Shot 2558-06-17 at 12.03.18 AM.png]] |
|
| |
|
| As can be seen here,in this step, the final resault take only small part of the source image. | | As can be seen here,in this step, the final result take only small part of the source image. |
|
| |
|
| It is quite difficult to trance back what the sorce image look like but it is the preparation for the next step. | | It is quite difficult to trace back what the source image look like but it is the preparation for the next step. |
|
| |
|
|
| |
|
| code for the image processing | | code for the image processing |
| ============================= | | ============================= |
| <pre style="font-size:normal" > | | |
| | <source lang="python"> |
|
| |
|
| from PIL import Image, ImageDraw,ImageFilter | | from PIL import Image, ImageDraw,ImageFilter |
Line 220: |
Line 223: |
|
| |
|
|
| |
|
| </pre> | | </source> |
| | |
|
| |
|
|
| |
|
| | '''FINAL BOT''' |
|
| |
|
| '''STEP 2 : moving Kaleido''' | | '''STEP 2 : moving Kaleido''' |
Line 239: |
Line 242: |
| so they will affect how smooth the animated GIF going to be. | | so they will affect how smooth the animated GIF going to be. |
|
| |
|
| This is the example result.
| |
|
| |
|
| [[File:Botexample1.png]]
| | '''STEP 3 Making the bot works online''' |
| [[File:Kaleidogif1.gif]]
| |
|
| |
|
| Source image : illustration from Oliver Jeffers
| | The @kaleidogif twiiter account is created to be the page for the bot. |
| [[File:JEFFERS>JPG]]
| | ( Before that I just did trial and errors with my own account) |
|
| |
|
| This is the code of Gif Version
| | Link : [KaleidoGIF twitter|https://twitter.com/kaleidogif] |
|
| |
|
| [[Media:jeffers.gif |Example result .GIF]]
| |
|
| |
|
| ======Kaleidoscope 360 GIF ========
| | [[File:Botscreen1.PNG|900px]] |
| <pre style="font-size:normal" >
| |
|
| |
|
| from PIL import Image, ImageDraw,ImageFilter
| | This is the example result. |
| import PIL.ImageOps as im
| |
| import numpy as np
| |
| import moviepy.editor as mpy
| |
|
| |
|
| | [[File:Botexample1.png|210 px]] |
| | [[File:Kaleidogif1.gif]] |
|
| |
|
| | more examples of the final result !! |
| | [[File:Botexamplegif2.gif]] |
| | [[File:Kaleidoexample3.gif.gif|320 px]] |
| | [[File:Kaleidoexample2.gif|320 px]] |
|
| |
|
| def onepic():
| |
| global output
| |
| #creat mask base the same size with source image
| |
| mask = Image.new('RGBA', base.size, (255,255,255,0))
| |
| x, y = base.size
| |
| print("base size: %sx%s"%(x,y))
| |
|
| |
| # one variable to vary the size of triangle
| |
| var = y/28
| |
|
| |
| # Define triangle mask position (triangle with 20 degree)
| |
| (originx,originy) = (int(0.4*x),int(y))
| |
| trih = int(12*var) #fix formular for triangle height
| |
| triw = int(4.2*var) #fix formular for triangle width
| |
| polygonpos = [(originx,originy),
| |
| (originx+triw,originy),
| |
| (originx+triw/2,originy-trih)]
| |
| print(trih,triw)
| |
|
| |
|
| |
| # Create mask
| |
| draw = ImageDraw.Draw(mask,'RGBA')
| |
| draw.polygon(polygonpos,(0,0,0,255))
| |
| del draw
| |
| mask.save("mask.png")
| |
|
| |
| # Get the Alpha band from the template
| |
| tmplt = Image.open('mask.png')
| |
| A = tmplt.split()[3]
| |
|
| |
|
| |
| #make one piece of triangle on transparent bg
| |
| [R,G,B]=base.split()
| |
| tri = Image.merge('RGBA', (R, G, B, A))
| |
|
| |
| #crop it to the exact size of triangle!! to create primary pattern
| |
| #box (left, top , right, buttom)
| |
| box =(originx,(originy-trih),(originx+triw),originy)
| |
| pattern_plain=tri.crop(box)
| |
| pattern_plain.save('pattern_plain.png')
| |
| print('....pattern created....')
| |
|
| |
|
| |
| # add style to pattern
| |
| pattern = pattern_plain
| |
| #pattern= pattern_plain.filter(ImageFilter.EDGE_ENHANCE)
| |
| pattern.save('pattern_tri.png')
| |
| print('....stylized pattern....')
| |
|
| |
|
| |
| #make square canvas for the output (wide = double size of height of primary pattern)
| |
| canvas =Image.new('RGBA',(2*trih,2*trih), (255,255,255,0))
| |
| canvas.save('tmpcanvas.png')
| |
| pcanvas=Image.new('RGBA',(2*trih,2*trih), (255,255,255,0))
| |
|
| |
|
| |
|
| |
|
| |
| #put pattern on the canvas
| |
| #make sure to put the tip of the triangle at the center of the canvas
| |
| #because when we rotate the center of the object is the pivot point
| |
| #note: paste command require the coordinate of top left corner
| |
| #so point to paste the pattern is . . .
| |
| ccenterx = int(trih-triw/2)
| |
| canvas.paste(pattern_plain,(ccenterx,trih))
| |
|
| |
|
| |
| # start rotate the pattern around every 40 degree
| |
|
| |
| for i in range (0,360,40):
| |
| tmpcanvas = canvas
| |
| tmppat = canvas.rotate(i)
| |
| canvas= Image.alpha_composite(tmpcanvas,tmppat)
| |
|
| |
| # now we get half of the things
| |
| half = canvas
| |
| print('half already')
| |
| #mirror the half and put in the space to create simple kaleidoscpoe effect
| |
| mirror = im.mirror(half)
| |
| half2= mirror.rotate(20)
| |
| print('mirrored')
| |
|
| |
| #merge 2 half
| |
| output=Image.alpha_composite(half,half2)
| |
| output.save("output.png")
| |
|
| |
|
| |
| #def makegif():
| |
| #clip = mpy.ImageSequenceClip(outfilename, fps=3)
| |
| #clip.write_gif("%s.gif"%filename)
| |
|
| |
| def makekaleido(image) :
| |
| global base, filename, source, imgfile, n, outfilename
| |
| #IN CASE Working on filename in the laptop
| |
| #put image path
| |
| imgfile = "tweetimg.jpg"
| |
| filename = imgfile[:-4]
| |
| print(filename)
| |
|
| |
| #load Image
| |
| source = Image.open(imgfile)
| |
|
| |
| #source = image.copy()
| |
| x, y = source.size
| |
|
| |
| if x > 1000:
| |
| newy = int(1000*y/x)
| |
| source =source.resize((1000,newy), Image.ANTIALIAS)
| |
| print('resize to %sx%s'%source.size)
| |
|
| |
| #creat mask base the same size with source image
| |
| mask = Image.new('RGBA', source.size, (255,255,255,0))
| |
| print("mask size:%sx%s"%source.size)
| |
|
| |
|
| |
|
| #rotate source n times for a degree
| | '''FINISHING STEP''' |
| n= 10
| |
| outfilename=[]
| |
| for a in range(n+n-2):
| |
| outfilename.insert(a,'0')
| |
| a= 10
| |
| base = source
| |
| for i in range(n):
| |
| base = source.rotate(31+i*a)
| |
| onepic()
| |
| output.save('%s%s.png'%(filename,i))
| |
| outfilename[i] = filename+str(i)+'.png'
| |
| if i!=0:
| |
| outfilename[2*n-2-i] = filename+str(i)+'.png'
| |
|
| |
| clip = mpy.ImageSequenceClip(outfilename, fps=3)
| |
| clip.write_gif("%s.gif"%filename)
| |
| image2 = Image.open('tweetimg3.png')
| |
|
| |
|
| return image2,clip
| | Last step . . . for the summaery event , I improved a bit the quality of the |
| | GIF by editing the code to be able to make best quality it can and also the final GIF is not larger that the twitter status update limit. |
|
| |
|
|
| | So I added lines of code to get the size of the final GIF and resize it if it exceed the limit. |
|
| |
|
| if __name__ == '__main__':
| |
|
| |
|
| makekaleido(image)
| | '''The complete code of the final version can be found here in the GitHub link'''. [https://github.com/AaeApasri/KaleidoGIFBot] |
| </pre>
| | feel free to download and develop it further if you are interested. ;) |