Welcome to Doom9's Forum, THE inplace to be for everyone interested in DVD conversion. Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules. 
1st June 2015, 19:57  #1  Link 
unsigned int
Join Date: Oct 2012
Location: 🇪🇺
Posts: 723

Writing VapourSynth filters in Python
Just for fun.
Here is RemoveGrain mode 19 implemented in Python: Code:
import vapoursynth as vs c = vs.get_core() def removegrain_mode19(n, f): fout = f.copy() for p in range(fout.format.num_planes): plane = fout.get_write_array(p) plane_height = len(plane) plane_width = len(plane[0]) for y in range(1, plane_height  1): for x in range(1, plane_width  1): plane[y][x] = (plane[y1][x1] + plane[y1][x] + plane[y1][x+1] + plane[y][x1] + plane[y][x+1] + plane[y+1][x1] + plane[y+1][x] + plane[y+1][x+1] + 4) >> 3 return fout src = c.ffms2.Source("asdf.mov") src = c.std.ModifyFrame(clip=src, clips=src, selector=removegrain_mode19) src.set_output()
__________________
Buy me a "coffee" and/or hire me to write code! 
1st June 2015, 21:51  #2  Link 
►◄
Join Date: Mar 2006
Location: A wretched hive of scum and villainy
Posts: 4,402

3 nested for loops with array operations in the inner loop  The Python script interpreter should manage one frame in less than a day.
__________________
Groucho's Avisynth Stuff 
1st June 2015, 21:56  #4  Link 
Professional Code Monkey
Join Date: Jun 2003
Location: Ikea Chair
Posts: 2,002

We obviously need to switch to PyPy!
__________________
VapourSynth  proving that scripting languages and video processing isn't dead yet 
2nd June 2015, 05:51  #5  Link 
Registered User
Join Date: Jan 2010
Posts: 270

Obviously you need to add some asm to it.

2nd June 2015, 07:55  #6  Link  
Excessively jovial fellow
Join Date: Jun 2004
Location: rude
Posts: 1,073

Quote:


2nd June 2015, 09:57  #7  Link  
ангел смерти
Join Date: Nov 2004
Location: Lost
Posts: 9,413

Quote:
__________________
There are four boxes to be used in defense of liberty: soap, ballot, jury, and ammo. Please use in that order. 

6th June 2015, 10:21  #9  Link 
Professional Code Monkey
Join Date: Jun 2003
Location: Ikea Chair
Posts: 2,002

Cython can compile the module for pypy too (and 2.x python but I don't care about ancient versions). It's just that nobody's really tested it yet.
__________________
VapourSynth  proving that scripting languages and video processing isn't dead yet 
8th June 2015, 12:12  #10  Link 
Registered User
Join Date: Oct 2010
Posts: 36

Before we delve into the magical and mysterious world of pypy, let's get this algorithm more optimised. (And maybe have a better understanding of python internals at the same time).
Firstly nested for loops. Surely we need one? we have to iterate over two axis! nope, python has a beautiful module in the standard library called itertools. The product function will generate us a nested for loop for us! so: Code:
for y in range(1, plane_height  1): for x in range(1, plane_width  1): ... Code:
from itertools import product for y,x in product(range(1, plane_height1), range(1, plane_width1)): ... Secondly lets look at: Code:
plane[y][x] Code:
plane[y,x] >> 3 has the same comparable speed as // 8 so let's use the one that makes more sense in terms of what the algorithm is doing. Finally I noticed a bug in the original implementation. We are reading pixel values from the copied frame and not the original frame! this means that when values change in the output that will affect the pixel values. (Which I believe is not what the original mode19 does). So a pure Python implementation with speedups would look like this: Code:
from itertools import product import vapoursynth as vs c = vs.get_core() def removegrain_mode19(n, f): fout = f.copy() for p in range(fout.format.num_planes): plane = fout.get_write_array(p) inplane = f.get_read_array(p) plane_height = len(plane) plane_width = len(plane[0]) for y, x in product(range(1, plane_height  1), range(1, plane_width  1)): plane[y, x] = (inplane[y1, x1] + inplane[y1, x] + inplane[y1, x+1] + inplane[y, x1] + inplane[y, x+1] + inplane[y+1, x1] + inplane[y+1, x] + inplane[y+1, x+1] + 4) // 8 return fout Finally it's also worth pointing out here get_write_array(p) can be used as an input to other modules such as numpy and not occur a memory copy. Utilising these you may get even more of a speed up. Last edited by splinter98; 8th June 2015 at 13:08. 
8th June 2015, 14:39  #11  Link 
Registered User
Join Date: Jan 2010
Posts: 270

Range in python3 only creates an iterator which is extremely cheap (both cpu and memorywise). Also considering that there are no cyclic references, the created iterator (and memoryview objects for that matter) will be collected at the end of the outer loop after every iteration so I'm not sure where that memory consumption reduction would come from.
Last edited by TurboPascal7; 8th June 2015 at 14:44. 
9th June 2015, 12:03  #13  Link  
Registered User
Join Date: Oct 2010
Posts: 36

Quote:
Quote:
Code:
import numpy as np import vapoursynth as vs from scipy import ndimage c = vs.get_core() def removegrain_mode19(n, f): fout = f.copy() for p in range(fout.format.num_planes): plane = np.asarray(fout.get_write_array(p)) inplane = np.asarray(f.get_read_array(p)) #Implement filter below using numpy methods return fout 

11th June 2015, 15:09  #14  Link 
I'm Siri
Join Date: Oct 2012
Location: Los Angeles, California
Posts: 2,133

the very FIRST filter I just wrote....
a spatial median (radius=1) filter Code:
def median (n, f): fout = f.copy() for p in range(fout.format.num_planes): plane = fout.get_write_array(p) plane_height = len(plane) plane_width = len(plane[0]) members=[plane[0][0]]*9 for y in range(1, plane_height  1): for x in range(1, plane_width  1): members[0] = plane[y1][x1] members[1] = plane[y][x1] members[2] = plane[y+1][x1] members[3] = plane[y1][x] members[4] = plane[y][x] members[5] = plane[y+1][x] members[6] = plane[y1][x+1] members[7] = plane[y][x+1] members[8] = plane[y+1][x+1] members.sort() plane[y][x] = members[4] return fout so I'll just wait Myrsloik to update "std.Median"
__________________
If I got new ideas, will post here: https://github.com/IFeelBloated 
12th June 2015, 08:19  #15  Link 
I'm Siri
Join Date: Oct 2012
Location: Los Angeles, California
Posts: 2,133

Code:
def rg11_int (n, f): fout = f.copy() for p in range(fout.format.num_planes): plane = fout.get_write_array(p) plane_height = len(plane) plane_width = len(plane[0]) for y in range(1, plane_height  1): for x in range(1, plane_width  1): plane[y][x] = (plane[y][x] * 4 + (plane[y+1][x] + plane[y1][x] + plane[y][x+1] + plane[y][x1]) * 2 + plane[y+1][x+1] + plane[y+1][x1] + plane[y1][x+1] + plane[y1][x1] + 8) // 16 return fout
__________________
If I got new ideas, will post here: https://github.com/IFeelBloated 
12th June 2015, 08:43  #16  Link 
Professional Code Monkey
Join Date: Jun 2003
Location: Ikea Chair
Posts: 2,002

You read from the same frame as you write. That's the problem.
__________________
VapourSynth  proving that scripting languages and video processing isn't dead yet 
12th June 2015, 12:19  #17  Link  
I'm Siri
Join Date: Oct 2012
Location: Los Angeles, California
Posts: 2,133

so, in case I did something wrong about rg11, I just copied the code at #1 by jackoneill
Code:
import vapoursynth as vs c = vs.get_core() def removegrain_mode19(n, f): fout = f.copy() for p in range(fout.format.num_planes): plane = fout.get_write_array(p) plane_height = len(plane) plane_width = len(plane[0]) for y in range(1, plane_height  1): for x in range(1, plane_width  1): plane[y][x] = (plane[y1][x1] + plane[y1][x] + plane[y1][x+1] + plane[y][x1] + plane[y][x+1] + plane[y+1][x1] + plane[y+1][x] + plane[y+1][x+1] + 4) >> 3 return fout src = rule6.vob src = c.std.ShufflePlanes(src, planes=0, colorfamily=vs.GRAY) src1 = c.std.ModifyFrame(clip=src, clips=src, selector=removegrain_mode19) dif = c.std.MakeDiff (src1,c.rgvs.RemoveGrain (src,19)).std.Expr ("x 128  10 * 128 +") dif.set_output() Quote:
clp=rule6 dup=clp std.ModifyFrame(clip=clp, clips=dup, selector=xxx) but not working
__________________
If I got new ideas, will post here: https://github.com/IFeelBloated 

12th June 2015, 12:49  #18  Link  
I'm Siri
Join Date: Oct 2012
Location: Los Angeles, California
Posts: 2,133

and one more thing,
Quote:
Code:
plane[y][x] = (plane[y1][x1] + plane[y1][x] + plane[y1][x+1] + plane[y][x1] + plane[y][x+1] + plane[y+1][x1] + plane[y+1][x] + plane[y+1][x+1]) >> 3 but actually implemented as Code:
plane[y][x] = (plane[y1][x1] + plane[y1][x] + plane[y1][x+1] + plane[y][x1] + plane[y][x+1] + plane[y+1][x1] + plane[y+1][x] + plane[y+1][x+1] + 4) >> 3
__________________
If I got new ideas, will post here: https://github.com/IFeelBloated 

12th June 2015, 13:01  #19  Link 
Professional Code Monkey
Join Date: Jun 2003
Location: Ikea Chair
Posts: 2,002

How the code should be written in the first post.
Code:
import vapoursynth as vs c = vs.get_core() def removegrain_mode19(n, f): fout = f.copy() for p in range(fout.format.num_planes): plane = f.get_read_array(p) dst_plane = fout.get_write_array(p) plane_height = len(plane) plane_width = len(plane[0]) for y in range(1, plane_height  1): for x in range(1, plane_width  1): dst_plane[y][x] = (plane[y1][x1] + plane[y1][x] + plane[y1][x+1] + plane[y][x1] + plane[y][x+1] + plane[y+1][x1] + plane[y+1][x] + plane[y+1][x+1] + 4) >> 3 return fout src = c.ffms2.Source("asdf.mov") src = c.std.ModifyFrame(clip=src, clips=src, selector=removegrain_mode19) src.set_output()
__________________
VapourSynth  proving that scripting languages and video processing isn't dead yet 
12th June 2015, 13:22  #20  Link 
I'm Siri
Join Date: Oct 2012
Location: Los Angeles, California
Posts: 2,133

@Myrsloik
difs still exist, but a LOT smaller now, difs look like some random dust covered on a blank gray clip now, guess that's because of rounding errors caused by asm opt? and I get that "+4" now, so "x >> 3"=floor(x/8), that +4 turns it into round (x/8), so it should be removed in float point version edit: so "//" is actually floor division, I always thought it's round division
__________________
If I got new ideas, will post here: https://github.com/IFeelBloated Last edited by feisty2; 12th June 2015 at 13:33. 
Thread Tools  Search this Thread 
Display Modes  

