View Full Version : MaskTools 2.0a48


Manao
20th August 2005, 23:06
Hi,

As I said in the Avisynth 2.6 thread, I'm working on the MaskTools again. The code has been rewritten from scratch, mainly to make it easily portable to the upcoming Avisynth 3.0.

All inline asm has been ported to nasm. Some filters have disappeared. Some behaviors have changed. All named have changed, to allow you to use both MaskTools v1.5.8 and 2.0a.

Refers to the readme.txt to have a quick summary of the filters and what have changed since the 1.5.8.

This thread is here to collect bug reports and feature requests.

Here is the link to the new version : http://manao4.free.fr/masktools-v2.0a48.zip

Changes from alpha 47 to alpha 48 : * added : signed and unsigned binary shifts to LUTs, ceil/floor/trunc float -> int conversions. @ is now equivalent to °Changes from alpha 46 to alpha 47 : * added : signed and unsigned binary operators to LUTsChanges from alpha 45 to alpha 46 : * fixed : with mt_lutf, "std" mode wasn't working. Could also affect "std" with mt_luts and mt_lutsxChanges from alpha 44 to alpha 45 : * fixed : mt_clamp on sse2 platforms with resolution not multiple of 64
* added : mode parameter to mt_lutspa, to clean up biased/relative messChanges from alpha 43 to alpha 44 : * added : new very flexible mode to mt_luts and mt_lutsxChanges from alpha 42 to alpha 43 : * fixed : optimized versions of small horizontal resolutions with mt_edge, mt_xxpand and mt_xxflate
* fixed : avisynth 2.6 support (likely broken since avisynth 2.6 alpha 2 at least)
* added : hprewitt mode to mt_edge
* added : "biased" option to mt_lutspa
* optimized : prewitt and hprewitt mode for mt_edgeChanges from alpha 41 to alpha 42 : * added : specialized modes for mt_binarize
* added : specialized modes for mt_logicChanges from alpha 40 to alpha 41 : * (re)optimized : mt_edge with custom kernels and divisors that are a power of two</li>
* fixed : mt_edge with custom kernels (has always been broken in C, which became obvious once asm was removed)</li>
* fixed : no more crashes when an input clip isn't YUV planarChanges from alpha 37 to alpha 40 : * optimized : mt_xxpand vertical/horizontal/both modes are asmized
* optimized : mt_xxflate are asmized
* optimized : mt_motion with sse2
* potential fix : mt_merge with mod8 width
* potential : 64 bits build includedChanges from alpha 36 to alpha 37 : * fixed : mt_polish wasn't handling "z", "min", "max", "clip" and "round"
* added : mt_infix, which convert from polish to infix notation
* changed : built with MSVC 2008Changes from alpha 35 to alpha 36 : * fixed : "pi" wasn't properly defined for all lutsChanges from alpha 34 to alpha 35 : * added : mt_lutspaChanges from alpha 32 to alpha 34: * added : support for interleaved2planar hack, enabling 422 support
* changed : both avisynth 2.5 and 2.6 version are builtChange from alpha 31 to 32 * added : mt_lutxyz
* added : mt_lutsx
* fixed : small memory leak in mt_lutsChange from alpha 30 to alpha 31 * fixed : mt_hysteresis was randomly crashing.
* fixed : mt_polish is back.
* added : round, clip, min, max and = for lut.
* adapted : to msvc8 / yasm.Change from alpha 29 to alpha 30 * fixed : luts was crashing if some pixels didn't have any neighbours in the pixels list.
* added : mt_freerectangle, mt_freeellipse and mt_freelosange helpers.Change from alpha 28 to alpha 29 * fixed : intern float to integer conversion that were badly rounding negative
number. That resulted in -1.0 been rounded into 0 (!). Most notably affected was
mt_convolution. Thanks redfordxx for pointing that out.
Change from alpha 27 to alpha 28 * fixed : asm optimizations for mt_inpand/mt_expand/mt_edge ( mostly )Changed from alpha 26 to alpha 27 : * fixed : mt_binarize asm optimizations that borked with some thresholdsChanged from alpha 25 to alpha 26 : * fixed : avs closing issueChanged from alpha 24 to alpha 25 : * added : new html documentation.
* fixed : wrong frame issue.
* fixed : mt_merge with luma=true.Changed from alpha 23 to alpha 24 : * fixed : issues with MT.dll ( thanks tsp, Boulder, vanessam and all those who suffered the bug )
* fixed : check for YV12 colorspace, and report an error if it isn't ( thanks Boulder )
* speed up : median mode for luts ( once again, thanks to tsp )Changelog from alpha 22 to alpha 23: * fix & speed up : median mode, thanks to tsp's insightful remarks. Note to self : think
less like a mathematician, and more like a programmer. Simpler, faster & not bugged.Changelog from alpha 21 to alpha 22 : * added : "med"/"median" mode to luts/lutf
* changed : luts doesn't necessarily consider the center pixel
* changed back : forms helpers prepends (0, 0).
* changed : forms helpers now have a bool "zero" parameter, defaulted to true
* added : bool "luma" parameter to mt_merge, which makes it use the luma mask for
all three planes, and which forces chroma modes to "process" ( u=v=3 )Changelog from alpha 20 to alpha 21 * fixed : some filters were requesting wrong frames, thus creating ghostsChangelog from alpha 19 to alpha 20 : * bugfix releaseChangelog from alpha 18 to alpha 19 : * code refactoring
* fixed : bug with asm and width lower than 64
* fixed : doesn't prepend (0, 0) pixel to the forms helpers
* added : "min/max" mode to mt_edge. The edge value is local max - local min ( taken on a
3x3 square ).
* added : mt_lutf : a frame lut
* added : mt_luts : a spatial lutChangelog from alpha 17 to alpha 18 : * added : mt_makediff, mt_adddiff, mt_average and mt_clamp, ported from mg262's
limitedsupport plugin. The asm code is his, though it has been ported to nasm. They
respectively amount to MakeDiff, AddDiff, SimpleAverage and Clamp.
* added : mt_edge : "prewitt" kernel, taken from mg262's Prewitt filter. Unlike mg262's filter,
there's no multiplier ( it's always 1 ), but mt_edge's thresholds still apply. Results,
and speed, are identical except for the borders, which are now filtered.
* added : "chroma" parameter, taken from mg262's excellent idea. It's a string that,
if used, overrides U and V values. It can be either "process", "copy", "copy first",
"copy second" or a number. "copy" and "copy second" work alike.
* added : vmToon-0.74, adapted to masktools 2.0.
* added : LimitedSharpenFaster, with LimitedSupport functions imported into the masktools.Changelog from alpha 16 to alpha 17 : * changed : behavior of mt_edge with a custom kernel : the automatic normalization factor
is now the sum of the absolute value of the coefficients, ceiled to the next power of two
if that power is <= 128 ( else, it isn't ceiled ).
* added : cartoon mode for mt_edge
* added : modified mfToon script, for masktools v2. mfToonLite's speed goes from 30 fps
to 70 fps, mfToon from 4.5 to 6.5.Changelog from alpha 15 to alpha 16 : * fixed : some asm code used in invert, binarize and memset to a particular value.
Bug made the first 8 pixels of the picture to be incorrect. Also, avoid another nasty issue
that arise when cropping ( not my fault this time, though ).Changelog from alpha 14 to alpha 15 : * fixed : bugs from inflate & deflate ( thx you know you )
* reversed : inflate and deflate now match their masktools' v1 counterparts' behavior.
( if anybody used the new buggy one, let him speak quickly )Changelog from alpha 13 to alpha 14 : * fixed : random crashes with some width and asm functions ( thx Didee )Changelog from alpha 12 to alpha 13 * fixed : mt_merge order swapped for mask operation ( no comment... )Changelog from alpha 11 to alpha 12 * fixed : bug with some width ( mod4 ) for the non processing mode ( != 1 or 3 )
* changed : mt_merge order swapped for mask operationChangelog from alpha 10 to alpha 11 * fixed : mt_convolution's multiple instanciation bugChangelog from alpha 9 to alpha 10 * fixed : offY was always set to offX
* fixed : offsets quirk
* fixed : mt_convolution was crashing with floats
* changed : luts' equal operator is now equivalent to abs(x - y) < 0.000001
* added : bool saturate(true) parameter to mt_convolution
* added : float total(1.0) parameter to mt_convolutionChangelog from alpha 8 to alpha 9 * fixed : mt_lut, mt_lutxy : even faster loading
* fixed : mt_convolution : negative coefficients were offseted by 1
* fixed : mt_convolution : division by zero if the sum of the coefficients was 0.Changelog from alpha 7 to alpha 8 : * fixed : mt_edge in custom mode wasn't working properly
* fixed : mt_edge in custom mode, optimized wasn't working properly either
* fixed : mt_lutxy was slow to load, it's better nowChangelog from alpha 6 to alpha 7 : * fixed : forgot to add functions to the parser. Thanks Didee for pointing that outChangelog from alpha 5 to alpha 6 * fixed : mt_polish ( sin(x+y) wasn't properly converted, while sin((x+y)) was)Changelog from alpha 4 to alpha 5 * added : helpers for creating string for inpand / expand custom modes :
- mt_circle
- mt_square
- mt_diamond
- mt_ellipse
- mt_rectangle
- mt_losange
* added : helper for lut : consersion from infix to reverse polish notation :
- mt_polishChangelog from alpha 3 to alpha 4 * Added : custom modes for inpand / expandChangelog from alpha 2 to alpha 3 : * Fixed : mt_invert, mt_binarize, mt_lutxy, which weren't working properly anymore
* Fixed : offset created by incorrect rounding in mt_convolution
* Fixed : mmx version of edges filters ( soft thresholding, and roberts )
* Fixed : mmx version of motion edge ( soft thresholding )
* added : mt_mappedblurChangelog from alpha 1 to alpha 2 : * added functions to luts : sin, abs, cos, tan, exp, log, acos, atan, asin
* added "vertical", "horizontal" and "both" mode to mt_inpand / mt_expand
* added mt_convolution
* fixed mt_merge behavior for y, u, v = 2.
* added y, u, v = 4, for masked merge : copy the second clip channel. It's worth for any two clips input filters.
* internal changes ( code reorganization )Edit : url updated

Mug Funky
21st August 2005, 06:39
w00t! just d/l'd and i'll check it out ASAP.

unskinnyboy
21st August 2005, 15:20
Awesome! On it!

unskinnyboy
21st August 2005, 22:54
@Manao: This version doesn't seem to work with LimitedSharpen. I get this:

http://img394.imageshack.us/img394/5486/masktoolserror0gg.jpg

Usually this error comes when the MaskTools are not updated (?). But here, is it because of the change in Luts? How do I get this to work with LimitedSharpen now? :(

P.S: I hope I posted in the right place.

scharfis_brain
21st August 2005, 23:22
Uhm, read Manaos 1st post more carefully.
Read the readme of Masktools 2.0a

Didée
21st August 2005, 23:25
unskinnyboy - read the txt in the package, it cannot work out-of-the-box. All filter names have changed, so you'd have to edit all calls to MaskTools' filters in LS by yourself.

Manao: --> :) <--
I've prepared a small feature suggestion regarding in|expand, but right now it's out of reach, on the other machine ... will post it probably on Tuesday. Basically, it's about the possibility of splitting them into horizontal/vertical operation only. Hopefully this not too extravagant. ;)

unskinnyboy
21st August 2005, 23:34
Ah ok. As I thought..wanted to confirm nonetheless..:|

@Didée, Will you be rewriting LS for this version of MaskTools? :)

AVIL
22nd August 2005, 06:13
Hi,

I've read the readme.txt file with the filters included in the new release. YV12Convolution is not ported to this new tools. I use it, and think is useful because his generality.

I tink also it could be useful a thresholded blur. A filter much like mt_inpand/mt_expand but averaging only those pixels with a value near at the center's value by, at most, a parametred threshold. The rest of the pixels will be discarded for the averaging. It can be parametred also the behaviour of the filter in the case when none neighbour went into average. By example replacing center by 0 or not touching center's value.

Anyway, that's tools are unvaluable. Thanks.

Manao
22nd August 2005, 06:21
Indeed, YV12Convolution hasn't yet been ported. It'll be, soon I guess.

For the thresholded blur, I can do it, but it already exists. The beavior you're describing looks a lot like deen(a2d / w2d / c2d) behavior, and I don't want to reinvent the wheel ( especially when the existing wheel is fast )

AVIL
22nd August 2005, 07:57
Hi,

My goal with the thresholded blur is making "edge aware" averaging. All the pixels very different to the center's one (possible edge) are completely discarded (not zeroed) from the average. For my purpose the center must be excluded also.

Convolution3D and (I suppose) Deen don't discard pixels, limit it to the threshold instead. And process the center also. The result is different, mostly if the center is very different from neighbours (isolated dots).

Manao
22nd August 2005, 08:56
Ok, in that case, I'll see what I can do.

Didée
22nd August 2005, 09:34
Quickly - -

AVIL: The idea of edge-aware averaging is certainly good, but surely it is more complex ... there arise *many* questions of what to do, what not, and why and how ...
Probably it would be a good idea to make up a separate thread for that. For sure I would participate if you make one ;)

>> Convolution3D and (I suppose) Deen don't discard pixels, limit it to the threshold instead

No. I'm pretty sure (for C3D: absolutely) that pixels within <thresh> contribute to the avaraging, and pixels outside of <thresh> do not. They are not "include-everything-and-limit-the-result" filters.
This' for both filters, and ...

>> And process the center also

both treat <thresh> based on the center pixel, of course. Deen, however, has the possibility to reduce <thresh> as pixels go farther away from the center.


Manao: What I already have thought about is, perhaps, a filter that works similar to the new edgemask-thresholding you did introduce: A kind of blur filter where, for every pixel, the thresholds of what-to-include are given by either one additional clip (thresh radius is specified by this clip) or two additional clips (by which absolute upper & lower thresholds are specified).
This would rise possibilities like selfmade edge-aware blurring (or sharpening), selfmade bilateral filtering, and probably some more I currently can't think of.

However, this definetly should be a separate filter, not part of the MaskTools, IMO.

AVIL
22nd August 2005, 11:59
@Didée

I'm trying to denoise a video with two copies. Instead of make a mix with overlay, I choose from every copy the pixel who best match an ideal value. I calculate this value averaging the neighbourgs. But the edges (and spurious pixels) distort the prediction. So I wish ignore them.

My information about C3D comes from :

Tutorial about C3D (http://avisynth.unite-video.com/plugins/Convolution3D.htm)

This page states that the surrounding pixels are used always, but with a value adequate to the threshold. And by comparating C3D with average procedure make by scripting with mvtools I agree with the author of the page.

Anyway thanks for your offer.

Didée
22nd August 2005, 13:27
No.

x1=blankclip(color=$666666,width=640,height=240).converttoyv12()
x2=blankclip(color=$AAAAAA,width=640,height=240).converttoyv12()
before=interleave(x1,x2).assumefieldbased.weave()
after=before.convolution3d(1,16,16,16,16,3,0)
interleave(before,after)
There is zero change. Period. Now try the same with Deen.

Please inform that page's author that he is spreading misinformation. (The page won't even load for me...)


edit (to Manao below): That's unfair, I had no chance to read that page ;)

Manao
22nd August 2005, 13:50
Actually, the page is correct, but both of you misanderstood it ( I cheated, I'm french :p ) : it says that all value above the threshold are replaced by the center pixel's value. So in Didee'd sample test, nothing is changed.

AVIL
23rd August 2005, 10:49
@Didée

I apologize for give a link in french. Actually, I work in a french multinational enterprise ("chez Renault") and don't mind that not everybody can read french pages.

@ all

Anyway, I'd prefer not to process the central pixel because it can be spurious. In this case, no neighbourg can be selected, and the adecuate value for my purposes is more difficult to state. Perhaps the average value of the neighbours or the median value (more edge-aware). Actually, I have resolved the process with scripting but involves 8 or 9 convolutions (fast due to yv12convolution) to separate every neighbourg in a different clip and average it with kassandro's corrector filter (for thresholded average). It works but is slow.

Bye

Manao
23rd August 2005, 10:54
Convolution is coming tonight, hopefully. But i never considered yv12convolution to be fast ( no mmx code ).

AVIL
23rd August 2005, 11:35
@Manao

Thanks for your quick response. I'd say yv12convolution is fast because the comparation with the alternative (generalconvolution) that involves colourspace conversion (RGB32 only).

Didée
23rd August 2005, 12:24
AVIL - the problem wasn't the page in french, but rather the "page not found" I was getting. >today< it loads for me, but too late ...


Manao -

>> i never considered yv12convolution to be fast ( no mmx code )

Ah. Would this answer your own wondering, time back, why I'm often using DEdgeMask where YV12Convolution would be the obvious filter? :)


Okay ... here my little suggestion for inpand and expand:

As noted, it would be nice to have the possibility to in/expand only horizontally, or only vertically. When working e.g. with comb masks, or horizontal-only/vertical-only edgemasks, the advantages are obvious.

Plus there's one thing more behind it. When internal code for one-dimensional in/expanding is available, then an additional operation could be implemented: a merging of [normal expand] + [horizontal+vertical expand].
Why? to get "round corner" expanding. Currently, a chain of 10*expand() will turn e.g. a point into a 21*21 square. With "round corner" expanding, one would get a circle of diameter 21. There are cases where this would be desireable, because the "distance" of the filtering is of equal length in all directions, then. For simple expanding, there is a distance deviation of sqrt(2) - - too long in diagonal direction.

For the case of expand, I put together a scripted variant ... of course its pretty slow, but hey, it deals for visualization only.
function expand2(clip clp, int "direction", int "Y", int "U", int "V")
{
direction = default(direction, 3)
Y = default(Y,3)
U = default(U,1)
V = default(V,1)

direction==0 ? clp.expand(Y=Y,U=U,V=V)
\ : direction==1 ? clp.expand_H(Y=Y,U=U,V=V)
\ : direction==2 ? clp.expand_V(Y=Y,U=U,V=V)
\ : direction==3 ? logic( clp.expand_H(Y=Y,U=U,V=V),
\ clp.expand_V(Y=Y,U=U,V=V),
\ "max",Y=Y,U=U,V=V)
\ : direction==4 ? yv12lutxy( clp.expand(Y=Y,U=U,V=V),
\ logic( clp.expand_H(Y=Y,U=U,V=V),
\ clp.expand_V(Y=Y,U=U,V=V),
\ "max",Y=Y,U=U,V=V),
\ "x 71 * y 100 * + 171 /",Y=Y,U=U,V=V)
\ : clp.subtitle("illegal direction :p")
}
function expand_H(clip clp, int "Y", int "U", int "V")
{
Y = default(Y,3)
U = default(U,1)
V = default(V,1)
logic( clp, logic( clp.yv12convolution("1 0 0","1",Y=Y,U=U,V=V),
\ clp.yv12convolution("0 0 1","1",Y=Y,U=U,V=V),
\ "max",Y=Y,U=U,V=V),
\ "max",Y=Y,U=U,V=V)
}
function expand_V(clip clp, int "Y", int "U", int "V")
{
Y = default(Y,3)
U = default(U,1)
V = default(V,1)
logic( clp, logic(clp.yv12convolution("1","1 0 0",Y=Y,U=U,V=V),
\ clp.yv12convolution("1","0 0 1",Y=Y,U=U,V=V),
\ "max",Y=Y,U=U,V=V),
\ "max",Y=Y,U=U,V=V)
}
Procedure:

expand2(direction=0) --> normal expand()

expand2(direction=1) --> horizontal-only expand()

expand2(direction=2) --> vertical-only expand()

expand2(direction=3) --> horizontal+vertical expand() ("triangular" effect when chaining several instances)

expand2(direction=4) --> "round corner" expand()


I think this would be sensible to implement ... in one form or the other, not necessarily the way I did above. Are there any hurdles I don't see?

Manao
23rd August 2005, 12:52
Didee : OK, so basically, you want the following kernels for inpand / expand :
1 1 111
111 1 111 111
1 1 111
That will be easy to add.

Didée
23rd August 2005, 13:07
If the plugin will run faster than above function by the same percentage as your post was shorter than mine, then it's OK :D

Oh, the longer part was about the 1 2 1 3 4 3
2 2 2 4 4 4
1 2 1 3 4 3 left kernel, or more exactly the right one. First one would be sufficient (and faster), me thinks.

Manao
23rd August 2005, 19:48
Changes from alpha 1 to alpha 2 :

* added functions to luts : sin, abs, cos, tan, exp, log, acos, atan, asin
* added "vertical", "horizontal" and "both" mode to mt_inpand / mt_expand
* added mt_convolution
* fixed mt_merge behavior for y, u, v = 2.
* added y, u, v = 4, for mt_merge : copy the second clip channel. It's usable for any two clips input filters.
* internal changes ( code reorganization )You will find it here (http://manao4.free.fr/masktools-v2.0a2.zip)

Didee : weights for morphologic operators won't be implemented ( it would complicate to much the filter, and the speed gain in comparison to other means wouldn't be worth the complication ).

kassandro
23rd August 2005, 21:16
Okay ... here my little suggestion for inpand and expand:

As noted, it would be nice to have the possibility to in/expand only horizontally, or only vertically. When working e.g. with comb masks, or horizontal-only/vertical-only edgemasks, the advantages are obvious.

Plus there's one thing more behind it. When internal code for one-dimensional in/expanding is available, then an additional operation could be implemented: a merging of [normal expand] + [horizontal+vertical expand].
Why? to get "round corner" expanding. Currently, a chain of 10*expand() will turn e.g. a point into a 21*21 square. With "round corner" expanding, one would get a circle of diameter 21. There are cases where this would be desireable, because the "distance" of the filtering is of equal length in all directions, then. For simple expanding, there is a distance deviation of sqrt(2) - - too long in diagonal direction.

The following filters can be implemented:

ShapeMax(clip input, string "Yshape", string "Ushape", string "Vshape")
ShapeMin(clip input, string "Yshape", string "Ushape", string "Vshape")
ShapeAverage(clip input, string "Yshape", string "Ushape", string "Vshape")

Here Yshape is a string containing pairs of numbers describing a shape. This shape is then translated from (0,0) to any point in the frame, then for each point the maximum over the translated shape is taken to calculate the pixel values of ShapeMax. ShapeMin and ShapeAverage are similar. Of course, for pixels near the boundary not all points of the translated shift are inside the frame. Execution time increases linearily with the number of points of the shape.
While shape strings can be written by hand, it is convenient to have generating function for such strings. It is easy to implement functions like

Circle(R)

which returns a shape string for a circle with radius R.

Mug Funky
24th August 2005, 06:51
oooh, that looks interesting. i spy a bokeh-blur filter coming :)

Manao
25th August 2005, 20:27
New version up : Alpha 3 (http://manao4.free.fr/masktools-v2.0a3.zip)

Changelog : * Fixed : mt_invert, mt_binarize, mt_lutxy, which weren't working properly anymore
* Fixed : offset created by incorrect rounding in mt_convolution
* Fixed : mmx version of edges filters ( soft thresholding, and roberts )
* Fixed : mmx version of motion edge ( soft thresholding )
* added : mt_mappedblurAs you can see, lots of fixing. My bad...

tsp
25th August 2005, 21:35
what about adding support for infix expressions instead of only the reverse polish notation?

mg262
25th August 2005, 21:48
An alternative is to allow a 256-sized (or 65536-sized) array stuffed inside a AVSValue as an argument... then people could define functions which operated on such arguments to produce new arrays, and you would have the infix "for free".

(I don't particularly want this method... I'm just throwing it in as an idea.)

Manao
25th August 2005, 22:10
what about adding support for infix expressions instead of only the reverse polish notation?Make the parser and the expression builder, i'll include it. But i'll keep using reverse polonese, i don't like parenthesis that much :)

mg262 : would work, if somebody can overload operators in avisynth script parser, which can't be done without hacking avisynth itself. So won't work. But I liked the idea.

Tomorrow morning : custom 'matrices' for inpand / expand.

kassandro
25th August 2005, 22:37
Make the parser and the expression builder, i'll include it. But i'll keep using reverse polonese, i don't like parenthesis that much :)

Avisynth has already a C like expression parser (with brackets, of course). Thus, if YV12LUTxy is incorporated into the Avisynth core, then we could use this expression parser to fill the LUTs. Then I could become a lutmaniac as well. The inverse polish notation really drives me nuts.

tsp
25th August 2005, 22:45
Make the parser and the expression builder, i'll include it. But i'll keep using reverse polonese, i don't like parenthesis that much :)

Sure I will do that. BTW is your favorit calculator a Hewlett Packard :p

mg262
25th August 2005, 22:53
This is a very quick way to build a parser:

http://www.boost.org/libs/spirit/doc/introduction.html

Manao
26th August 2005, 07:04
Alpha 4 (http://manao4.free.fr/masktools-v2.0a4.zip)

Changelog ( short ) * added : custom modes for inpand / expandEdit : boost is great, but I did write my reverse polonese 'parser' faster than I failed my attempt to compile spirit. And i don't even want to think at the time the project will take to compile if i use spirit as a parser.

Didée
26th August 2005, 09:14
Friends, christmas is very early this year :) - Very nice stuff. Everything is highly appreciated.

Oh, and I definetly vote for keeping reverse polish notation for the expressions. Working with them IMO is really easy ... and honestly said: a regular expression with 8 nested levels of parantheses, written "in one line", might give way more headaches than reverse polish ... ;)

Manao
26th August 2005, 09:19
What i'll do once i manage to compile spirit, or if somebody gives me a parser, is to make a filter that converts infix notation to polonese one. So you'll use mt_lut like that : mt_lut(yexpr = ConvertToPolonese("expr"))

Leak
26th August 2005, 11:18
polonese
You keep using this word... are you sure it means what you think it means? ;)

Polonese (http://images.google.at/images?q=polonese&btnG=x) vs. RPN (http://en.wikipedia.org/wiki/Reverse_Polish_notation)

*grins, ducks & runs* :D

Mug Funky
26th August 2005, 11:26
how about "polish remover"... hehe.

i sorta like inverse-polish too. when you get the hang of it it's quite easy (i never used a hp calculator btw, but they look cool).

kassandro
26th August 2005, 13:13
While it is easy to write parsers with postfix notation, Polish notation is against the human brain. Nobody would use Avisynth with scripts like this

16 8 -8 -32 align true = crop

A prefix parser would have been almost as easy to implement, but much more brain friendly. On the other hand infix is really the way to go.
In the early eighties FORTH was regarded as the programming language of the future. It did use postfix notation and never ever a serious application was developed with it. It didn't wonder me at all.

tsp
26th August 2005, 20:30
Kassandro good to see that I'm not the only one who thinks postfix notation is not the most readable format for humans.

Manao here is a small function you can include in masktools for the infix to postfix conversion:

// ConvertToPostfix Copyright 2005 Tonny Petersen

// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
// http://www.gnu.org/copyleft/gpl.html .

#include "avisynth.h"
#include <string>
#include <sstream>
#include <stack>

using namespace std;

AVSValue __cdecl ConvertToPostfix(AVSValue args, void* user_data, IScriptEnvironment* env)
{
const string numerics("0123456789xy");
string input = args[0].AsString();
string temp;
stringstream output;
stack<string> stringstack;
int pos=0;
int lastpos=pos;
int poplast=0;
while(string::npos!=(pos=input.find_first_of(' ',lastpos))){
temp = input.substr(lastpos,pos-lastpos);
lastpos=pos+1;
//find right parenthesis
while(string::npos !=(pos=temp.find(')'))){
poplast++;
temp.erase(pos,1);
}
//delete spaces and left paranthesis
while(string::npos !=(pos=temp.find_first_of("( "))){
temp.erase(pos,1);
}

//if number output it
if(string::npos != (numerics.find_first_of(temp)) )
{
if(string::npos != temp.find_first_of("xy")&&temp.length()>1)
stringstack.push(temp);
else
{
output<<temp<<" ";
}
}
//else push it
else
stringstack.push(temp);
//pop from stack
while(poplast)
{
poplast--;
output<<stringstack.top()<<" ";
stringstack.pop();
}
}

temp = input.substr(lastpos,input.length()-lastpos);
//find right parenthesis
while(string::npos !=(pos=temp.find(')'))){
poplast++;
temp.erase(pos,1);
}
//delete spaces and left paranthesis
while(string::npos !=(pos=temp.find_first_of("( "))){
temp.erase(pos,1);
}

//if number output it
if(string::npos != (numerics.find_first_of(temp)) )
{
if(string::npos != temp.find_first_of("xy")&&temp.length()>1)
stringstack.push(temp);
else
{
output<<temp;
if(stringstack.size()>0)
output<<" ";
}
}
//else push it
else
stringstack.push(temp);
//pop all operators from stack
while(stringstack.size())
{
poplast--;
output<<stringstack.top();
if(stringstack.size()>1)
output<<" ";
stringstack.pop();
}
input=output.str();
return env->SaveString(input.c_str(),input.length());
}

extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env) {
env->AddFunction("ConvertToPostfix","s", ConvertToPostfix, 0);
return 0;
}

mg262
26th August 2005, 20:36
@tsp,

Can I ask how the function deals with precedence?

tsp
26th August 2005, 20:47
It don't manao's parser handles that. It just converts the infix expression to a postfix expression. If that was what you meant. Ie
Contverttopostfix("20 + 1 * 10") returns "20 1 10 * +" and it's mf_lut's responsebility to get the right result out of it. Also before each number/x/y there most be a space (except the first character in the string) so "sin( 2 *( 29 + 5)) is okay but "sin(2 *(29 + 5))" is not.

Manao
26th August 2005, 20:57
tsp : thanks for the parser. But do you support ternary operators ( ? : ) ?I don't know how manao's parser handles thatWell, except for ? :, every operators are commutative. a b c ? is translated as a ? b : c.

Manao
26th August 2005, 21:12
BTW, what is infix ? It doesn't take operator's priority into account, does it ? Because if so, your parser doesn't work ( 3 * 4 + 8 * 8 returns 3 4 8 8 * + * which is ((8 * 8) + 4) * 3 ).

tsp
26th August 2005, 23:18
hmm your are right. Current the expressions is just evaluated from left to right so you have to set the parathesis the right place. I will fix that and also add support for the a?b:c notation currently it just works like a?b c -> a b c? so I only need to add support for the : . So any suggestions about the presedens. Maybe the same as c++ but does that means that ^ sin,cos,abs,log,exp etc. gets the same precedens before the / * or should maybe ^ have the highest precedens?

mg262
26th August 2005, 23:33
I would have said:

unary functions
^
* /
+ -

With unary functions you would almost always expect to put brackets after them if they take a compound argument, i.e. sin(4*x), and the above reflects this behaviour.

tsp
26th August 2005, 23:50
ok for some strange reason my calculator (a Texas Instrument 86) gives ^ the highest precedens

Manao
27th August 2005, 13:22
Ok, finally, I managed to work with spirit. I must aknowledge it's great, though it takes times to compile. Anyway, here is the new build : alpha 5 (http://manao4.free.fr/masktools-v2.0a5.zip)

Changelog : * added : helpers for creating string for inpand / expand custom modes :
- mt_circle
- mt_square
- mt_diamond
- mt_ellipse
- mt_rectangle
- mt_losange
* added : helper for lut : consersion from infix to reverse polish notation :
- mt_polish

mg262
27th August 2005, 13:30
Great! Is a losange the same as the diamond but with width and height allowed to differ?

(Not that it's really relevant but I think the English equivalent is lozenge ... it's not a word that is used very often.)

Manao
27th August 2005, 13:37
Yep, it is. I wouldn't have thought it would be spelled differently, since it's originally a french word. But that way, it sounds almost alike.

tsp
27th August 2005, 14:11
ok now it should work correct allthough I am not entirely sure how a? b+c:d+e is translated correct. I don't think it is possible to translate it correct without using the :

here is the code:

// ConvertTofix.cpp : Defines the entry point for the DLL application.
//

// ConvertToPostfix Copyright 2005 Tonny Petersen

// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
// http://www.gnu.org/copyleft/gpl.html .

#include "windows.h"
#include <string>
#include <algorithm>
#include <stack>
#include "avisynth.h"

using namespace std;

class Operator{
string _op;
int _precedens;
public:
Operator(string _operator,int precedens):_op(_operator),_precedens(precedens){};
bool operator==(const string& s) const{return s==_op;}
bool operator>=(const Operator& o) const{return _precedens>=o._precedens;}
operator string(){return _op;}
};

AVSValue __cdecl ConvertToPostFix(AVSValue args, void* user_data, IScriptEnvironment* env)
{
const string numerics("0123456789,.()");
const unsigned int NumberOfOperators=28;
Operator o[NumberOfOperators]={Operator("+",50),Operator("-",50), Operator("/",60), Operator("*",60), Operator("^",70), Operator("%",60) , Operator("&",30), Operator("|",30), Operator("°",30), Operator("!&",40),Operator("<",40), Operator("<=",40), Operator(">",40), Operator(">=",40), Operator("=",40), Operator("!=",40),
Operator("cos",80), Operator("sin",80), Operator("tan",80), Operator("acos",80), Operator("asin",80), Operator("atan",80), Operator("exp",80), Operator("log",80), Operator("abs",80), Operator("?",10),Operator(":",11),Operator("ENDOFLIST",-10)};//the last operator is a dummy operator to signal the end of the list. Also the first 2 characters of an Operator must be unique

string input = args[0].AsString();
transform (input.begin(),input.end(), input.begin(), tolower);
int pos=0;
while(string::npos !=(pos=input.find(' '))){
input.erase(pos,1);
}
string temp("");
string output;
stack<Operator> operatorstack;
for(unsigned int i=0;i<input.length();i++)
{
if(string::npos == numerics.find_first_of(input[i])&&!((input[i]=='x'||input[i]=='y')&&temp==""))
{
temp+=input[i];
Operator* result;
if((result = find(o,o+NumberOfOperators-1,temp))!=(o+NumberOfOperators-1)&&(find(o,o+NumberOfOperators-1,temp+input[i+1])==(o+NumberOfOperators-1))){
if(output.length()&&output[output.length()-1]!=' ')
output+=" ";
if(operatorstack.size()==0)
operatorstack.push(*result);
else
{
while(operatorstack.size()&&operatorstack.top()>=*result)
{
if(!(operatorstack.top()==":")){
output+=operatorstack.top();
output+=" ";
}
operatorstack.pop();
}
operatorstack.push(*result);
}
temp="";
}
}
else if(input[i]=='(')
operatorstack.push(Operator("(",-100));
else if(input[i]==')')
{
if(output.length()&&output[output.length()-1]!=' ')
output+=" ";
while(operatorstack.size()&&!(operatorstack.top()=="("))
{
output+=operatorstack.top();
output+=" ";
operatorstack.pop();
}
if(operatorstack.top()=="(")
operatorstack.pop();
}
else
output+=input[i];

}
if(operatorstack.size()&&output[output.length()-1]!=' ')
output+=" ";
while(operatorstack.size())
{
if(!(operatorstack.top()==":")){
output+=operatorstack.top();
if(operatorstack.size()>1)
output+=" ";
}
operatorstack.pop();
}
return env->SaveString(output.c_str(),output.length());
}

extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env) {
env->AddFunction("ConvertToPostFix","s", ConvertToPostFix, 0);
return 0;
}

and you don't need spaces in this version so 2*3+4*5+(6*(7+8)) is okay. Even expx is okay = exp(x)
[EDIT]
small change to the code. Should now recognise <= and >= also convert the input string to lowercase so case doesn't matter. Should parse ugly string like "E X p 23> =sIny* expX" correct

tsp
31st August 2005, 18:03
Get ConvertToPostfix here (http://www.tsp.person.dk/ConvertToPostfix.zip) if you want to try:

mg262
29th October 2005, 13:11
Quick thought for the lookup table functions: as an alternative to using a string, would it be possible to take the name of a AVISynth function like

function myfunction(int argument) #returns an integer
or
function myfunction(int first, int second) #returns an integer

And using Invoke repeatedly, build up the lookup table?

Manao
29th October 2005, 13:54
mg262 : why do you want to use avisynth functions for ? or better put, what is missing in mt_lut that I could add

@all : a new version is up, fixing the mt_polish helper ( it was having some problem with functions ) :

http://manao4.free.fr/masktools-v2.0a6.zip

mg262
29th October 2005, 18:35
Nested repeated subexpressions. For example, min(x,y) :

x y < x y ?

(I think!) This kind of thing crops up a lot in scripts, especially Didée's. In itself it is not a problem, but when these things start being nested then the string length grows exponentially for obvious reasons.

In particular, I wanted to write a filter that worked on masks of luma differences; often these are represented by adding 128, but there are advantages to using signed bytes, both for speed and simplicity. Because the input mask would nearly always come from YV12LUT, the unsigned to signed conversion could be incorporated at no speed cost -- but because you need to be careful about overflow, the resultant string could become so long that it was difficult to check its correctness.

what is missing in mt_lut that I could add
min and max would help a bit? (lambda expressions would solve everything, but that's expecting a bit much!)

Don't worry about this one too much -- I can always do the signed<-->unsigned+128 conversion in separate filter.

Manao
29th October 2005, 18:53
function min(string x, string y)
{
return "(" + x + ") < (" + y + ") ? (" + x + ") : (" + y + ")"
}

function max(string x, string y)
{
return "(" + x + ") > (" + y + ") ? (" + x + ") : (" + y + ")"
}

my_expr = min(max("x", "y"), "x")

my_expr = mt_polish(my_expr)

return messageclip(my_expr)lambda expressions would solve everythingCan you be a little more specific ? you'd want to be able to define functions in order to use them in the expression ?

Edit : BTW, the string generated for min(max(x, y), x) is x y > x y ? x < x y > x y ? x ?So, indeed, min & max might prove usefull :P

mg262
29th October 2005, 19:13
String functions will solve things nicely. Thank you!

lambda expressions would solve everythingThat wasn't really meant to be a serious suggestion -- sorry if it came across that way. Looking at postfix/prefix expressions always reminds me of LISP and variants,* which lets you create anonymous functions in the middle of expressions like this: (lambda (arg) (/ arg 50)) -- that term can be used just like any built-in function (e.g. cos). So you could write (cos 20) or ((lambda (arg) (/ arg 50)) 20). I wasn't seriously suggesting that you add something like this though -- it is not clearly necessary in this context.

*prefix not postfix, but the equivalence will be fairly clear.

I will create an appropriate string function -- probably directly postfix rather than using mt_polish. Thank you for the solution.

Didée
30th October 2005, 04:02
There seems to be a bug in the parser. On my side, multi-letter operators are not working.

last.mt_lut("x 128 - abs")

All of those "abs", "sin" and whatnotelse throw a "lut: invalid yexpr" and similar. Both for lut and lutxy.
Didn't work for me in a5, and doesn't in a6.

Manao
30th October 2005, 08:10
Fixed ( i forgot to make the parser aware of the functions :) )

Didée
30th October 2005, 10:56
Yup, much better now. Thanks a lot :)

Oh, and your signature is outdated. Still links to MT 2.0a5.

Manao
30th October 2005, 11:03
What would I do without you ? Oh, yeah, sleep :D

Socio
3rd November 2005, 02:58
unskinnyboy - read the txt in the package, it cannot work out-of-the-box. All filter names have changed, so you'd have to edit all calls to MaskTools' filters in LS by yourself.


Kind of OT:

Well I am thoroughly confused with Mano's new naming structure, there is no function called DEdgeMask. There is a function called " mt_edge" which along with mt_motion and mt_mapped "are the counterpart of EdgeMask,
DEdgeMask, DEdgeMask2 and MotionMask".

I tried changing the calls in LS from DEdgeMask to mt_edge and it did not work, so what function call do you use to replace DEdgeMask in LS?

EDIT: Didee it looks like you may need to completely re-write your DEdgeMask call in LS to make this new version of masktools work.

foxyshadis
3rd November 2005, 03:25
Kind of OT:

Well I am thoroughly confused with Mano's new naming structure, there is no function called DEdgeMask. There is a function called " mt_edge" which along with mt_motion and mt_mapped "are the counterpart of EdgeMask,
DEdgeMask, DEdgeMask2 and MotionMask".

I tried changing the calls in LS from DEdgeMask to mt_edge and it did not work, so what function call do you use to replace DEdgeMask in LS?

EDIT: Didee it looks like you may need to completely re-write your DEdgeMask call in LS to make this new version of masktools work.
Just replace with mt_edge(mode="custom matrix",y1=....). The main change is that edgemask and dedgemask were merged, mode replaces both type and matrix. If there's a divisor, it's appended to the end of the custom matrix.

mt_mapped is dedgemask2 equivalent, I guess, replacing the y/c arguments with special clips.

Socio
6th November 2005, 19:30
I got it working in LS took a litle more than just subing the names though thx for the help foxyshadis.


I have another question does the "mt" prefix in the new function names stand for multi threading?

Manao
6th November 2005, 19:33
No, it's a shortcut for MaskTools. Since both version ( v1 and v2 ) had to be usable at the same time, I had to differenciate them.

Manao
7th November 2005, 23:10
*Bump*

New build is up : http://manao4.free.fr/masktools-v2.0a8.zip

Changes from alpha 7 to alpha 8 : * fixed : mt_edge in custom mode wasn't working properly
* fixed : mt_edge in custom mode, optimized wasn't working properly either
* fixed : mt_lutxy was slow to load, it's better now

AVIL
8th November 2005, 20:51
@manao

mt_convolution don't work for me

myclip.mt_convolution(horizontal="0 1 0", vertical="-1 2 -1",u=3,v=3) left myclip x untouched.

myclip.yv12convolution(horizontal="0 1 0", vertical="-1 2 -1",u=3,v=3) does the convolution ok.

It's the same for :

myclip.mt_convolution("0 1 0","-1 2 -1",u=3,v=3)

BTW my version is 2.0 a8

Manao
8th November 2005, 21:46
AVIL : thanks for the report, it's fixed :

Changed from alpha 8 to alpha 9 : * fixed : mt_lut, mt_lutxy : even faster loading
* fixed : mt_convolution : negative coefficients were offseted by 1
* fixed : mt_convolution : division by zero if the sum of the coefficients was 0.

puffpio
8th November 2005, 22:29
the link to a9 is broken..it looks like it's not on the server

Manao
9th November 2005, 05:23
Fixed

AVIL
9th November 2005, 23:57
@Manao

mt_lutxy and mt_lut (version 2.0a9) dont work :


mt_LUTxy(myclip,myclip,"x y - abs" , "128", "128",u=3,v=3)

gives a pale green clip

yv12LUTxy(myclip,myclip,"x y - abs" , "128", "128",u=3,v=3)
gives a black clip, as spected.

mt_lut(myclip,"x 25 < 255 0 ?" , "128", "128",u=3,v=3)
gives an uniform pale green clip also

yv12lut(myclip,"x 25 < 255 0 ?" , "128", "128",u=3,v=3)
gives a binary clip, as spected.

Manao
10th November 2005, 00:07
This time, it's not a bug. Arguments should always be named to avoid all confusion. In this case, you didn't notice that I added a fourth string, "expr", in addition to "yExpr", "uExpr" and "vExpr", whose purpose is to serve as default expression if one is missing. Order is expr, yexpr, uexpr, vexpr, so vexpr is missing, replaced by the first one, and yexpr is "128".

AVIL
10th November 2005, 07:06
@manao

Sorry.

Indeed, I must read the manual BEFORE use (not AFTER how I'm accustomed)

Didée
10th November 2005, 09:40
Just a note, if anyone is scratching it's head like I was ... the "equal" operator has been changed to "==" in MT 2.x , where it was "=" in MT 1.5.x ...
"x y = 255 0 ?" --> "x y == 255 0 ?"

It's fine that way, but isn't noted anywhere ... lut description refers to the old 1.5.x documentation.

Manao
10th November 2005, 09:53
Never use that operator anyway. Numbers are floats during the lut precomputation, and you should never do a =(=) b with floats. Rather use abs(a-b) < epislon instead.

But I'll update the documentation.

Didée
10th November 2005, 10:41
When checking the hyperbolic cosecant of a complex power against <value>, sure. /*earnest face*/ :D

For direct checking of pixel values, "=" has proven to be quite handy.

"x 128 = [this] [that] ?" (a)

is readable. When instead writing

"x 128 - abs 0.00001 < [this] [that] ?" (b)

then, while we're at it anyways, why not make it completely unreadable like

"x 128 - 128 x - * 1 2.0 / ^ 1 10000 / < [this] [that] ?" (c)


Somehow I prefer variant (a), dunno ... :)

Manao
10th November 2005, 10:51
Then, I could change =(=) operator to act like x y - abs epsilon <, what do you think of that ?. Because I persist in thinking that =, as such, on float, is a bad idea. If you need, I can even export the epislon parameter ( though 0.001 should be OK for most purposes ).

AVIL
16th November 2005, 21:24
@Manao

I've found that mt_convolution lacks of parameters "total", "automatic" and "saturate".

Although I can emulate "total" parameter with a posterior mt_lut step, I don't know how to mimic saturate.

Is possible to implement this parameters in mt_convolution or i must
use yv12convolution? (or ¿they are an easy method to emulate them?)

BTW, I agree with the idea of the epsilon for the == operator. I think also that checking pixel identity is a must for the LUT tools.

Thanks.

cwolf
20th November 2005, 17:09
It seems that the parameter "offy" is being disregarded in mt_lutxy. It is assuming "offx" as "offy" because no matter what I put in "offy" it is considering the value in "offx", so the "home" point is always a square. Could you confirm this? I'm using the 2.0a9 version dated nov 8th 21:41.
Cecilia
[edit]forgot to post the script:
mt_LUTxy (last,levels(0,1,255,255,255), yexpr="y", uexpr="y", vexpr="y",offx=64,offy=344,w=120,h=64)
levels is being used here for debugging purposes only.

Manao
20th November 2005, 17:19
cwolf : well spotted, fixed, I'll soon release a new version.

AVIL : sorry for having taken so long to answer : I'll add them ( automatic will be useless though ).

Manao
20th November 2005, 18:47
*bump*

Changed from alpha 9 to alpha 10 : * fixed : offY was always set to offX
* fixed : offset quirk
* fixed : mt_convolution was crashing with floats
* changed : luts' equal operator is now equivalent to abs(x-y) < 0.000001
* added : bool saturate(true) parameter to mt_convolution
* added : float total(1.0) parameter to mt_convolution

Didée
10th December 2005, 19:14
mt_convolution still has bugs. You can create weird output and access violations with

a = last
b = mt_convolution("1","1 4 6 4 1",U=2,V=2)
c = mt_convolution("1 4 6 4 1","1",U=2,V=2)
d = mt_convolution("1","1 4 6 4 1",U=2,V=2)
\ .mt_convolution("1 4 6 4 1","1",U=2,V=2)

e = stackvertical(stackhorizontal(a,b),stackhorizontal(c,d))
f = stackvertical(stackhorizontal(a,c),stackhorizontal(b,d))

#a
#b
#c
#d
#e
#f

return( last )
so it seems mt_convolution goes crazy when it gets input that was already processed by mt_convolution.
Interesting: on its own, the single-processed clips "b" and "c" are OK. In the stacked() output of "e", the "c" clip is distorted, too. And "f" just crashes with access violation.


Then, a question about shape-strings and expand & Co:

a) inflate/deflate

The readme of mt_masktools states: "compute a local average by taking into account only the neighbourgh whose value is higher than the pixel.

The html of v1.5.x states: Inflate will compute the mean of the surrounding pixels, and will replace the value of the pixel by it only if this mean is superior to the original value of the pixel.

This is definetly not the same operation. Has the behaviour changed, or is one of the two descriptions just not correct?


b) shape strings

I don't get the right grip to them. I.e. according to the readme of mt_masktools, the string "0 0 -1 0 1 0" is equivalent to "horizontal" for inpand/expand.
How does this work? the string has 6 numbers, but expand is working on 3x3 pixels ... so I'd rather expect a string with 9 numbers. Or is this similar to the "vector" format of mt_convolution, with both strings packed into one?

Then, radii bigger than 1 are supposed to work, yes? However when producing accordingly long strings, the respective filters do ~something~, but for me it's not predictable. In the same breath, the strings produced by the helpers mt_circle, mt_square etc. I just do not understand. Perhaps the string creation is buggy, perhaps the way the strings get interpreted from other filters is buggy. Perhaps I am buggy. ;)

Manao
10th December 2005, 20:35
Ok, well spotten bug, it's fixed. For inflate / deflate, I changed the behavior ( by mistake ). I can change it back, or change current inflate / deflate and add back the old one.

For the shape : you give a list of relative coordinates : 0 0 -1 0 1 0 means (0,0), (-1,0) and (1,0). Expand can now work on any kind of "kernel", so the 3x3 size doesn't matter anymore ( though the good old 3x3 kernel is speeded up by isse optimizations ).

So : http://manao4.free.fr/masktools-v2.0a11.zip

Changes : * fixed : mt_convolution's multiple instanciation bugEdit : I almost forgot, once again, thanks a lot for your previous feedback Didee.
Edit2 : i tested prefetching the lut tables, it doesn't help on my amd64

Manao
13th December 2005, 09:31
There's a bug when a mode Y,U,V < 1 is used and the resolution of the channel is only mod4 horizontally. It'll be fixed tonight. Thanks a lot Lefungus for pointing that out.

Didée
13th December 2005, 11:01
While you're at it, could you have a look at two things:

1) mt_merge :

It seems that in comparison to MaskedMerge, mt_merge handles the input clips swapped:

MaskedMerge(a,b,m) == mt_merge(b,a,m)


2) FitY2UV :

At times I love this handy little function ... but since it uses ReduceBy2() internally, it has two small issues:

- throws an error when the input width is MOD4, but not MOD8: "Resize: YV12 width must be a multiple of 4.".
It's not such a big deal ... if one is foreseeing to use FitY2UV, one can force MOD8 as well. Still, it would be more convenient if that would work, too.

- ReduceBy2() generally produces an offset that XYZresize() doesn't. If a (perhaps even multiple) reduce'd frame is upscaled to full resolution again, this might become a problem. It would be beneficial to call a standard resizer instead of Reduce (if possible).


BTW, thank you for the clarification on the shape strings. Didn't see the wood for the trees. ;)

Manao
13th December 2005, 11:11
You can script FitY2UV ( usually, speed doesn't matter when you use FitY2UV, does it ? or am I missing sth ? )

For mt_merge, reading the source code, it seems indeed it's swapped. But isn't it the correct order ? Because I kinda remind always having trouble with MaskedMerge's order.

Didée
13th December 2005, 11:43
Well, about how a mask should be interpreted, the world falls apart in two parts:

a) Mask is interpreted as "opacity"

b) Mask is interpreted as "amount"

Personally, I am always confused by the "opacity" interpretation, as it's used in Overlay(). I'm never sure to *what* the opacity refers - does it define opacity for the base image or for the image getting overlayed, or have I to imagine the mask lying between the two layers, where the opacity tells how much image will "diffuse" through the mask?
But then, where does a mask have "full opacity" again - at Y=0, or at Y=255?

Again personally, I find the "amount" interpretation much easier to understand:

- we have a base image
- we have an image we want to overlay
- the mask tells how much copying to do: 0=copy nothing, 255=copy everything. Period.


For example, the not-famous (alas) "photographic editor" Picture Window (http://www.dl-c.com/Temp/store/store_content_pw.html) does it this way:

http://img230.imageshack.us/img230/6712/pw2masking4hx.th.png (http://img230.imageshack.us/my.php?image=pw2masking4hx.png)


Of course, both points of view are perfectly valid. For my taste, the "amount" interpretation is much more intuitive to work with (read: requires less brainpower ;) ). If you prefer the other way round (the Photoshop way) more, we'll arrange with that way, too.

Manao
13th December 2005, 13:14
OK, now I know what i swapped : I do see the mask as an amount of the frame but I apply the mask to the first clip instead of the second :). So here's a quick poll : who's for d = s1 * m + s2 * (256-m) and who's for d = s1 * (256-m) + s2 * m. Tonight I do the change, so be quick :D

mg262
13th December 2005, 13:43
I'm for Didée's "amount" implemented as shown in the screenshot. I think that is d = s1 * (256-m) + s2 * m, yes?

Didée
13th December 2005, 14:19
Yeeeeeh, that's 2 vs. 1 :D

BTW, I updated the screenshot ... named application supports 2 masks at the same time, and this way it's a better reflection of the proposal. :o

Manao
13th December 2005, 20:57
OK, 2 vs 1, you win :

http://manao4.free.fr/masktools-v2.0a12.zip

Changelog from alpha 11 to alpha 12
* fixed : bug with some width ( mod4 ) for the non processing mode ( != 1 or 3 )
* changed : mt_merge order swapped for mask operation

Alain2
13th December 2005, 22:20
Does that mean we have to (for instance) swap accordingly mt_merge clips in limitedsharpenfaster ?

Manao
13th December 2005, 22:29
That means that the clips must be in the same order as in the LimitedSharpen with MaskedMerge. Sorry for the confusion, but I hadn't realized that I swapped the order when going from 1.5.8 to 2.0a

mg262
14th December 2005, 17:08
Manao -- Thank you for the update!

Alain2,
Socio modified LimitedSharpen to use this new version of MaskTools, but I think it was running into difficulties (with LMode = 3 only) precisely due to the changed argument order. So it should be the case that the script works correctly with this new version of MaskTools.

The modified-modified version I released (limitedsharpenfaster) uses Socio's code almost everywhere, so the same should apply. I won't have time to test all this for a while, but you can do it yourself... just call something like

Subtract(LimitedSharpen(...), limitedsharpenfaster(...))
levels(128-15, 1, 128+15, 16, 235) #magnify the difference

and scroll through the result. The two scripts should return exactly the same thing, so you should get a flat grey output.

Manao
14th December 2005, 17:20
Subtract(LimitedSharpen(...), limitedsharpenfaster(...))
levels(128-15, 1, 128+15, 16, 235) #magnify the difference You certainly wanted to write mt_lutxy(LimitedSharpen(...), limitedsharpenfaster(...), "x y - 255 * 128 +", y=3, u=3, v=3), didn't you ? :D

foxyshadis
14th December 2005, 17:23
I think the new version of mt_merge broke something.


x=avisource("some.avi")
y=x.trim(200,0)
mask=x.mt_binarize(threshold=20).FitY2UV
m1=maskedmerge(x,y,mask,u=3,v=3)
m2=mt_merge(y,x,mask,u=3,v=3)
return stackhorizontal(m1,m2,mask)


m1 always gives the results I expect, m2 gives what looks like a 50/50 merge when mask is all black. Returning to 2.0a11 (and swapping parameters) gives a matching output. Happens with color and luma-only processing.

Manao
14th December 2005, 20:48
Erm... I did swapped the two input clips. Just not the good ones :D. I swapped the mask with the second clip instead of the two first clips... I'm shameful ( though I did laugh when I saw what I did :) )

Anyway, here's the fixed version : http://manao4.free.fr/masktools-v2.0a13.zip

Changelog : * fixed : mt_merge order swapped for mask operation ( no comment... )

mg262
14th December 2005, 21:29
I don't think you should be embarrassed. Since the connection between argument order and argument usage is distributed across three locations in the code:
-- string passed into AVISynth
-- Create function for the relevant filter
-- filter constructor
fiddling with parameter order is IMO very fiddly and easy to slip on -- hopefully it will be easier in 3.0. But I drift OT...

Fizick
14th December 2005, 22:36
Manao,
I am not very understand what I ask, :)
but any chance to implement not 1-pixel inflate-deflate for more general morphological open-close operations?

Manao
15th December 2005, 00:49
Fizick : that is already possible for inpand / expand : do you want that for inflate / deflate as well, or were you thinking of inpand / expand in the first place ?

Didée
15th December 2005, 01:39
Hmh ... having shapes for in/deflate would be interesting to see, but how useful are they going to be? For mask dilation, wouldn't it simply need the operation of expand(), only that each candidate pixel's value is altered by f(distance) before checking, with f = linear, cosine, gauss, etc.? And the same way, by enabling radii < 1.0 and working supersampled internally, there is (edge)mask contraction/thinning.

Fizick
15th December 2005, 18:15
Manao,
thanks, i will try read the readme. I did not try use new version.

Fizick
18th December 2005, 18:36
I tried to model morhological dilation-erosion with MVtools2. Here is example script for structure element similar to circle with diameter=5.

avisource("football.avi")
converttoyv12()
mask=mt_motion(10,10,10,10,100)
circle5=" -2 -1 -2 0 -2 1" \
+ " -1 -2 -1 -1 -1 0 -1 1 -1 2" \
+ " 0 -2 0 -1 0 0 0 1 0 2" \
+ " 1 -2 1 -1 1 0 1 1 1 2" \
+ " 2 -1 2 0 2 1 "
mask.mt_expand(255,255,mode=circle5) # dilation
mt_inpand(255,255,mode=circle5) # closing=erosion(dilation)

It works as grey morphological closing with symmetrical (circle) black (=0) structure element.
Here is some links for curious persons.
http://www.cs.kun.nl/~ths/rt2/col/h11/11morphENG.html
http://www.ph.tn.tudelft.nl/Courses/FIP/noframes/fip-Morpholo.html
Thanks, Manao!
P.S. New MT_... names are not conflicted with MT (multy threaded) plugin by TSP?

Manao
18th December 2005, 18:43
Fizick : you should have a look at the mt_circle helpers, if you plan to use larger circles. Meanwhile I'll check whether names conflict with TSP's plugin

tsp
18th December 2005, 19:52
the only function I use in mt.dll is MT() as mt_ is just a prefix in masktool I don't think there will be any name conflicts problem.

AVIL
20th December 2005, 21:29
@Manao

A question about mt_edge and the rest of the mask. ¿What is the behaviour if the result of the convolution is negative or greater 255?. ¿Would be useful a parameter "bias" like in generalconvolution or "saturate" like in mt_convolution?.

Thanks

Manao
20th December 2005, 21:43
mt_edge computes the absolute value of the convolution. The kernel can be normalized, so it can be made in order not to go over 255. Default kernels are normalized that way. If you don't specify a normalization value in the custom kernel, a value is computed in order the absolute value not to go over 255, though it's overnormalized ( hence 255 most probably be reached )

AVIL
21st December 2005, 07:18
@Manao

Thanks

Neil Lee
23rd December 2005, 21:13
This is a usage Q but Knowing this could be a potential bug
so I'll post it here. relocate if deemed to.

I tried to use merge funtion in MaskTool (both MaskedMerge & mt_merge)
but never got the result I expected, so I ran a simple test.
can anyone tell me what's wrong or maybe Mt_Merge/MaskedMerge has bugs?

green vid (10 K) (http://dabadee.hypermart.net/mvtool/green.avi)

red vid (10 K) (http://dabadee.hypermart.net/mvtool/red.avi)

bw vid (10 K) (http://dabadee.hypermart.net/mvtool/bw.avi)

Base
http://dabadee.hypermart.net/mvtool/green.jpg

Overlay
http://dabadee.hypermart.net/mvtool/red.jpg

Mask
http://dabadee.hypermart.net/mvtool/bw.jpg

Expecting a Green and Red vid but the OUTPUT IS An ALL RED

Result
http://dabadee.hypermart.net/mvtool/red.jpg

--------------------------------------------------------
loadplugin("C:\delogo-FTV\masktools.dll")
loadplugin("C:\delogo-FTV\mt_masktools.dll")

base=AviSource("G:\red.avi")
overlay=AviSource("G:\green.avi")
mask=AviSource("G:\bw.avi")

base=converttoyv12(base)
overlay=converttoyv12(overlay)
mask=converttoyv12(mask)

output=mt_merge(base , overlay , mask)

return output
---------------------------------------------------------

Manao
23rd December 2005, 22:27
Channels Y, U and V are independant in the masktools, and, by default, chroma isn't processed. In your case, black amounts to Y=0, u=128, v=128, white to y=255, u=128, v=128, so U & V channels will be blended if they are processed.

A channel will be processed if you add the option y=3, or u=3, or v=3 in the filter's parameters ( for example, in your case, you'll want to do mt_merge(source, overlay, mask, y=3, u=3, v=3) ), have a deeper look in the (too short) documentation provided ( hint : the old documentation that comes with the masktools v1.5.8 explains the concept, you might want to get it ).

Finally, in your case, it's not a black & white mask that you want, but a dark green ( y=0, u=0, v=0 ) & bright pink ( y=255, u=255, v=255 ). Usually, when having a greyscale mask, you can obtain a mask that applies to all three channels by using ytouv.

AVIL
31st December 2005, 12:47
@Manao

I've found, using mt_merge, that chroma processing is the same using modes 2 and 3 for both u and v parameters.

i.e.

mt_merge(clip1,clip2,mask,u=2,v=2) and mt_merge(clip1,clip2,mask,u=3,v=3) yields the same result.

I've expected that in the first case, chroma comes from first clip and in the second case chroma where obtained from both clip according to the mask.
¿What is the actual processing of the chroma in this filter? (Chroma proccessing is not mentioned in the documentation for mt_mege nor for maskedmerge)

Thanks

Manao
31st December 2005, 14:10
Firstly, chroma is processed independantly from luma ( so the chroma mask applies, not the luma one ). Secondly, modes should work the same, i.e 1 trashes, 2 copies the first, 3 processes, and 4 copies the second. If you observe another behavior, it means there's a bug, but I'd be rather surprised, since I took care last time to check all that.

Didée
31st December 2005, 19:01
Quirk in chroma processing of in/expand & in/deflate:

wdth = 656 # <-- toy around & have fun
hght = 480

a = blankclip( width=wdth, height=hght, pixel_type="yv12" )
b = a.mt_expand( U=3, V=3 )

return( b )

This' my last nagging this year, promised. :)

Manao
1st January 2006, 12:20
Thanks a lot, once again

http://manao4.free.fr/masktools-v2.0a14.zip

Changes from alpha 13 to alpha 14 : * fixed : random crashes with some width and asm functions ( thx Didee )

Didée
5th January 2006, 20:48
Many thanks for fixing last year's bug ... now let's proceed with this year's ones ... :D

Bug in mt_inflate / mt_deflate:

somemask = blankclip(width=80,height=24,pixel_type="yv12").subtitle(" . o + !")
\ .greyscale.addborders(56,36,56,36)

expandold = somemask.expand().expand().expand().greyscale()
expandnew = somemask.mt_expand().mt_expand().mt_expand().greyscale()
inflateold = somemask.inflate().inflate().inflate().greyscale()
inflatenew = somemask.mt_inflate().mt_inflate().mt_inflate().greyscale()
deflateold = expandold.deflate().deflate().deflate().greyscale()
deflatenew = expandold.mt_deflate().mt_deflate().mt_deflate().greyscale()

expandoldD = yv12subtract(somemask,expandold)
expandnewD = yv12subtract(somemask,expandnew)
inflateoldD = yv12subtract(somemask,inflateold)
inflatenewD = yv12subtract(somemask,inflatenew)
deflateoldD = yv12subtract(expandold,deflateold)
deflatenewD = yv12subtract(expandold,deflatenew)

stackhorizontal( stackvertical( somemask.subtitle("source"),
\ inflateold.subtitle("inflate (old)"),
\ inflatenew.subtitle("inflate (new)").addborders(0,0,0,16,color=$FFFFFF),
\ expandold.subtitle("source2"),
\ deflateold.subtitle("deflate (old)"),
\ deflatenew.subtitle("deflate (new)")
\ ),
\ stackvertical( somemask, inflateoldD,
\ inflatenewD.addborders(0,0,0,16,color=$FFFFFF),
\ expandold, deflateoldD, deflatenewD)
\ )

http://img445.imageshack.us/img445/2407/bugmt2inflate4ef.png


BTW, may I suggest to rename mt_inflate to perhaps mt_inflate2 or something, and to restore the old functionality of inflate? While frankly i don't like either of them too much (old one's effect is too weak, new one's effect is too strong), the new behaviour of mt_inflate could severely break scripts when porting them from MT v1.5.8 to MT v2.0. (For example, mf's HQDering would become a joke when replacing inflate with the current mt_inflate.)

Manao
5th January 2006, 22:10
Damned you :p

http://manao4.free.fr/masktools-v2.0a15.zip

Changes from alpha 14 to alpha 15 : * fixed : bugs from inflate & deflate ( thx you know you )
* reversed : inflate and deflate now match their masktools v1 counterparts' behavior.
( if anybody used the new buggy one, let him speak quickly )

PS: Didee, you're a god send for a developper.

Manao
7th January 2006, 12:05
Yet another bugfix ( will it ever end ? )

http://manao4.free.fr/masktools-v2.0a16.zip

Changes from alpha 15 to alpha 16 : * fixed : some asm code used in invert, binarize and memset to a particular value.
Bug made the first 8 pixels of the picture to be incorrect. Also, avoid another nasty issue
that arise when cropping ( not my fault this time, though ).Thanks Lefungus for finding that one.

Revgen
7th January 2006, 18:42
Yet another bugfix ( will it ever end ? )


Not as long as it's called "alpha";)

Manao
7th January 2006, 18:55
I'll not deprive Didee of the pleasure of finding bugs :)

And there're still filters in the masktools for which bugs haven't been found. Since it's far too unlikely that they don't have bug, I can't decently rebrand it "beta" or something else.

foxyshadis
8th January 2006, 08:05
Hate t' bother ya, but I found a new discrepancy I'm surprised hasn't showed up yet. Can you compare the output of:

DEdgemask(0,255,0,255,"100 0 0 0 0 0 0 0 0")
and
mt_edge("100 0 0 0 0 0 0 0 0",0,255,0,255)

Then compare with 100 tacked on the end. It seems the new one uses 128 as the divisor for some reason.

Manao
8th January 2006, 09:09
Indeed, it does, but it's a wanted feature, for once :)

The thing is, 100 would require to divide by 100, while 128 merely require a shift, which is both faster and would enable mmx optimizations ( see later why it doesn't )

So, the hidden behavior of the filter is the following :
* If you specify a divisor, it'll use it. No mmx is allowed.
* If you don't, it'll use the closest next power of 2 of the sum of the absolute value of the coefficients. If that value is <= 64, a mmx version will be used. So in your case, it's not the mmx version that is used.

At the cost of a small unaccuracy in the division, I can do a mmx version with an emulated division. But when I designed the filter, I didn't want to bother with that ( and it would be slower than the shift one )

In any case, I can change the behavior so that if no mmx is possible, the "correct" divisor could be used. I can also correct the bug that you'd have noticed in the end ( if the sum is higher than 256, it chooses 1 as automatic divisor )

foxyshadis
8th January 2006, 10:34
Hmm, even using "8 0 0 0 8 0 0 0 0" I get much darker results than if I add a 16 to the end. It's using 32 for that one. "16 0 0 0 0 0 0 0 0" works fine however.

I did miss the power of 2 line in the readme, sorry about that.

Manao
8th January 2006, 10:46
I didn't even remember having written that in the readme, so don't feel sorry ( anyway, even in my best day, I wouldn't call that a readme )

Anyway, "ceiled to the closest power of 2" --> 16 is ceiled to 32. It was wanted, by design, but thinking about it, the reasons for which I wanted that aren't that good ( or, rather, I don't remember why the hell did I force such a constraint, it might have been something along the lines "they don't care about the normalization factor, so lets choose one that pleases me, and lets take a huge useless security margin to avoid to have to think about whether or not the computation overflows" ;) ).

So I'll think a bit more about it, and change it if it's useless.

foxyshadis
8th January 2006, 11:44
But... 16 is a power of 2. I think I see what you're saying about overflow though, is it actually a big danger? The way it is now it pretty much by design will never use the expected normalization. (And oops, I was comparing two different things, I guess "16 0 0..." is the same way.)

If I specify a power-of-two value, will it use the mmx codepath?

Manao
8th January 2006, 17:27
Yes, it will use mmx if it can.

I removed the silly limitation ( 16 isn't changed into 32 ), and added some candies.

http://manao4.free.fr/masktools-v2.0a17.zip

Changes from alpha 16 to alpha 17 : * changed : behavior of mt_edge with a custom kernel : the automatic normalization factor
is now the sum of the absolute value of the coefficients, ceiled to the next power of two
if that power is <= 128 ( else, it isn't ceiled ).
* added : cartoon mode for mt_edge
* added : modified mfToon script, for masktools v2. mfToonLite's speed goes from 30 fps
to 70 fps, mfToon from 4.5 to 6.5.

The script is based on mfToon v0.53, it doesn't give a binary identic output, because of the bug in the previous masktools that I definitely don't want to emulate. But it looks alike.

Egh
9th January 2006, 01:40
http://manao4.free.fr/masktools-v2.0a17.zip

* added : cartoon mode for mt_edge



A lamish question: what is cartoon mode for?

And more important: is there a mirror for new builds?
E.g. currently i can't access the site to grab last build... ^^

Didée
9th January 2006, 02:28
Temporarily mirrored: MaskTools 2.0a17 (http://home.arcor.de/dhanselmann/_stuff/masktools-v2.0a17.zip)

mg262
12th January 2006, 19:40
Manao,

I just saw this on another thread (http://forum.doom9.org/showthread.php?p=766793#post766793):

mt_merge(NR,some_other_clip,MyMoMask.fity2uv(),U=3,V=3)

And it made me think that actually this is quite a common usage... having a grayscale (i.e. ideally Y8, luma only) mask and wanting to use it to merge all the planes of two other planar clips. Would you consider it as an addition to MaskTools :)?

Manao
12th January 2006, 19:58
I might. It doesn't go well into the framework I designed, but that can be changed, and I'll have to write another mmx function to process efficiently the chroma channels, so it may take some times. Most of all, I'll have to think of a new parameter name (*sigh*).

Manao
14th January 2006, 21:43
Ok, new version is up. I asked mg262 if I could include his LimitedSupport filters into the masktools, and he kindly agreed. Hopefully, the conversion was made without new bug.

In addition, I put inside the zip "Limitedsharpenfaster.avsi", adapted to these filters. Finally, mg262's great idea about a "chroma" parameter has also been added.

I didn't forget his request for mt_merge, it'll come soon I guess.

http://manao4.free.fr/masktools-v2.0a18.zip

Changelog from alpha 17 to alpha 18 : * added : mt_makediff, mt_adddiff, mt_average and mt_clamp, ported from mg262's
limitedsupport plugin. The asm code is his, though it has been ported to nasm. They
respectively amount to MakeDiff, AddDiff, SimpleAverage and Clamp.
* added : mt_edge : "prewitt" kernel, taken from mg262's Prewitt filter. Unlike mg262's filter,
there's no multiplier ( it's always 1 ), but mt_edge's thresholds still apply. Results,
and speed, are identical except for the borders, which are now filtered.
* added : "chroma" parameter, taken from mg262's excellent idea. It's a string that,
if used, overrides U and V values. It can be either "process", "copy", "copy first",
"copy second" or a number. "copy" and "copy second" work alike.
* added : vmToon-0.74, adapted to masktools 2.0.
* added : LimitedSharpenFaster, with LimitedSupport functions imported into the masktools.

aberforthsgoat
20th January 2006, 08:07
Say Manao,

I'm getting an error message now: "there is no function named 'mt_average.'" I'm guessing that this is one of the parts you have ported from mg262 - have I done something wrong?

Mike

Manao
20th January 2006, 09:18
Did you properly replaced the old mt_masktools.dll by the new one ? Because I don't have the problem on my computer.

aberforthsgoat
20th January 2006, 09:38
Did you properly replaced the old mt_masktools.dll by the new one ? Because I don't have the problem on my computer.

Aaargh!! - I just checked the timestamp on the new dll - and I think I pulled a pretty swift trick: Instead of copying the new dll into my plugin directory, I think I copied the old dll into the download directory, overwriting the old one. A downloaded again, and life seems to be improving.

Sorry for the mix up,

Mike

Didée
20th January 2006, 21:39
Hi again,

and today's bug is ... drummroll ... none! (I didn't search :D )

But I've a suggestion for a certain computation, which should or could fit well into mt_edge:

One thing I seem to do rather often is the following:
mt_lutxy(clp.mt_expand(),clp.mt_inpand,"x y - [factor] *")
(at times also for chroma).

Basically this is an edge mask, at least it looks like one. But in contrast to most other edgemasks, this one delivers a well defined result: the "span", or the value range, that is covered by the pixels in a 3x3 neighborhood.
While at times it deals well as a simply-an-edgemask, it might be of interest when doing comparisons between two clips. (Actually it is, surprise ;) )

Scripting it is obviously no problem. But I think it would run *way* faster with a dedicated implementation. When scripted, there are two 3x3 kernel operations to be done, plus a 2-clip lookup. But the required minimum is only one 3x3 kernel operation, anything more is unnecessary overhead. (And when doing lots of comparisons, it will count.)

What doesn't fit so well into mt_edge's framework is the [factor] thingy, I see. But then, that one most probably is only for purposes of visualization, hence could be done with an additional mt_lut, or later on when an actual comparison is done with mt_lutxy.
The important thing would be to do the funky "Lutxy(expand,inpand)" in one loop.

End of suggestion. :)

Manao
20th January 2006, 21:57
Suggestion noted. Actually, I rather like the edge mask built by expand - inpand, and used it back in the time when I was actually encoding things.

I'm still in the process of cleaning up a bit my framework, in order to make easily and cleanly possible mg262's mt_merge filter that applies directly the luma mask to all three components, so it might take a while ( well, actually, i don't know, it might be fast too ^^ ).

BTW, I was also thinking of another filter, more generic this time. Lets say you give it a list of pixels, a lut ( to apply to all these pixels, taking the central pixel's value into account ), and a way of collecting the result ( average, median, min, max, variance, whatever ( why not even a matrix )). You end up with a filter that gives you quite a lot of liberties, though it'll be slow. But I'm sure you would find a use to such a thing, wouldn't you ? ;)

Didée
20th January 2006, 22:36
Heya, that sounds interesting. However much more complicated than anything I ever would even dare to suggest ;)
Though right now, I don't see what is "a list of pixels" ?

Smells like the way to a solution to a problem that's always buggin' me: evaluation of "spatial correlation" properties. (Imagine you build a signed difference of two clips - with the naked eye, you see immediately where the difference is just noise, and where there are real "structures" in the difference map ... but forcing a dumb-as-grass computer to properly reckognize this is not all that trivial.)

Go on, Manao. We're all on edge.

Manao
20th January 2006, 23:32
Though right now, I don't see what is "a list of pixels"It's the list of the surrounding pixels you want to take into account. Basically, it's the same thing than inpand/expand's custom kernels. But instead of doing what inpand / expand do ( ie, finding the min / max of the list of surrounding pixels ), that one will let you choose what you want to find ( well, almost ).

Manao
21st January 2006, 17:27
Ok, finally, it was sooner than later. Here's a new version :

http://manao4.free.fr/masktools-v2.0a19.zip

Changes from alpha 18 to alpha 19 : * code refactoring
* fixed : bug with asm and width lower than 64
* fixed : doesn't prepend (0, 0) pixel to the forms helpers
* added : "min/max" mode to mt_edge. The edge value is local max - local min ( taken on a
3x3 square ).
* added : mt_lutf : a frame lut
* added : mt_luts : a spatial lut
And here is the documentation for the new filters * mt_lutf : clip, clip, string mode("avg"), string expr("y"), string yexpr("y"), string uexpr("y"), string vexpr("y")
+ mt_lutf takes two clips into account. It'll compute the "mode" operation over the
pixels of the first clip, and then apply the lut on the second clip, with x = computed "mode"
value, and y the usual lut variable. "mode" can be "avg", "std", "min", "max", and
"range" = "max" - "min".

* mt_luts : clip, clip, string mode("avg"), string pixels(""), string expr("x"), string yexpr("x"), string uexpr("x"), string vexpr("x")
+ mt_luts takes two clips into account. It'll compute the "mode" operation over the
result of the lut expression, with the pixel of the first clip as x, and the neighbouring
pixel of the second clip as y. Since that doesn't make any sense when explained so bluntly,
lets give some examples :
- mt_luts( c1, c1, mode = "avg", pixels = mt_square( 1 ), expr = "y" ) does a convolution
by a 3x3 kernel filled with ones.
- mt_luts( c1, c1, mode = "min", pixels = mt_square( 1 ), expr = "y" ) does an inpand
- mt_luts( c1, c1, mode = "range", pixels = mt_square( 1 ), expr = "y" ) does a
mt_edge( mode = "min/max" )
- mt_luts( c1, c1, mode = "std", pixels = mt_square( 1 ), expr = "y" ) gives the local
standard deviation of the clip
- mt_luts( c1, c1, mode = "max", pixels = mt_square( 1 ), expr = "x y - abs" ) gives
the maximum difference between the surrounding pixels and the center.
As you can see, the "modes" play a great part in the behavior of the filter. I wasn't really inspired when I created those 5 modes, so feel free to bug me whenever you find an interesting idea for them.

Manao
21st January 2006, 19:35
Mmm, I borked something just before releasing it. I erased some files and restored them to an incorrect version. That resulted in most filters being mainly borked...

I'll correct that ASAP.

Manao
21st January 2006, 20:15
Fixed : http://manao4.free.fr/masktools-v2.0a20.zip

Didée
21st January 2006, 20:34
Huh, that was fast! And what nice things to play with - if I only think of how dreadful it was to juggle around with masks to get something ~similar~ like standard deviation ... :rolleyes:

A bunch of new possibilities has opened (... though it might take some time to actually realize all of 'em).

Many many thanks, Manao!

foxyshadis
22nd January 2006, 08:17
http://forum.doom9.org/showthread.php?p=772816#post772816

Can you check this out, Manao? I haven't had time to investigate whether it was a script translation error or actual filter error for certain.

Manao
22nd January 2006, 10:06
Thanks for pointing it out

http://manao4.free.fr/masktools-v2.0a21.zip

Changed from alpha 20 to alpha 21 : * fixed : two & three input clips filters where requesting wrong frames
leading to ghost artefacts.

The script is ok, so whenever an issue arises, it's a bug on my side.

While debugging that issue, I found out something disturbing. The result of the script was fine, except for frames #89, #119, #149 and so on. I'll investigate some more, because I don't know yet what I'm doing wrong. The 2.0a18 version doesn't seem to suffer that issue ( though it's quite hard to found, and for all I know, might be somehow random ). So, except for those wanting to play with the new filters, I strongly advise to come back to that version. Else, using SetMemoryMax to increase avisynth's cache also solved the issue ( which means it would reappear with a bigger script... )

Manao
22nd January 2006, 11:36
Ok, false alarm, it was my avisynth.dll that was buggy. Hint to everyone, use latest avisynth ( 2.5.6 RC2 ) when you use complicated scripts :p

So 2.0a21 is fit to be used ( till the next bug :p )

AVIL
23rd January 2006, 21:03
@Manao

I'm playing with the new function mt_luts and I wish make some questions.

1st. If I use pixels=mt_square( 2 ), the neighbouring chosen is a 5x5 matrix?
2nd. The center pixel of the second clip is used in the operation?.
3rd. What is the formula for mode "std"

Thanks

Manao
23rd January 2006, 21:10
If I use pixels=mt_square( 2 ), the neighbouring chosen is a 5x5 matrix?YesThe center pixel of the second clip is used in the operation?Yes - though it might change if needed. I actually think both way have assets and drawbacks, so in the end, both might get chosen. Also, the center pixel is always taken into account. By the way, thinking of it, you can include twice a pixel, if so, it'll be used twice by the operator - which is useless if you're using min, max or range operator, but acts like weights if used with average and standard deviation.What is the formula for mode "std"square root(average(sum of (x - average(x)) ^ 2))

Manao
23rd January 2006, 22:41
http://manao4.free.fr/masktools-v2.0a22.zip

Changelog : * added : "med"/"median" mode to luts/lutf
* changed : luts doesn't necessarily consider the center pixel
* changed back : forms helpers prepends (0, 0).
* changed : forms helpers now have a bool "zero" parameter, defaulted to true
* added : bool "luma" parameter to mt_merge, which makes it use the luma mask for
all three planes, and which forces chroma modes to "process" ( u=v=3 )

No bug fixes for once :p

Mug Funky
24th January 2006, 11:48
oops, found one :)

try:

mt_expand(mode=mt_circle(7),y=3,u=3,v=3)

it seems the middle pixel isn't being processed correctly... try it on a contrasty clip (this works for any radius).

looks to be pretty minor though.

mg262
24th January 2006, 11:53
Manao,
* added : bool "luma" parameter to mt_merge, which makes it use the luma mask for all three planes, and which forces chroma modes to "process" ( u=v=3 )
Brilliant! Thank you.

Manao
24th January 2006, 12:09
With 2.0a22 ? Because it's supposed to be fixed in a22.

Manao
24th January 2006, 21:00
Mug Funky : i rechecked, the strings created by mt_circle contain the pixel (0,0), and mt_expand and mt_expand(mt_square(1)) return the same results. Were you using 2.0a21 ?

Anyway, new release because since I released a buggy & slow median mode. Thanks for tsp for the idea that allows to speed the search :

http://manao4.free.fr/masktools-v2.0a23.zip

Changelog from alpha 22 to alpha 23 : * fix & speed up : median mode, thanks to tsp's insightful remarks. Note to self : think
less like a mathematician, and more like a programmer. Simpler, faster & not bugged.

Mr.Bitey
25th January 2006, 02:02
Hi Manao,

Repost from Limtedsharpen thread:
Im getting graphedit errors in ZoomPlayer 4.51 (causing ZP to crash-out) using limitedsharpenfaster and mask_tools v2.0a21 after a second or two of dvd playback - no problems if I roll back to v2.0a18..

Cheers,
Bitey

vanessam
27th January 2006, 18:23
Hi,
Mt don't work with version after v20.a18.

vanessam
27th January 2006, 18:25
Mt don't work with version after v2.0a18 ...

My script:
Mt("hqdn3d(3)LimitedSharpenFaster(ss_x=1.4,ss_y=1.4,Smode=3,strength=50,overshoot=7)
Converttoyv12()")

Manao
27th January 2006, 21:36
At all those having issues with masktools and mt, please have a look here, and see if you can help :

http://forum.doom9.org/showthread.php?p=776215#post776215

Boulder
27th January 2006, 22:01
I got alpha 23 to crash with this function (Didée's YLevels adjusted to 2.0) if I don't feed YV12 data in it:

function Ylevels(clip clp,
\ int "input_low", float "gamma", int "input_high",
\ int "output_low", int "output_high", bool "show_function")
{
input_low = Default(input_low, 0)
gamma = Default(gamma, 1.0)
input_high = Default(input_high, 255)
output_low = Default(output_low, 0)
output_high = Default(output_high, 255)
show_function = Default(show_function, false)

wicked = "x " +string(input_low)+ " - " +string(input_high)+ " " +string(input_low)+ " - / 1 " +string(gamma)+
\ " / ^ " +string(output_high)+ " " +string(output_low)+ " - * " +string(output_low)+ " +"

return( show_function ? clp.subtitle(wicked) : clp.mt_lut(Yexpr = wicked, U=2,V=2) )
}

http://img206.imageshack.us/img206/3181/masktools9uj.th.jpg (http://img206.imageshack.us/my.php?image=masktools9uj.jpg)

Manao
28th January 2006, 10:54
Ok, here is a new release that should hopefully work with MT :

http://manao4.free.fr/masktools-v2.0a24.zip

Changelog from alpha 23 to alpha 24 : * fixed : issues with MT.dll ( thanks tsp, Boulder, vanessam and all those who suffered the bug )
* fixed : check for YV12 colorspace, and report an error if it isn't ( thanks Boulder )
* speed up : median mode for luts ( once again, thanks to tsp )

Boulder : if that one still crashes when closing the script, I'll try to cook up another debug version with pertinent logs.

Boulder
28th January 2006, 12:04
It still crashes VDubMod. Also, the script works fine for the first couple of frames, then begins to show the frames in a random order. It looks like every other frame is in correct order, every other isn't.

Manao
28th January 2006, 13:50
S**t...

I'll have to think of the information that i need to output before making a new debug build. Meanwhile, can you :
- tell me if you're still using the same script than the one you post
- whether "crashes vdubmod" means it crashes when closing or while processing
- send me another debug log from the mt_masktools2.dll debug build. I would need only a few frames of logs, starting before the frame's order is disrupted and ending after.

Boulder
28th January 2006, 13:56
1. The same script I wrote when I emailed the log.

2. VDubMod vanishes after the script has been closed. Not immediately, but some seconds after that. If it's of any use, ffdshow's tray icon remains visible until VDubMod vanishes. Without the YLevels line, the icon won't stay there when the script is closed. (I use ffdshow's mjpeg for my captures)

3. Forgot to mention, mt_masktools2.dll produces correct frames but the vanishing VDubMod issue still remains. I couldn't make it crash while advancing through the frames at least for several hundred frames.

foxyshadis
29th January 2006, 02:09
mt_merge seems to have some corruption problems that occasionally make it grab the second clip from some random point it memory. Whatever it is it's definitely not the clip I'm feeding it. The first and the mask always look correct though. Usually it has extra black or green bleeding through the mask. I took a screen cap one time it happened:

http://foxyshadis.slightlydark.com/random/supclipd0000.jpeg

It never occurs when viewing the clips or masks alone, and isn't even remotely reproduceable (reloading usually fixes it, for a time; exiting and reopening vdub always helps keep it at bay for a while). Also I suspect that it's the cause of occasional "Cannot locate a decompressor for format "XVID"" that I get several reloads after it happens and have to reopen vdub to fix.

Oh, and a question, did you ever implement Clouded's suggestion of user-defined functions callable from the lut?

Manao
29th January 2006, 02:33
foxyshadis : what is the date of your avisynth.dll ? What happens if you upgrade to latest 2.5.6 ( iirc from october 2005 ) ?

Boulder : I still don't know what's happening to you. tsp told me he got no issues with the new dll, but we hardly had the time to speak, and I don't know how your script behaved on his computer. Perhaps more information will come during the day.

foxyshadis
29th January 2006, 04:00
12/31/05, 2.5.7-pre from tritical. Haven't seen it yet from 2.5.6a, but it usually only shows up once an hour or less. I never saw it happen with the debug, only the non-debug 23/24, so I can't get you any logs. =\ Then again, there's also the possibility that it could be a rare bug in eedi2, hard to tell.

Oh, an interesting oddity, probably related to boulder's: virtualdub doesn't close if any instances of masktools 2 are in scripts. It just sits dead in the process list sucking up memory. Tried several of the mt2 functions and they all do the same, even if they're not accessed; only commenting them out fixes. Both versions of avisynth.dll do this.

Manao
29th January 2006, 08:26
foxyshadis : for the wrong frames, I once encountered the issue, and it appeared that avisynth was giving me the wrong frames to process. That happened only with 2.5.6 from july, not 2.5.6 from october. It also didn't happen when I increased the SetMemoryMax value.

I discarded the issue as an avisynth's bug. It may be on my side, but I can't see how I could make avisynth give me the wrong frame ( yet, it's a possibility I don't discard )

I'll try with the script that was causing the bug on my side, just to see if it happens again with tsp's avisynth dll.

In any case, I don't think the bug is in eedi2.

The closing issue seems to be on my side though. I'll create another debug version. In the meantime, can you post your script ?

Oh, and a question, did you ever implement Clouded's suggestion of user-defined functions callable from the lut?No. However, I hinted some tricks to ease the writing of the luts : write functions such as :function mt_min(string "x", string"y")
{
return x + " " + y + " < " + x + " " + y + " ?"
}or likefunction mt_scale(string "x", string "old_min", string "old_max", string "new_min", string "new_max")
{
old_range = old_max + " " + old_min + " -"
new_range = new_max + " " + new_min + " -"
return x + " " + old_min + " - " + old_range + " / " + new_range + " * " + new_min + " +"
}

foxyshadis
29th January 2006, 09:13
Huh, it really doesn't like my main encoding machine and server (Athlon XP, isse/sse, server 2003 sbs sp1, latest official avisynth), everything came out garbled. Glad I don't have to give you the nasty script I was working on before, heh.


AVISource("tb14.avi").crop(0,4,0,-8)
s0=trim(0,129)
s1=trim(130,2216)
s2=trim(2217,0)

s1.blendcombs()

function BlendCombs(clip orig, bool "slow") {
assert(Defined(orig),"CLIP PLZ")
slow = default(slow,true)
orig

fe=mt_average(orig,orig)

cm=CombMask().bilinearresize(width/2,height/2).bilinearresize(width,height).mt_expand()

fm=mt_merge(orig,fe,cm.fitY2UV(),chroma="process")

return fm

}


I'm pretty sure it's happening in blendcombs, that's the only place with masktools and the crud is in the shape of the masks again. As soon as that machine is done encoding something else I'll strip the script down and retry to make sure.

(Yeah, that's what I ended up doing for the luts.)

Edit: Yup, came down to just this and still shows a mess all over with 2.5.6a. 2.5.7pre is unaffected as far as I can tell however.

Manao
29th January 2006, 12:25
Ok, I spotted another silly mistake. Thanks a lot for the script, foxyshadis, because it's indeed a real killer that systematically shows the issue :)

So, http://manao4.free.fr/masktools-v2.0a25.zip

Changelog from alpha 24 to alpha 25 : * added : new html documentation.
* fixed : wrong frame issue.
* fixed : mt_merge with luma=true.

Boulder
29th January 2006, 13:14
I did some quick testing and it looks like alpha 18 is the last one that works correctly for me with MT. The script itself doesn't crash but again, when the script is closed, ffdshow's icon remains in the lower right corner and after a while VDubMod closes by itself (after which ffdshow's icon disappears as well).

I tried with MT v0.41 plus the latest official Avisynth v2.5.6 and with MT 0.5 plus tsp's latest Avisynth build. Both behave the same way.

Manao
29th January 2006, 14:00
And here is ( hopefully ) the last bug fix. I overlooked Boulder's observation on the ffdshow icon tray not disappearing, which prevented me from recreating the bug on my side. Luckily for me, he insisted a second time on that very point :). So big thanks, Boulder

http://manao4.free.fr/masktools-v2.0a26.zip

Changelog from alpha 25 to alpha 26 : * fixed : avs closing issue

Boulder
29th January 2006, 14:17
Hehe, you wanted them bugs to crawl out :p

It seems to work perfectly, thank you!

foxyshadis
12th February 2006, 05:52
I think mt_binarize is broken. upper=true and upper=false are supposed to be inverses, right? A lot of pixels seem to fall through the cracks, though I can't tell what the pattern is.

Manao
12th February 2006, 14:07
Well spotten. It happened when threshold < max ( pixels of video - 128 ).

Fixed with the new version : http://manao4.free.fr/masktools-v2.0a27.zip

Changelog : * fixed : mt_binarize asm optimizations that borked with some thresholds

Egh
17th February 2006, 18:43
* chroma("") : allow to set the mode of both chroma channels in a more user-friendly way. Possible strings are "process" ( u=v=3 ), "copy" or "copy first" ( u=v=1 ), "copy second" ( u=v=4 ), "copy third" ( u=v=5 ), "none" ( u=v=1 ) and finally, a number "xxx" ( u=v=-xxx )


I think in the first instance it should be u=v=2, right? :P

Manao
17th February 2006, 20:43
Yes, but the documentation has been rewritten in html, and the error isn't in the html file :p

Egh
18th February 2006, 16:55
@Manao: great to know that, but in readme it's still like that :)

Also i wanted some clarifications concerning mt_edge.

Which kernel is best in quality? Is there a difference in speed between those and how much? And why despite some claims it seems that prewitt is rather imprecise?

I'm currently making my own script for edge enhancement, mostly targeted for hi-rezo things like 720p raws, and thinking which kernel to use. At the moment I think "roberts" is likely best for my purposes.

Also, can you please clarify what exactly is created by mt_expand().mt_inpand() command applied to original image? This kind of thing is used in FastLineDarken, which i rewritten from mt1.5.1 to mt2.0. So I wonder if the results now are same as before...

Manao
18th February 2006, 17:08
Lots of questions :)

Which kernel is best in qualityThey all serve different purposes.Is there a difference in speed between those and how much?Yes, there's a great difference. Roberts is the fastest, closely followed by sobel. Then comes laplace and min/max. Then comes the unoptimized one : cartoon, and prewitt.it seems that prewitt is rather impreciseCan you be a bit more explicit ? imprecise in what way ? edge position, or edge detection ? Any sample to show ?what exactly is created by mt_expand().mt_inpand()It's called a overture ( inpand.expand is a closure ). It's a common way of denoising, but it can have other uses. I don't remember well fastlinedarken script, so I don't know why it was used there. Anyway, Expand and mt_expand behave exactly in the same way, and so does Inpand and mt_inpand.

Egh
18th February 2006, 17:42
Well. It's not that prewitt is bad, it's probably better for some applications like LimitedSharpen. But for my purpose i.e. searching primarily for character's edges it's not good.

http://xs68.xs.to/pics/06076/mosk.no.png <-- original
http://xs68.xs.to/pics/06076/mosk.roberts.png <-- good but probably too thin lines
http://xs68.xs.to/pics/06076/mosk.sobel.png <-- very good :)
http://xs68.xs.to/pics/06076/mosk.prewitt.png <-- thick lines but lots of hits background, which i would like to avoid. So in short prewitt sees edges which are not good from anime point of view :) On some specific backgounds the difference between prewitt and sobel can be very substantial. Like when prewitt covers half of backround image with edges roberts/sobel hardly see any at all. So although roberts/sobel produce thinner edges, I correct that with single mt_expand operation and the result produced is much better compared to prewitt. But again, it's due to the task of correcting dark lines only.

Btw, if you're interested, that's the video sample with lines enhanced. http://rapidshare.de/files/13553656/h264.mkv.html I guess in due time i'll release a whole episode of this as well. Original raw is very good but lines are too thin and vague to my taste. mfToon is probably good but it's such a bulky monster :) The script i did works a bit slower than FLD() but still with good speed and main difference from otherwise superior FLD() is that I try to smooth the edges as well, since fld() makes them too pixelated imo. Since it's hdtv which then will be dully downsampled a bit (from 720p to 576p) i don't even use supersampling for edge correction.

Concerning that expand.inpand. That's how the same frame looks after such operation: http://xs68.xs.to/pics/06076/mosk.png
I think it's not only for denoising in FLD().

Manao
18th February 2006, 18:22
Thresholds exist to avoid false hits in the background. Play with thY1, thy2, in order to avoid false edge detection.

Applying inpand.expand on a mask also takes care of small false detection, while expand.inpand fills in the small gaps inside the edges. So inpand.expand.expand.inpand would improve the output ( and slow things down... )

Another possibility is to use mt_hysteresis. You give it two masks ( one with thin edges and no false detection, the other with thick edges but some false detection ), and it'll make one grow into another, giving the best of both world ( at least, it's supposed to ). There again, a slowdown is to be expected.

Egh
18th February 2006, 20:28
Thresholds exist to avoid false hits in the background. Play with thY1, thy2, in order to avoid false edge detection.

Another possibility is to use mt_hysteresis. You give it two masks ( one with thin edges and no false detection, the other with thick edges but some false detection ), and it'll make one grow into another, giving the best of both world ( at least, it's supposed to ). There again, a slowdown is to be expected.

No. It's not only small artefacts on background. It's a whole load of thick lines detected where i don't need them to be (not on that pix i gave, but I can show others where the diffence is really huge). So for the purposes of edge enhancement i don't think prewitt will do. Thresholds are not easily played with, since i need some specific values there. thY1 is set to 10 to avoid some small artefacts though.

And at the moment i use only mt_expand to a mask produced with sobel kernel, thus both filling small gaps and enlargening areas for additional processing. And that's rather fast. How fast (or slow) is hysteresis, btw?

Any ideas why FLD() uses that expand/inpand on the image?

P.S. why in your signature it's a26 whilst you already released a27?

foxyshadis
19th February 2006, 02:59
I recall a thread here, perhaps by clouded, wherein the effectiveness of different edgemasks was discussed. Mostly for animated stuff, both cel-shaded and painted. There are some that give even thinner lines than roberts, because it's getting only the outline's edge, not the outline as a whole (which I assume you're after). That's an important distinction, because if the outline is more than a couple pixels wide, it can be seen as a solid area with its own edges by more kernels. Hysterizing sobel into prewitt would probably help.

Then there are some (maybe they were in the thread, not sure) that are 5x5 or more, with I guess mt_luts or mt_convolution, but of course slooooooooooooow. I would link to the literature or the thread, but I can't find it right now.

Richard Berg
23rd February 2006, 04:59
Bug in 2.0a27 package - run this script:

---
Version
LimitedSharpenFaster(dest_x = 640, dest_y = 480)
---

Lots of diagonal artifacts.

Manao
23rd February 2006, 06:24
Works on my computer, if I add converttoyv12 ( version outputs RGB )

Didée
23rd February 2006, 11:07
LimitedSharpen doesn't handle RGB input correctly. It never did, in all of its versions. Only YV12 and YUY2 input are safe to use.

Richard Berg
23rd February 2006, 16:42
Ok. The version of LimitedSharpen I have works ok on that script.

foxyshadis
12th March 2006, 04:02
Manao, would you mind putting masktools html docs on your site as well, so it could be more easily linked to?

Manao
12th March 2006, 07:43
Done : http://manao4.free.fr/mt_masktools.html

foxyshadis
19th March 2006, 11:55
Posting again, you probably know why by now... Thanks for the docs though!

Looks like vmtoon shows a bug in some sources; I'd seen it reported before but now that I could repro it, I have a nice simple test case.

http://rapidshare.de/files/15864704/Inuyasha_Macroblocking.demuxed.m2v.html


mpeg2source("Inuyasha_Macroblocking.demuxed.d2v")
mt_Expand()
greyscale


It causes sliding diagonal lines on every frame, looks like some kind of off-by-8 error. Occurs with at least expand and inpand.

Manao
19th March 2006, 12:53
I still can't reproduce it :(.

Two things to try on your side : add a greyscale() in order the chroma not to trouble what you're seeing ( since with your script, chroma is completely randomized ), and try to add "mmx=false, isse=false, d3now=false" in mt_expand(), to see if results are still the same. If not, screenshots would be welcomed ( with them, with some luck, i might be able to find the possible bug ).

foxyshadis
19th March 2006, 13:15
I was using greyscale, so it wasn't chroma. isse=false fixes it. Oh, and the lutxy had nothing to do with it, just: mt_Expand() does it for me. Hm. (But not on all sources, especially smaller ones.)

http://foxyshadis.slightlydark.com/random/off.jpg

This is a core duo, I don't recall it ever happening on the Pentium M, or the AXP. (Testing now.) Hope it's not a processor bug. >_<

Edit: Tested both, no error on AXP, same error on P-M. Main difference is P-M is SSE2 and AXP is not.

Edit2: Tested with 2.5.6a and it does not show. The AXP uses it, which also explains that. I normally use 2.5.7-cvs from tritical, versions at least since january show this. So now I guess I should take the report over to tritical and IanB?

It only shows on all 720x480 sources, not 320x240 or 704x480 so far.

foxyshadis
19th March 2006, 19:34
From PM:

I'll look, but I'm guessing off hand that it is a pitch/width problem. In 2.5.6 planar frames by default get 16 byte aligned pitch on Y and 8 on chroma, but in 2.5.7 chroma gets 16 and Y gets 32 which on a 720 width frame means the pitch no longer equals the width (736 vs 720). Whereas on a 704 or 320 width frame pitch will still equal width since both are divisible by 32.

Manao
19th March 2006, 21:03
Ok, thanks again for that nice report, I found the bug as soon as I installed avs 2.5.7.

http://manao4.free.fr/masktools-v2.0a28.zip

Changelog :Fixed : asm optimizations for mt_inpand/mt_expand/mt_edge ( mostly )

IanB
19th March 2006, 23:23
As noted by Tritical, 2.5.7 defaults to mod 16 alignment (SSE2 ready) for the chroma planes and mod 32 (chroma * 2) for the luma planes. This feature was introduced in 2.5.6 but is not enabled by default.

This feature is controlled by the SetPlanarLegacyAlignment(clip, bool) control function, bool==True -> Legacy mod 8 chroma, bool==False -> Advanced mod 16 chroma.

2.5.6 developers should test their plugins for future compatibility with the feature by putting a SetPlanarLegacyAlignment(False) at the end of their script.

In 2.5.7 for non-conformant old pluggins the feature may be restored to legacy mode by putting a SetPlanarLegacyAlignment(True) after the call to the problem pluggin.

In 2.6.0 the default alignment for all planes is 16. The alignment of each plane is independant of the other planes. i.e. your code must get the pitch for each plane independantly, pitch>>=1 will not work! SetPlanarLegacyAlignment only effect YV12 chroma plane alignment, forcing it to be half that of the luma plane.

redfordxx
10th May 2006, 15:12
@Manao

Is the speed of
mt_convolution("1 1 1 1 1 1 1 1 0 0 0 0 0 0 0","1 1 1 1 1 1 1 1 0 0 0 0 0 0 0")
and
mt_convolution("1 1 1 1 1 1 1 1 0","1 1 1 1 1 1 1 1 0")
same?

Tnx

Manao
10th May 2006, 15:27
No, the filter isn't smart enough to see that zeroes are useless ( and won't, ever ).

Manao
31st May 2006, 21:07
Ok, I fixed the bug described here (http://forum.doom9.org/showthread.php?p=834822#post834822)

Changelog : * fixed : intern float to integer conversion that were badly rounding negative number.
That resulted in -1.0 been rounded into 0 (!). Most notably affected was mt_convolution.
Thanks redfordxx for pointing that out.

redfordxx
5th June 2006, 21:02
a=mt_luts(o1,o1, mode = "avg", pixels = "-1 0 1 0", expr = "y" )
b=mt_luts(o1,o1, mode = "avg", pixels = "0 -1 0 1", expr = "y" )
c=mt_luts(o1,o1, mode = "avg", pixels = "1 -1 -1 1", expr = "y" )
d=mt_luts(o1,o1, mode = "avg", pixels = "-1 -1 1 1", expr = "y" )
e=mt_luts(o1,o1, mode = "max", pixels = "1 -1 -1 1", expr = "y" )
f=mt_luts(o1,o1, mode = "max", pixels = "-1 -1 1 1", expr = "y" )

a,b,e,f works
c,d==>blankscreen in VD-M2

redfordxx
5th June 2006, 21:10
BTW: Courious:
Why mt_lutf has no pixels parameter?
It would be useful.
Workaround is mt_luts("y") followed by mt_lutxy but wouldn't it be faster?

Manao
5th June 2006, 21:30
Ok, bug found, expect a release tomorrow.

mt_lutf doesn't have a pixel parameter, because its purpose is to adapt a local mask according to the value of the property of the whole picture. I fail to see how a pixels parameter would help. Can you give me an example of what you were thinking about ?

Finally, speed shouldn't be considered when playing with luts / lutf. I didn't inted these filters to be fast, only to be tweakable. Their purpose is to allow scripters who don't know how to code to have tools to make interesting scripts. From that, one could expect interesting filter's idea to come up, which, in turn, could be implemented into real filters, that would be fast.

redfordxx
5th June 2006, 22:14
Can you give me an example of what you were thinking about ?
s=mt_luts(o1,o1, mode = "avg", pixels = "1 -1 -1 1", expr = "y" )
mt_lutxy(o1,s, expr = "x y > x y ?" )
could be same as
mt_lutf(o1,o1, mode = "avg", pixels = "1 -1 -1 1", expr = "x y > x y ?" )
which would reconstruct diagonal lines..

Their purpose is to allow scripters who don't know how to code to have tools to make interesting scripts. From that, one could expect interesting filter's idea to come up, which, in turn, could be implemented into real filters, that would be fast.Yeah, that's 100% me.
My SmoothDeblock is slow as hell (0.25fps:devil:) and all I can do is to make it even slower. But, if I have time and am lucky, there will be something working from it, and maybe some1 will c-peed up it...

redfordxx
5th June 2006, 22:20
Well - throwing ideas:
How about making

mt_freerectangle : int left(0), int top(0), int width(2), int height(2)

So for example
mt_freerectangle(0,0,8,8)
would cover 8x8block right-down from pixel x inclusive

Manao
6th June 2006, 06:36
Ok, new version is up : http://manao4.free.fr/masktools-v2.0a30.zip

Changelog : * fixed : luts was crashing if some pixels didn't have any neighbours in the pixels list.
* added : mt_freerectangle, mt_freeellipse and mt_freelosange helpers.

Manao
6th June 2006, 06:46
Concerning lutf, it doesn't work like you think. lutf collects information on the whole frame, and compute from that information a single value per frame, defined by the "mode". "avg", for example, will compute the average pixel value for the whole frame, while "range" will compute the difference between the max and the min on the whole frame.

Then, "expr" is a 2 variables lut which will be applied on the whole frame. In that lut, x is the value previously computed, while y is the value of the pixel. So I really can't add a pixel list parameter to lutf.

Concerning the mt_freeforms helpers, just a sidenote : mt_freerectangle(0, 0, 2, 2 ) will create a 3x3 rectangle ( 2 is included ), so if you want a 8x8 rectangle, use (0,0,7,7).

redfordxx
6th June 2006, 16:53
Concerning lutf, it doesn't work like you think.
Well I already know how it works, but that's why I proposed it as a change. If parameter pixels would be added, then
pixels="" ... current behavior
pixels=someshape ... behaviour like reverse luts

By the way it seems to me now that many operations of luts on square can be done faster with inpand,expand, lutxy, pointresize combo.

For example I am making a function to fill n*n pixels block with its max value with expand-pointrezize combo, because I don't know any other way how to do it. It has nice property that the larger n the faster. (Well, this fact also means that there should be faster solution;))

But generally there can be really awsome things done with mt. Nice.

Last question: only being curious, because for implementation is maybe late.
Once I realized that lut works strange and then I realized:
mt_lut("1","2","3")
is not same as
mt_lut(yexpr="1",uexpr="2",vexpr="3")

iirc the defaults in old masktools were different there were only 3 expr parameters. In new masktools are 4 expr. What was there a reason? IMHO something like
yexpr=default(yexpr,"x")
uexpr=default(uexpr,yexpr)
vexpr=default(vexpr,uexpr)
would be best....

redfordxx
15th June 2006, 22:26
Hi Manao,
it's again me --- the troublemaker.

I have a suggestion of new feature. Of course, it comes from what I do and I need and I know neither how many other users will appreciate it, nor how difficult to add this feature.

And as you are the judge, I only show what I have in mind.

IDEA: Sometimes there are more values calculated than necessary. Example: I want to calculate range value per each 8x8 block. When I do it with mt_luts("range",mt_freerectangle(0,0,7,7)...) there is calculated 64x more values than necessary, because I need only the first pixel in every block.

SUGGESTION: How about adding another optional common parameter or pair of parameters where would be set which pixels the operation should be applied to. When I should present the maximalistic version, there could be defined repeating cycle in each axis, list of pixels within the cycles to be processed and logical operator between h and v axis.

EXAMPLES:Calculating range for each 8x8 block
mt_luts("range",mt_freerectangle(0,0,7,7),applyto="h % 8 = (0) & v % 8 = (0)",...)
Calculating avg of 8x8 pixels every 4 pixels horizontaly
mt_luts("range",mt_freerectangle(0,0,7,7),applyto="h % 4 = (0)",...)
First half of deblock_qed looks like "block, block...". It could look like:
original.mt_lut(y=-255).mt_lut("0",applyto="h % 8 =(0,7) | v % 8 =(0,7)")

well..sorry for bothering...

redfordxx
3rd December 2006, 02:20
Hi Manao,
today I'll be brief. Would you consider adding a "bias" parameter for mt_convolution like in GeneralConvolution?
Would be useful in cases like
mt_convolution("0 -1 1","1",bias=128...)

until then I share for those might find useful...

function rd_convolution(clip o, string "horizontal", string "vertical", bool "saturate", float "total", int "bias", int "y", int "u", int "v")
{
bias=default(bias,0)
rdhorizontal=default(horizontal,"1 1 1")
rdvertical=default(vertical,"1 1 1")
rdsaturate=default(saturate,true)
rdtotal=default(total,1.0)
rdy=default(y,3)
rdu=default(u,1)
rdv=default(v,1)
p=o.mt_convolution(rdhorizontal, rdvertical, bias==0 ? rdsaturate : true, rdtotal, rdy, rdu, rdv)
a= bias==0 ? p : mt_convolution(o, rdhorizontal, rdvertical, false, rdtotal, rdy, rdu, rdv)
bias==0 ? p : mt_lutxy(rdsaturate==true ? p : a, a, "x y == y 0 y - ? " + String(bias) + " +",y=rdy,u=rdu,v=rdv)
}

martino
16th January 2007, 14:47
I keep getting "there is no function named DEdgeMask" when trying to use LimitedSharpen and "there is no function named YV12LUTxy" when using aWarpSharpDering.

What am I doing wrong?

foxyshadis
16th January 2007, 19:14
Not having both masktools 1 and 2. (Those functions are part of v1.)

martino
16th January 2007, 23:19
So I need to have both installed...

d'oh

AssassiNBG
22nd March 2007, 21:23
So I need to have both installed...

d'oh

You just have to load both dlls into your script. (1.5.8 and 2.0a30)

And now onto my question. I have a function that uses edgemask() from masktools version 1.5.8. Since it is conflicting with fft3dgpu, I would like to modify this function to use mt_edge instead (from mt 2.0a30) I had a look at the documentation, but I couldn't understand much. I've never written a function before, or have paid much attention to the ones I copied from the board.

I hope at least the developer of masktools could help me out.

You can see the fft3dgpu development thread for reference about the problem.

tsp
29th March 2007, 17:26
is mt_polish broken in 2.0a30? It's complaining that spirit parser is not available with this script:

blackness().converttoyv12()
subtitle(mt_polish("x+y"))

jmac698
6th April 2007, 22:16
colorbars(pixel_type="YV12")
yv12lut() returns a bright green image (expected original image).

mt_lut(yexpr="x 161 = 0 x ?",uexpr="128",vexpr="128",y=3,u=3,v=3)
doesn't work, no test is true for equality. != does work and can be used as a workaround.

krieger2005
6th April 2007, 23:17
equal-sign changed from "=" to "=="

jmac698
7th April 2007, 04:46
agreed, but 1.5.8 still has a bug, but I guess that's irrelevant now.

Manao
7th April 2007, 06:43
By default, yv12lut trash the chroma planes, so their values is random. It's not a bug.

Tsp : noted, next version will have mt_polish back ( i must have disabled it because it was so slow to compile ).

redfordxx : noted too

Didée
12th April 2007, 02:32
noted
noted too
Oh, while you're holding the pencil anyway ... ;)

Proposal: New mode for mt_LutS: masking of "pixel's extremity"

Explanation: in a pixel's neighborhood, there's a darkest and a brightest pixel. Then ...

Method1: extremity = abs((pixel-min)/(max-min)-0.5)*2*255
(In the very middle between max and min, extremity is zero. At min and at max, extremity is maximal.)
(Used that several times.)

Method2: extremity = (pixel-min)/(max-min)*255
(Zero extremity gives mask=128. mask=0 means "pixel has 100% extremity @ dark". mask=255 means "pixel has 100% extremity @ bright".)
(Never used this one, but seems feasable, for completeness.)

Several times I found this useful during toying-around, but it's rather laborious to script with the current filters: three values are needed for computing, the complete list goes: one (or 2 or 3) inpand's, one (or 2 or 3) expand's, and three instances of LutXY: a=lutxy(min,max), b=lutxy(pixel,min), mask=lutxy(a,b). A good bunch of filter instances that is.

So I thought, perhaps(!) it is easier(?) when integrated into mt_LutS ... A new mode, "extremity1/2" or whatever, and via "pixels=" one can define the neighborhood that is to search for the local min and max.


Not earthbreaking, not of major importance. Just an idea. ;)

Dr.Khron
23rd April 2007, 16:56
Not sure if this thread is the correct place for this, but here I go...
Been fooling around with VMtoon. (the anime sites tend to rave about its predecessor, MFToon).

Got it all set up and it produced a horrible result: it turned most of the black outlines into white pixels! Hopefully, I'm doing something wrong.

http://img255.imageshack.us/img255/166/lisagl0.jpg

Turning down the power with VMtoon(strength=20) reduced the effect, but then it didn't sharpen either.
Here is my script:
LoadPlugin("C:\Program Files\AviSynth 2.5\MyPlugins\mt_masktools.dll")
LoadPlugin("C:\Program Files\AviSynth 2.5\MyPlugins\WarpSharp.dll")

import("C:\Program Files\AviSynth 2.5\MyPlugins\vmToon-v0.74.avsi")

#import Mpeg video and correct colors
DGDecode_mpeg2source("D:\Ripping\D2V.d2v")

#De-interlace
edeintted = AssumeTFF().SeparateFields().SelectEven().EEDI2(field=-1)
tdeintted = TDeint(edeint=edeintted,order=1)
tfm(order=1,clip2=tdeintted).tdecimate(hybrid=1)

#crop
crop( 8, 0, -8, 0)

#Resize
LanczosResize(640,480) # Lanczos (Sharp)

#noise filter
FluxSmoothST(7,9)

vmtoon()

foxyshadis
23rd April 2007, 17:19
A few things to test, to see what eliminates the effect.

Remove resizing: ssw=0 & ssh=0
Remove xsharpen: xstren=0
Remove thinning: thinning=0
Remove darkening: strength=0

If only one is missing the white, that'll quickly narrow it down; if it's more, it could be tougher.

Dr.Khron
24th April 2007, 00:13
vmtoon(ssw=0)
vmtoon(ssh=0)
vmtoon(ssw=0, ssh=0)
Using any of thse returns the same error:
"Resize: Width must be bigger then or equal to 4."

vmtoon(xstren=0)
Result: fixes the problem.

vmtoon(thinning=0)
Seems to make the problem slightly worse.

vmtoon(strength=0)
Seems to fix the problem, but makes the sharpening wierd: the black edge lines break up a little.

Leak
24th April 2007, 08:57
vmtoon(ssw=0)
vmtoon(ssh=0)
vmtoon(ssw=0, ssh=0)
Using any of thse returns the same error:
"Resize: Width must be bigger then or equal to 4."
I guess using 1 instead of 0 here would be the "do nothing" option...

foxyshadis
24th April 2007, 13:53
Ooops, ss has to be 1, not 0. >.>

So Xsharpen might be overflowing? Hrm. I'll see if I can get that to happen here.

Dr.Khron
24th April 2007, 16:27
I've now confirmed that:
vmtoon(ssw=1)
vmtoon(ssh=1)
vmtoon(ssw=1, ssh=1)

Do not fix the problem, they only make it worse.

Thanks for all the help, let me know if you need a few frames to check it out.
Would posting screen shots of the output with those different settings help?

foxyshadis
24th April 2007, 22:20
I wasn't able to reproduce, but I'm not sure I have the right source to do so. If you could replace vmtoon() with ImageWriter(file="x:\wherever\sample",start=x,end=y,type="ebmp") where x to y are representative frames, and then zip them up, I can try to find out where it's overflowing.

Dr.Khron
24th April 2007, 23:38
Here you go:

http://www.mytempdir.com/1307532

It only 3 frames, I wasn't sure if that was enough.
Anyway, if you couldn't reproduce it, its probably somehting to do with my set up. I just did a clean install of everything though, and I was careful to get the latest DLLs...

EDIT:
I tried using an older version, mftoon2 (mfToon-v0.54.avsi), but it keeps telling me that the "Unsharpmask" function cannot be found... I can't this function anywhere. Is it part of an older package I might be missing?

IanB
25th April 2007, 09:31
Someones got a bug in there code. This is typical when one doesn't clamp arithmetic results to 0 at the low end and 255 at the high end.

In 8 bit unsigned arithmetic 0-1=255 (0=black, 255=white)

Manao
1st August 2007, 21:00
New version : v2.0a31 (http://manao4.free.fr/masktools-v2.0a31.zip)

Changelog : * fixed : mt_hysteresis was randomly crashing.
* fixed : mt_polish is back.
* added : round, clip, min, max and = for lut.
* adapted : to msvc8 / yasm.

Manao
1st August 2007, 21:03
Didee : what you asked for isn't possible with a lut, it would require too big a lut.

Dr Khron, foxyshadis : does anybody still have the problem on the edges reported by Dr Khron ? If yes, can I have something to help me reproduce it ?

Terranigma
1st August 2007, 22:06
Thanks for the update Manao :)

Terranigma
1st August 2007, 23:27
Manao, was there some sort of speed tweak involved as well? Seems like it, but maybe i'm just off my engines.

Manao
2nd August 2007, 19:08
I didn't do anything to make it faster.

Manao
5th August 2007, 14:27
New version : v2.0a32 (http://manao4.free.fr/masktools-v2.0a32.zip)

Changelog : * added : mt_lutxyz
* added : mt_lutsx
* fixed : small memory leak in mt_luts

Basically, mt_lutsx is the filter Didee previously required, and mt_lutxyz is a three clip lut. I changed my position on what "too big" is for a lut. Those filters take some time to initialize ( 3*2^24 values to compute ), something like 5 seconds can be expected. Each instance of those filters takes up 48 MB too.

check
10th August 2007, 18:19
Just letting you know there's a typo in the filterlist in the .htm help. 'mt_rectange'

Spuds
20th December 2007, 03:18
Not so much a bug as an observation or just a plain mistake on my part.

I was using mt_lutf to see if a frame was over / under a very low threshold, something like:
lutf(mask,mask,mode="avg",expr="x 0.1 > y 0 ?")

and comparing the results to:
ConditionalFilter(mask, nullclp, mask, "AverageLuma()", "<", string(0.1),false)

I was getting different results on what frames got through and realized the mt_lutf was doing the comparison not on the float but on the rounded value of average. I know the final result is a round but expected the float to be maintained through the comparison.

Also found that the averageluma approach was about 30% faster.

Didée
20th December 2007, 03:41
Interesting finding on the rounding thing.
The speed difference probably isn't surprising: averageluma operates on just one single clip. LutF/LutS always operate on two input clips, could be this makes the internal pixel shuffling a bit slower.

Manao
20th December 2007, 06:58
LutF/S are completely unoptimized, so it doesn't suprises me if they are slow.

As for the rounding, I'll add that to the documentation. It makes sense for me, since the average becomes an entry to a LUT, it must be rounded, but I guess that a programmer's POV, not really a user's POV :)

Fizick
20th December 2007, 17:16
manao, why in your signature the stable version is 2.0a31 and not 2.0a32? :)

yup
28th February 2008, 10:24
Hi folks!
Can I use MaskTools V.2 in Avisynth 2.57 with planar YUY2?
I can get planar using SSETools.AVISource("a.avi")#YUY2 source
SeparateFields()
Interleaved2Planar()
MaskTools V.2 function
Planar2Interleaved()
Weave()

This will be work?
yup.

Boulder
28th February 2008, 10:28
MaskTools requires YV12 input, so you need to convert to YV12 before using any MaskTools functions.

yup
28th February 2008, 10:44
Hi Boulder!
This sentence from document.
The filters have a set of common parameters, that mainly concerns what processing to do on each planes. They all work only in YV12 ( though with Avisynth 2.6, support for all planar format will be available ).
We need waiting Avisynth 2.6? I right?
yup.

Boulder
28th February 2008, 10:47
I don't know the inner workings of MaskTools, it could (and probably does) mean that the MaskTools code needs some rewriting too.

Manao
28th February 2008, 10:58
Internally, it supports everything from 4:0:0 to 4:4:4 planar. I'll see what I can do for avs 2.5 and interleave2planar. It already works for avs 2.6.

Manao
28th February 2008, 19:56
Done : http://manao4.free.fr/masktools-v2.0a33.zip

XBoy
29th February 2008, 04:14
How about x64 support?

Manao
29th February 2008, 04:18
I can quickly make a x64 version with assembly disabled. I don't think that's what you want, but without having a 64bit OS, I won't do anything more.

yup
29th February 2008, 10:42
Manao!
:thanks:
I try and report.
yup.

yup
29th February 2008, 13:56
Hi Manao!
I tested now You new version, script simple
LoadPlugin("SSEToolsS.dll")
LoadPlugin("mt_masktools-25.dll")
AVISource("flower.avi")
AssumeTFF()
SeparateFields()
Interleaved2Planar()
mt_luts(last, last, mode="median",pixels=" 0 0 0 1 0 -1", expr="y", U=1, V=1)
Planar2Interleaved()
result
http://img264.imageshack.us/img264/5620/mtplanarqr8.th.png (http://img264.imageshack.us/my.php?image=mtplanarqr8.png)
Source analog capture YUY2 colorspace.
yup.

Manao
29th February 2008, 20:09
Hopefully, fixed : http://manao4.free.fr/masktools-v2.0a34.zip

yup
1st March 2008, 10:21
Manao!
:thanks:
Now all work. I try implement LSF for YUY2 colorspace, my source analog capture.
yup.

XBoy
6th March 2008, 04:30
I can quickly make a x64 version with assembly disabled. I don't think that's what you want, but without having a 64bit OS, I won't do anything more.

how about having the asm compiling in yasm?

Manao
6th March 2008, 08:30
If you knew what you were talking about, you'd already see that I use yasm. yasm != 64bit compatibility.

Manao
19th April 2008, 10:12
http://manao4.free.fr/masktools-v2.0a35.zip

A new filter, mt_lutspa, which comes in handy whenever you need to create mask/picture/whatever that can be mathematically defined.

For example :mt_lutspa(clip,false,"x 32 % 16 < 0 255 ?", chroma = "128"Creates vertical white & black stripes, and : mt_lutspa(clip, false, "x 32 % 16 < 0 1 ? y 32 % 16 < 0 1 ? + 1 == 0 255 ?", chroma = "128")Creates a black and white checker board.

halsboss
21st April 2008, 10:54
Hello, searched but didn't spot when to use mt_masktools-25.dll or mt_masktools-26.dll - any hints (nothing said in the readme of the latest version)... I have avisynth 2.5.7

Manao
21st April 2008, 11:39
mt_masktools-25.dll is for avisynth 2.5.x
mt_masktools-26.dll is for avisynth 2.6

Nikos
23rd April 2008, 15:14
In masktools Round(1.5)=2 or 1.

Manao
23rd April 2008, 17:49
Is that a question ?

jeffy
23rd April 2008, 19:03
Is that a question ?

Yes, it is. Simply said: is the value of Round(1.5) in MaskTools equal to 1 or 2?

I would like to know as well, :thanks:

Manao
23rd April 2008, 19:07
You shouldn't have to know. Any formula relying on 1.5 being specifically rounded to 1 or to 2 is ill designed. Masktools makes its computations in floats, which have a limited precision. 1.0 + 0.5 might not be exactly 1.5, thus you shouldn't care whether 1.5 is rounded to 1 or 2. You just know it rounds to the nearest integer.

Nikos
23rd April 2008, 20:19
Sorry for the wrong phrase :(

Thanks for the clear answer :)

yup
7th June 2008, 08:06
Hi All!
I have problem with mt_masltools. When I changed
mcfmaskpl=mt_merge(mcfpl,fieldsfpl,mmaskpl,u=3,v=3)

to
mcfmaskpl=mt_merge(mcfpl,fieldsfpl,mmaskpl,luma=true)
Avisynth crashed. Script work YUY2 planar color mode, when script work at YV12 no problem.
With kind regards yup.

foxyshadis
8th June 2008, 01:40
Didn't you read the documentation? Luma and chroma aren't booleans (true/false), they're strings ("ignore"/"process"/"copy"/"copy first"/"copy second"/"copy third").

Didée
8th June 2008, 02:10
True for chroma, false for luma. :D

("chroma" argument of any mt-filter is string type, but "luma" argument of mt_merge is boolean, indeed.)

yup
9th June 2008, 05:50
foxyshadis!
documentation mt_masktools:
mt_merge

mt_merge : clip clip1, clip clip2, clip mask, bool "luma"(false)

It's the backbone of the framework. It merges two clips according to the mask. The bigger the mask value, the more the second clip will be taken into account ( the actual formula is y = ((256 - m) * x1 + m * x2 + 128) / 256 )
luma is a special mode, where only the luma plane of the mask is used to process all three channels.
u and v are defaulted to 2 (that way, the resulting clip contains the chroma of clip1, and looks right).
Didée I want use luma plane from mask to 3 plane clip2. It is right?
yup.

Manao
9th June 2008, 08:36
yup: mt_merge should report an error when trying to use luma=true with a 422 video, but it shouldn't crash.

yup
9th June 2008, 10:16
Manao!
I get message when see script in VirtualDub:
If change luma=tru to U=3, V=3 all work without problem for YUY2 planar colorspace. If You want i can upload my script.
yup.

Didée
9th June 2008, 11:13
I guess the problem comes from the fact that mt_merge needs to perform a resizing operation when luma=true, but Avisynth does not support resizing of "planar hacked" YUY2 input ... ?

However: yup, most probably you don't need luma=true. It seems that you're currently dealing with masks provided by MVMask(). Those masks contain the needed information on all three planes, so using the normal U=3,V=3 in mt_merge should do what you want.
If that's not the case, you have to construct your mask clip manually by means of YtoUV() operations.

yup
9th June 2008, 13:39
Didée!
mask=Planar2Interleaved(maskpl)
HorizontalReduceBy2(mask).YtoUV()
mask=Merge(mask)
maskpl=Interleaved2Planar(mask)
maskpl mask in planar colorspace
mask YUY2 in interleaved colorspace.
This will be work?
yup.

yup
10th June 2008, 10:37
Please advice:
mmask=Planar2Interleaved(mmaskpl)
YtoUV(HorizontalReduceBy2(mmask),HorizontalReduceBy2(mmask))
mmask=MergeLuma(mmask)
mmaskpl=Interleaved2Planar(mmask)
And use U=3,V=3 at mt_merge. This work like luma=true for YUY2 planar?
Now right?
yup.

Didée
10th June 2008, 11:21
Seems to be correct, yes.
Small nitpick: it does a little more work than necessary.
More efficient:
mmask = mmaskpl.Planar2Interleaved()
mmask2 = mmask.HorizontalReduceBy2()
mmaskpl = YtoUV(mmask2,mmask2,mmask).Interleaved2Planar()

yup
10th June 2008, 12:19
Didée :thanks:
My collection tip&trick grow one more :thanks:
yup.

Alain2
6th September 2008, 16:07
Hi Manao,

Is it normal that mt_edge doesn't output the same thing when using a named kernel and its equivalent kernel as defined in the html help file ? (like for instance "laplace" and "1 1 1 1 -8 1 1 1 1")

Manao
6th September 2008, 18:09
laplace is equivalent to "1 1 1 1 -8 1 1 1 1 8", while "1 1 1 1 -8 1 1 1 1" gets interpreted as "1 1 1 1 -8 1 1 1 1 16". The same applies to sobel ("0 -1 0 -1 0 1 0 1 0 2" and robert ("0 0 0 0 2 -1 0 -1 0 2").

Alain2
6th September 2008, 18:23
ok :thanks:

LaTo
22nd December 2008, 10:55
Hi!

I have a little problem with the pi value... Maybe a bug!

In the documentation:
V) Reverse polish notation.
[...]
The constant "pi" can be used.

But if I try a simple expression:
mt_lut("pi 2 / sin 255 *")
It return a black screen instead of a blank screen...

It would be great to fix this :thanks:

Manao
22nd December 2008, 20:30
Fixed in 2.0a36

lilive
9th October 2009, 22:27
Hi,
:thanks: very much for this job, and to share it.
I'm using it to produce some movies for a little dance show.
I hope I will do somedays something usefull like that !
Bye,
Et le bonjour de Toulouse :)

adamhj
20th October 2009, 03:13
bug in 2.0a36 : it seems that mt_polish can not recognize variable "z" for mt_lutxyz

WorBry
3rd April 2010, 16:17
Any possibility that the MaskTools v2 developers could add a filter that translates reverse polish expressions to InFix notation - call it mt_Infix, if you will, or maybe make it an option in the mt_polish filter.

This would greatly assist non-programmers, such as myself, in deciphering and modifying the calculations/operations involved in scripted functions developed by others.

Thanks.

Manao
3rd April 2010, 19:56
adamhj, worbry : see my signature for the new version.

WorBry
3rd April 2010, 20:52
adamhj, worbry : see my signature for the new version.

Wow, that was fast. Really excellent. Thanks alot. :)

Although self explanatory, I guess the documentation needs to be updated to include mt_InFix in the filter list.

Thanks again.

Zep
9th April 2010, 14:38
I'm curious. what is the difference between the 25 and 26 dll's? :)


thx

Manao
9th April 2010, 14:56
One is for avisynth 2.5, the other one for avisynth 2.6

Zep
10th April 2010, 11:48
One is for avisynth 2.5, the other one for avisynth 2.6

ah thanks i thought that was the case so i used 25 but i wanted to make sure because i saw a lot of these scripts for denoising and what not and most state 26 is needed so i hoped there was nothing in 26 they truly needed that 25 didn't have. :)

better safe than sorry so i asked lol


thx!

Gavino
10th April 2010, 13:07
One is for avisynth 2.5, the other one for avisynth 2.6
It would be nice if this was made clearer in the documentation, as I see a lot of scripts posted that erroneously use mt_masktools26.dll with Avisynth 2.5.

In practice, what problems can arise from using the wrong version?

Manao
10th April 2010, 14:24
In practice, what problems can arise from using the wrong version? I have no idea. Somebody asked me once to release a 2.6 version, so I did. But I didn't test it, and neither did I test cross compatibilities. I'll try to add a note (which nobody will read...) and find a more explicit naming scheme for the next release.

IanB
10th April 2010, 22:47
In practice, what problems can arise from using the wrong version?You can use the 25 .dll for RGB24, RGB32, YUY2 and YV12 with any version of avisynth later than 2.5.0.

You can only use the 26 .dll with versions of Avisynth which were compiled with an avisynth.h that is compatible with the one used to compile the 26 .dll If the bit positions of the *needed attributes and pointers in the referenced structures do not match then you can expect incorrect behaviour and crashes.


* Stuff from the 2.5 feature set should be okay. Stuff that has not been shuffled since should be okay. Stuff like the VideoInfo pixel type bit definitions then maybe there is a problem.

Zep
11th April 2010, 16:05
It would be nice if this was made clearer in the documentation, as I see a lot of scripts posted that erroneously use mt_masktools26.dll with Avisynth 2.5.

In practice, what problems can arise from using the wrong version?

tell me about it and why i asked because i downloaded like 10 scripts and like most all said 26 or showed 26 being loaded :)

I just tested 26 with 258 avisynth and crashed right away so i can only assume all these scripters have 2.6 avisynth installed lol

Zep
11th April 2010, 16:08
I have no idea. Somebody asked me once to release a 2.6 version, so I did. But I didn't test it, and neither did I test cross compatibilities. I'll try to add a note (which nobody will read...) and find a more explicit naming scheme for the next release.

hey i would have read it because your docs were the FIRST place i went to try to figure it out and i saw nothing about it so i posted here :D
BTW - 26 crashed instantly for me on a 258 avisynth install. IIRC there was an out of bounds memroy read/write error.

anyway thx for the awesome plugin!

Manao
19th April 2010, 19:55
Hi everyone.

I'll need your help for that one, since I don't have a 64bits OS. here (http://manao4.free.fr/masktools-v2.0a38.zip) is a new set of dlls for masktools v2. There are four of them, 2 of them should work with 64bits avisynth (2.5 and 2.6, according to their filename)

Can anybody tell me whether the 64bits dll crashes or not ? Especially, try to use mt_edge (sobel or roberts would do) and mt_invert.

Also, I don't consider those dlls (even 32 bits) stable right now, since I had to rewrite most of the asm to make it 32/64 bits portable.

Didée
20th April 2010, 07:12
While you're at the compiler, may I note something?

function f4(clip c) { c.mt_inflate(Y=3,U=3,V=3) }
function f5(clip c) { mt_logic(c,c.removegrain(19),"max",Y=3,U=3,V=3) }

f4: 92 seconds :eek:
f5: 28 seconds :cool:
Seems that mt_xxflate() could need some optimization. (Are they still the plain C routines, maybe?)

Manao
20th April 2010, 07:30
mt_inflate/mt_deflate are plain c. I never bothered optimizing them, since I never noticed anybody using them. Now, if you start doing so, I might optimize them

Didée
20th April 2010, 07:58
Oh, be assured they have been used. All those years, all over the world. ;)

If it's for throwing ideas - in the TGMC script, there is this winded "VCRep()" function. It basically does a "signed" variation of expand+inpand, in order to cancel-out high frequency parts from a 128-centered difference map. The implementation is a bit arbitrary, and surely it's rather slow. I'm not sure if there is a better/simplier way of doing such an operation, or if it's even worth considering to include something like that into the masktools ...

Thoughts are welcome. :)

Terka
23rd April 2010, 10:23
Manao, please do!

Manao
25th April 2010, 10:10
New version (http://manao4.free.fr/masktools-v2.0a40.zip) in my signature. It should speed up mt_inflate/mt_deflate, and mt_inpand/mt_expand in the modes vertical/horizontal/both.

Terka
25th April 2010, 11:29
Thank you, it was done fast!

MatLz
25th April 2010, 14:16
Now my crappy functions will be 'faster crappy functions'...:D

Un grand merci!

Manao
27th April 2010, 19:24
To Didée and all the frenzy scripters out there : If you have some masktools-intensive script excerpts which might be optimizable, don't hesitate to share them here. I don't use any fancy script myself, so my knowledge on that matter is sorely outdated (think "when limitedsharpen became limitedsharpenfaster"...). For example, are there other examples of the like of vcrep() out there ? Are there any specific use of mt_luts / mt_lutf that could benefit from being specialized & optimized ? Are there some common combination of functions that are so often used together that they would merit their on filter (as mt_makediff / mt_average / mt_clamp / mt_adddiff did) ?

Also, I can most probably squeeze some more speed out of some of the filters (either using ssse3/sse4, or just rewriting assembly for mt_xxpand/mt_edge/mt_inflate and the likes), or make there assembly more versatile (most of them needs the width to be mod8). What are the filters that are used the most ?

Boulder
27th April 2010, 19:42
Hi Manao,

MCTemporalDenoise is one that uses MaskTools v2 functions quite a bit. Of course the MaskTools parts aren't the most time-consuming ones in the script but if you can provide any speedup, I am very happy to accept the offer :)

http://forum.doom9.org/showthread.php?t=139766

Manao
1st May 2010, 16:42
Hi,

Here (http://manao4.free.fr/masktools-v2.0a42.zip) is a new version, which adds new modes to mt_binarize and mt_logic.

For example, mt_lut("x "+string(cutoff)+" >= x 0 ?",U=1,V=1) can be replaced by mt_binarize(threshold = cutoff - 1, mode = "x 0")Andmt_lutxy(smP,i,"x y - abs "+string(maxdiff)+" <= x x y - 0 < y "+string(maxdiff)+" - x ? ?",U=1,V=1)bymt_logic(smP, i, th2 = -maxdiff, mode="max")

Gavino
9th May 2010, 19:14
Behaviour of mt_lutspa(relative=true)

According to the MaskTools docs, when relative=true is used with mt_lutspa, the expression variables x and y range from 0 to 1. However, it seems that the upper ranges are actually (width-1)/width and (height-1)/height, a value of 1 is never actually reached. Is this intended, or is it a bug?

To my mind it would be more useful, for creating accurate gradients etc, if the last pixel in a row or column corresponded exactly to 1. So I suggest pixel (m, n) should correspond to x=m/(width-1) and y= n/(height-1).

Mug Funky
10th May 2010, 14:48
i seem to not be having much luck with YV16 with masktools :(

i'm wanting to migrate my "workhorse" scripts that i've had for years to a 4:2:2 workflow.

i seem to be getting lots of unsupported colourspace errors.

Manao
10th May 2010, 19:53
Mug Funky : Fixed (http://manao4.free.fr/masktools-v2.0a43.zip)

Gavino : it was not intended, but neither was it a bug. Both [0, 1[ and [0, 1] make sense. So I added a "biased" parameter. relative=true, biased=true corresponds to the default [0, 1[, while relative=true, biased=false is [0, 1], what you want.

Gavino
10th May 2010, 20:25
Manao, thanks for your quick response and action.
:thanks:

Mug Funky
11th May 2010, 00:54
fantastic! thanks for the quick response. i'd been thinking i was missing something...

Gavino
26th May 2010, 09:12
Manao, the new biased parameter of mt_lutspa has been introduced between the parameters relative and expr.
This causes problems for existing scripts which have called mt_lutspa with positional parameters (eg see here).

Rather than have everyone affected update their scripts/functions, it would be better to make biased the last parameter in the list. It is generally good practice to do this when introducing new options, to preserve backwards compatibility.

foxyshadis
27th May 2010, 01:53
Actually, Deblock_QED and some one-off sharpener testing visualization script seem to be the only scripts on the forum using it without expr. As long as Deblock_QED is updated, it shouldn't be a major problem - and the error message should make it clear when it does happen that it's in Deblock_QED.

Gavino
27th May 2010, 09:21
Actually, Deblock_QED and some one-off sharpener testing visualization script seem to be the only scripts on the forum using it without expr.
Good to know, although the forum isn't the exclusive source for scripts. Some people actually write their own. ;)

Manao
30th May 2010, 11:17
New version (http://manao4.free.fr/masktools-v2.0a44.zip) available, with a new mode added to mt_luts / mt_lutsx. It will allow very flexible convolution with custom kernels.

Gavino : for mt_lutspa, the "evil" is done, I won't change it back. I'll try to keep backward compatibility in mind for later releases, but if it really matter to you, you can also take care of that on your side, by using named parameters (which I always do, thus why I didn't think adding a parameter in the middle of the parameter list would be a problem).

jpsdr
31st May 2010, 08:44
I'm agree with Gavino, and i'm thinking of people who use scripts made by others, and may don't know how to debug/correct it, or even how to contact the author of the script...

hydra3333
31st May 2010, 11:58
yes, please reconsider. just this once, maybe.

kemuri-_9
31st May 2010, 13:43
I'm in agreement with Manao, he's already made the change and so it is already propagating.
to change it would cause a re-propagation of changes.

besides if people seriously don't know how to fix the script they're using, then they should take that opportunity to actually learn about what they're doing.

Gavino
31st May 2010, 14:24
besides if people seriously don't know how to fix the script they're using, then they should take that opportunity to actually learn about what they're doing.
The issue is not whether people know how to fix their scripts, it's the basic software engineering principle that a new version of something should not impose unnecessary changes on existing users. IanB is very careful to adhere to this principle for Avisynth itself.

However, the damage is slight in this case and has already been done. It was probably a design 'mistake' in the first place to make 'relative' the first parameter of mt_lutspa, rather than the more frequently used 'expr'. But this is just nit-picking on what is ultimately a great piece of software.

Manao
31st May 2010, 14:52
Not really a mistake. Both "expr" and "relative" have to be provided. You can assume "relative" to have its default value, but it's a bad habit imho in this case.

Also, the logic behind the original positioning was that "expr" and "relative" should be the first two arguments (because they would be those used the most), and that "expr", "yExpr", "uExpr" and "vExpr" should be consecutive arguments (as they were in all the other filters using luts). Once those two predicates were in action, I didn't have a lot of choice in regard to their relative positioning. When I had to add "biased", once again, I decided it should be one of the first three, and that it shouldn't break the "expr" serie.

Guest
31st May 2010, 15:00
People that do not use named parameters deserve what they get, IMHO.

hydra3333
31st May 2010, 15:11
Oh ? They do ?

Didée
31st May 2010, 15:13
Well, it was me who "too quickly" fiddled that lutspa into that certain deblocking function ... Guilty! Blame me! Guilty!

(Will I be condemned to prison, or is there hope to get away with suspended sentence?)

A corrected script has been posted already ... but as usual, the problem is that once a malformed script has been spread in the wild, you can't make it disappear anymore.

Bi11
31st May 2010, 15:25
My 2 cents is that consistent relative positioning of the parameters is probably more important in this case (especially since mt_LutSpa is but one function in a much larger piece of software), as Manao pointed out.

I think most "ignorant" users (like me) get their scripts from the AviSynth Wiki. Hence the Wiki should be updated with the corrected version of broken scripts.
Edit: I see the AviSynth Wiki has already been updated with the corrected version of Deblock_QED. I would strongly advise those in charge of editing the Wiki to please link back to the source (post) of those scripts (just like a Wikipedia reference) for the benefit of everyone.

IanB
31st May 2010, 23:08
Manao, the new biased parameter of mt_lutspa has been introduced between the parameters relative and expr.
This causes problems for existing scripts which have called mt_lutspa with positional parameters (eg see here).

Rather than have everyone affected update their scripts/functions, it would be better to make biased the last parameter in the list. It is generally good practice to do this when introducing new options, to preserve backwards compatibility.Gavino : for mt_lutspa, the "evil" is done, I won't change it back. I'll try to keep backward compatibility in mind for later releases, but if it really matter to you, you can also take care of that on your side, by using named parameters (which I always do, thus why I didn't think adding a parameter in the middle of the parameter list would be a problem).Manao,

I must say I am very disappointed with your "evil is done, I won't change it back" attitude. You could have just said oops, my bad, here is a fixed v2.0a44a version and everybody would have been satisfied.

There are places in Avisynth where you do cannot use argument naming, Animate/ApplyRange being one.

You write excellent software, I hope you put away your black hat and start wearing your white hat again, please reconsider.

Manao
1st June 2010, 06:39
IanB: I didn't think of animate/applyrange, well spotted. But, luckily for me, since mt_lutspa's arguments are only bools and strings, it doesn't really apply.

As for my "evil" is done attitude (I should have said the genie is out of the box...), I would probably have made the change if the "problem" had been spotted right after 2.0a43, three weeks ago. Instead, something like that (http://forum.doom9.org/showthread.php?p=1402777#post1402777) happened in the meantime. Basically, making the change now would imho mess things up even more.

Gavino
1st June 2010, 08:11
IanB: I didn't think of animate/applyrange, well spotted. But, luckily for me, since mt_lutspa's arguments are only bools and strings, it doesn't really apply.
ApplyRange is not limited to numeric parameters, although in truth it's unlikely one would use it with mt_lutspa.

I don't think it's too late to make a change. The Deblock_QED fix uses named parameters, so will not be affected.

jpsdr
1st June 2010, 09:06
besides if people seriously don't know how to fix the script they're using, then they should take that opportunity to actually learn about what they're doing.

I don't agree. Why should the user of something (script or software) has to be able to fix it ?
A lot of people used a lot of video software, filters, plugins, scripts, they know what they are doing in video edition, but they don't have programming knowledge, or high video processing knowledge to do what they wanted. And they don't have to.

Bi11
1st June 2010, 20:04
You could have just said oops, my bad, here is a fixed v2.0a44a version and everybody would have been satisfied.
But what about the reasoning given for the positioning of the parameter in the first place.

I would probably have made the change if the "problem" had been spotted right after 2.0a43, three weeks ago.
It may have been spotted right after 2.0a43, but those who spotted it may have been too "dumb" to figure out the exact cause of the problem, or they may not be Doom9 members, or they didn't known how to submit a bug report, or didn't have time, or waited for someone else to post about it, or ...

Instead, something like that (http://forum.doom9.org/showthread.php?p=1402777#post1402777) happened in the meantime.
I can always update my post to state that the old script will continue to work with (the fixed) future versions of MaskTools 2.0.

Basically, making the change now would imho mess things up even more.
If you can live with slight internal inconsistency in parameter positioning then I see no reason not to apply the fix.

Scripts that worked before and after the change will continue to work after the fix. Scripts that didn't work after the change must be corrected, unless the fix is applied in which case they will continue to work as if the change never happened. Only scripts without named parameters that used the "biased" parameter after the change will no longer work after the fix, but those scripts would be an insignificant minority compared to scripts written before the change.

Thus, preserving backward compatibility is a win-win for everybody (except you, maybe :p).

Edit:
I just realized that the new "biased" parameter is a hack for the vagueness of "relative". The argument of consistency cannot be applied to hacks! Therefore, it is a software development error on your part, Manao, to break backward compatibility for a hack (esp. since it's usually done the other way around) in an otherwise flawless piece of software.
So that just leaves either keeping the hack but making sure to preserve backward compatibility, or fixing the hack properly (perhaps by changing bool relative to string mode, with values "absolute", "relative inclusive" and "relative exclusive"), but unavoidably breaking backward compatibility.

Bi11
1st June 2010, 23:01
You can probably get the best of all worlds by declaring the function as:

mt_lutspa : clip clip, bool relative("true"), string expr("x"), string yexpr("x"), string uexpr("x"), string vexpr("x"), string mode("relative exclusive"), bool biased("true")

Of course, you would have to declare "relative" and "biased" as being deprecated in favour of "mode" in the documentation.

Hence, the hack now serves the purpose of preserving backward compatibility, as it should be. :cool:

JEEB
13th June 2010, 07:43
Excuse me as a MaskTools beginner, but I happened to come upon something that begs me to question if this is intended behavior:


YourSourceFilter()

mask = last.mt_edge("cartoon",4,32,4,32)
mask

The (http://img27.imageshack.us/img27/8835/weirdcolors2.png) output (http://img27.imageshack.us/img27/4463/weirdcolors.png). What I would expect (http://img16.imageshack.us/img16/4586/13198mask.png).

This piece of script I got by combining rather random knowledge out of another script and my own scribbles, and used it here (http://forum.doom9.org/showthread.php?t=148395). Now, since the powerful white is there, and most of the other colors are rather slight, the actual script has worked. It's just that the other day I got asked about MaskTools2 usage on IRC, and got asked if random colors etc. were normal to have in the mask itself. So, as I couldn't give a proper answer to that question, here I am.

Tested on revisions 29, 34, 37, 39, 43 and 44 -- the output is quite identical. 32bit Avisynth 2.5.8 stable, no MT used. Source filter and resolution don't seem to matter, I have so far gotten identical results on several types of sources and several resolutions. Of course, if a source will be needed, I will be glad to provide.

foxyshadis
13th June 2010, 08:07
You forgot chroma="process" (or "copy" or -128). You can also follow it up with a .Greyscale() call.

Same thing tripped me and most others up the first time. :D

JEEB
13th June 2010, 08:22
Thank you, that indeed did help. I guess this is A) indeed intended behavior, and B) what I get from not RTFM'ing enough.

foxyshadis
23rd July 2010, 05:37
I'd like to know whether I'm correct in believing that mt_makediff is supposed to be commutative, so that this will produce the original input:

s=Source()
dn=s.Denoise()
df=mt_makediff(s,dn,chroma="process")
rn=mt_makediff(dn,df,chroma="process")
s+rn+df

However, when I do this, s is very different from rn. It might be saturating instead of wrapping, but the change is never more than +-20. Is this intended?

Gavino
23rd July 2010, 09:47
mt_makediff is not commutative - what makes you think it should be? (Subtraction is not a commutative operation.)

Loosely speaking, df = s-dn+128 and rn = dn-df+128, ie dn+dn-s.
To reconstitute s, use mt_adddiff(df, dn).
(Or mt_adddiff(dn, df), since mt_adddiff is commutative.)

foxyshadis
23rd July 2010, 21:41
Ah, once I think through the math, it's obvious. Here I've been using mt_makediff as an equivalent to xor for ages now, because it looks close enough. That's my fault for not ever actually thinking all the way through it - I probably munged a few projects that way. Thanks.

Now of course there's mt_logic with a real xor.

Didée
24th July 2010, 01:40
Now of course there's mt_logic with a real xor.
Depending on what exactly you want to to. All the "AND", "OR" / "XOR" of mt_logic are only well-defined for clips' values of [0] and [255]. For values [1,254], the behaviour isn't well-defined. After all, those are binary operators.

For general-case usage (i.e: difference clips), the equivalent of "OR" is "max", the equivalent of "AND" is "min". There is no equivalent for "XOR", since that doesn't make sense if the argument is a field/range of possible values.

(Slight possibility that Manao was aware and made AND/OR also working that way, I never actually checked. But per documentation, IIRC, AND/OR are really laid out for binary logic.)

Gavino
24th July 2010, 09:12
All the "AND", "OR" / "XOR" of mt_logic are only well-defined for clips' values of [0] and [255]. For values [1,254], the behaviour isn't well-defined.
The documentation suggests they work bit-wise for all values [0,255].
It even uses pixel values of 11 and 5 as an example, eg for xor, 11 ^ 5 = 1011 ^ 101 = 1110 = 14.

Edit: I thought this conversation seemed familiar, and after some searching I found this (http://forum.doom9.org/showthread.php?p=1256289#post1256289). ;)

Manao
7th September 2010, 13:44
*Bump* (http://manao4.free.fr/masktools-v2.0a45.zip)

In store, a fix to a problem with mt_clamp and SSE2, pointed out by tp7 on IRC. I also implemented Bi11 proposal to mt_lutspa conundrum. There's now a "mode" parameter, which takes the positional place of the "relative" parameter, which is in turn, together with the "biased" parameter, moved further away and shouldn't be used anymore. Consequently, backward compatibility with named parameters is preserved, but is (yet again) broken with positional parameters.

TurboPascal7
9th September 2010, 00:50
Looks like my first post here. ^^
Since I work a lot with HD video, I have a realy stupid question about scripts optimization.
Is there any possibility to replace mt_**pand with predefined custom modes (i.e. mt_square) with multiple calls of mt_**pand internally in masktools?
For example, in gradfun2dbmod, one can replace mt_luts(input,input,mode="range",pixels=mt_square(radius),expr="y",u=1,v=1) with something like mt_lutxy(input.mt_expand(mode=mt_square(radius)),input.mt_inpand(mode=mt_square(radius)),"x y -",u=1,v=1) (gives ~same speed as original), wich is equal to mt_lutxy(input.mt_expand().mt_expand(),input.mt_inpand().mt_inpand(),"x y -",u=1,v=1) (radius=2, about 10 times faster).
Works good, but without *for* statement totaly unoptimal and nonuniversal.
It's still possible to optimize script for some often usable modes, but it looks too silly for me.
GFmask = radius==1 ? input.mt_edge(mode="min/max",thY1=0,thY2=255,u=1,v=1)
\ : radius==2? mt_lutxy(input.mt_expand().mt_expand(),input.mt_inpand().mt_inpand(),"x y -",u=1,v=1)
\ : radius==3? mt_lutxy(input.mt_expand().mt_expand().mt_expand(),input.mt_inpand().mt_inpand().mt_inpand(),"x y -",u=1,v=1)
\ : radius==4? mt_lutxy(input.mt_expand().mt_expand().mt_expand().mt_expand(),input.mt_inpand().mt_inpand().mt_inpand().mt_inpand(),"x y -",u=1,v=1)
\ : radius==5? mt_lutxy(input.mt_expand().mt_expand().mt_expand().mt_expand().mt_expand(),input.mt_inpand().mt_inpand().mt_inpand().mt_inpand().mt_inpand(),"x y -",u=1,v=1)
\ : mt_luts(input,input,mode="range",pixels=mt_square(radius),expr="y",u=1,v=1)
P.S. My english isn't so good as I want it to be, sorry about that.

Manao
9th September 2010, 05:34
There are no "for" statements, but you can still do recursive functions :function mt_inpand_rec(clip c, int radius)
{
return radius <= 0 ? c : radius <= 1 ? c.mt_inpand : mt_inpand_rec(c.mt_inpand, radius - 1)
}Also, mode="range" is equivalent to "x y - abs", not "x y -".

TurboPascal7
9th September 2010, 05:45
Oh, I haven't thought about recursion, my fault.
Also, mode="range" is equivalent to "x y - abs", not "x y -".
is there any case when maximum value can be smaller then minimal value and x y - gives negative result?

Manao
9th September 2010, 07:47
is there any case when maximum value can be smaller then minimal value and x y - gives negative result? Not really, unless it's very early in the morning and you just woke up :p

cretindesalpes
11th September 2010, 11:46
It made me think about two helper functions I wrote for this kind of task, and I thought that I could share them:

#=============================================================================
# mt_expand_multi
# mt_inpand_multi
#
# Calls mt_expand or mt_inpand multiple times in order to grow or shrink
# the mask from the desired width and height.
#
# Parameters:
# - sw : Growing/shrinking shape width. 0 is allowed. Default: 1
# - sh : Growing/shrinking shape height. 0 is allowed. Default: 1
# - mode : "rectangle" (default), "ellipse" or "losange". Replaces the
# mt_xxpand mode. Ellipses are actually combinations of
# rectangles and losanges and look more like octogons.
# Losanges are truncated (not scaled) when sw and sh are not
# equal.
# Other parameters are the same as mt_xxpand.
#=============================================================================

Function mt_expand_multi (clip src, int "thY", int "thC", string "mode",
\ int "offx", int "offy", int "w", int "h", int "y", int "u", int "v",
\ string "chroma", int "sw", int "sh")
{
sw = Default (sw, 1)
sh = Default (sh, 1)
mode = Default (mode, "rectangle")

mode_m =
\ (sw > 0 && sh > 0) ? (
\ (mode == "losange" || (mode == "ellipse" && (sw % 3) != 1))
\ ? "both" : "square"
\ )
\ : (sw > 0 ) ? "horizontal"
\ : ( sh > 0) ? "vertical"
\ : ""

(mode_m != "") ? src.mt_expand (
\ thY=thY, thC=thC, mode=mode_m,
\ offx=offx, offy=offy, w=w, h=h, y=y, u=u, v=v, chroma=chroma
\ ).mt_expand_multi (
\ thY=thY, thC=thC, mode=mode,
\ offx=offx, offy=offy, w=w, h=h, y=y, u=u, v=v, chroma=chroma,
\ sw=sw-1, sh=sh-1
\ ) : src
}

Function mt_inpand_multi (clip src, int "thY", int "thC", string "mode",
\ int "offx", int "offy", int "w", int "h", int "y", int "u", int "v",
\ string "chroma", int "sw", int "sh")
{
sw = Default (sw, 1)
sh = Default (sh, 1)
mode = Default (mode, "rectangle")

mode_m =
\ (sw > 0 && sh > 0) ? (
\ (mode == "losange" || (mode == "ellipse" && (sw % 3) != 1))
\ ? "both" : "square"
\ )
\ : (sw > 0 ) ? "horizontal"
\ : ( sh > 0) ? "vertical"
\ : ""

(mode_m != "") ? src.mt_inpand (
\ thY=thY, thC=thC, mode=mode_m,
\ offx=offx, offy=offy, w=w, h=h, y=y, u=u, v=v, chroma=chroma
\ ).mt_inpand_multi (
\ thY=thY, thC=thC, mode=mode,
\ offx=offx, offy=offy, w=w, h=h, y=y, u=u, v=v, chroma=chroma,
\ sw=sw-1, sh=sh-1
\ ) : src
}


Though I don't know if the "common" parameters are in the right order (I'm too lazy to check the mt source code).

yup
21st September 2010, 17:51
Hi all!
I want organize following calculation:
source data
prefiltered prefiltered clip
3 masks center, backward and forward,
3 filtered clip centerfiltered, backwardfiltered and forwardfiltered
output=prefiltered
if (center<backward)&(center<forward) then output=centerfiltered
if (backward<center)&(backward<forward) then output=backwardfiltered
if (forward<bacward)&(forward<center) then output=forwardfiltered
Can this make using masktools?
Please advice.
yup.

Didée
21st September 2010, 18:17
Sure, that can be done. But sorry, the description of the chain is not clear enough.

- you create "3 masks center, backward and forward", but don't explain what is done with those masks

- how exactly are centerfiltered, backwardfilterd and forwardfiltered created? (Probably with the three masks from above...)

- what means "(center<backward)" etc.? Do you mean "pixel value is smaller"? Or rather "difference to prefiltered", or "difference to source", or ...

For "pixel value is smaller", you can use mt_logic(mode="min"). If it's really the difference-to-something, then you can use the Corrector() plugin.

yup
22nd September 2010, 04:54
@Didée:thanks:
It is very long story, hope you remember:)
http://forum.doom9.org/showthread.php?t=121197
3 masks center, backward and forward is min SAD value from both predictors (for center is backward1 and forward1, for backward backward1 and backward2, for forward forward1 and forward2 )
centerfiltered is median from 3 value center, backward and forward predictors.
backwardfiltered is median from 3 value center, backward and backward2 predictors.
forwardfiltered in a similar.
center<backward mean less by value and this try find better motion predictor from 3 variants.
yup.

yup
24th September 2010, 08:04
I think need use cascade mt_lutxyz

if (center<backward)&(center<forward) then output=centerfiltered

masktools equivalent

mt_lutxyz(center,backward,forward,'x y < x z < &')
output=mt_lutxy(last,centerfiltered,output, 'x y z?')

Please advice.
yup.

Manao
21st November 2010, 17:23
Yet another bugfix (http://manao4.free.fr/masktools-v2.0a46.zip), which concerns mt_lutf and "std" mode. Thanks again to TurboPascal7 for pointing out the bug.

kypec
1st December 2010, 11:57
Yet another bugfix (http://manao4.free.fr/masktools-v2.0a46.zip), which concerns mt_lutf and "std" mode. Thanks again to TurboPascal7 for pointing out the bug.
The download link in your first page still points to v2.0a45, please update it as well, thanks.

ChrisBeringB
6th December 2010, 15:40
How are the luts organized?
I'm asking because I'm worried about CPU cache locality.

Considering 'mask' is 99% zeros, which is better, speedwise:
a: MT_Lutxyz(mask, frame1, frame2, yexpr="some expression f(x,y,z)")
b: MT_Lutxyz(frame2, mask, frame1, yexpr="some expression f(y,z,x)")
c: MT_Lutxyz(frame1, frame2, mask, yexpr="some expression f(z,x,y)")

Same question could be asked for MT_Lutxy, but since the lut is small, it's not a big deal.

In the same vein, while trying to measure the speed difference, I noticed x264 didn't give exactly the same output for options a,b,c.
This suggests a fundamental bug.

Chris

Gavino
6th December 2010, 16:41
a: MT_Lutxyz(mask, frame1, frame2, yexpr="some expression f(x,y,z)")
b: MT_Lutxyz(frame2, mask, frame1, yexpr="some expression f(y,z,x)")
c: MT_Lutxyz(frame1, frame2, mask, yexpr="some expression f(z,x,y)")
...
I noticed x264 didn't give exactly the same output for options a,b,c.
This suggests a fundamental bug.

Perhaps just a typo, but you seem to have the expressions for b and c the wrong way round: b should be f(z,x,y) and c should be f(y,z,x). That might explain why you get different results.

ChrisBeringB
6th December 2010, 17:47
b and c are correct, but not that it matters - a,b and c are purely for illustrative purposes.
I imagined f(x,y,z) as a function that takes a mask as its first argument. So in b, when y=mask, all x'es are replaced with y's in f().

Chris

ChrisBeringB
6th December 2010, 18:49
MT_Adddiff and MT_Lutxy(yexpr="x y + 128 -")
doesn't yield the same results either.

Chris

Manao
6th December 2010, 19:05
Can you give precise examples ? Complete scripts ?

ChrisBeringB
6th December 2010, 21:06
q1=MT_Lutspa(BlankClip(width=256, height=256, pixel_type="YV12"), mode="absolute")
q2=q1.TurnRight
return Subtract(MT_Lutxy(q2, q1, yexpr="x y + 128 -"), MT_Adddiff(q2, q1)).levels(125, 1, 127, 0, 255, false).greyscale.converttorgb32

Shows that the two functions are indeed identical.

But in a complex script I have this line:
#mask2=MT_Adddiff(mask2, t)
mask2=MT_Lutxy(mask2, t, yexpr="x y + 128 -")

I get different, but consistent x264 encodings according to which line I use.
Very strange...

Chris

Manao
6th December 2010, 21:42
By default, both mt_adddiff and mt_lutxy (and actually, all filters from masktools, excepted mt_merge), create a random chroma channel (or, rather, U & V are malloc'd, but not memset'd). In order to have consistent encodings, you need either to add U=2, V=2 to both filters (that will copy the chroma channels from the source clip) or chroma="copy", or chroma = "128" (to set them to 128), or... Read the documentation, the part about common parameters (I know, it's easy to miss, everybody tends to jump directly to the filter list...)

My guess is that it also explains the behavior you're observing with mt_lutxyz.

Manao
6th December 2010, 21:45
As for mt_lutxyz cache coherency : the lut array is lut[x][y][z], so it's better if the first parameter is always constant. However, it's even better if you manage to avoid mt_lutxyz altogether...

ChrisBeringB
6th December 2010, 22:12
I've read your documentation carefully before using MT, and chroma isn't used at all in my script. Infact, after I first discovered the issue, I put greyscale on the output while doing further testing, just to be sure.

Thanks for the lut info - and yes, I try to use cascaded lutxy instead of lutxyz.

ChrisBeringB
6th December 2010, 22:21
mask2=MT_Adddiff(mask2, t, u=1, v=1)
mask2=MT_Lutxy(mask2, t, yexpr="x y + 128 -", u=1, v=1)
mask2=MT_Lutxy(mask2, t, yexpr="x y + 128 -")
Consistently gives the same result.
EDIT: also mask2=MT_Adddiff(mask2, t, u=0, v=0)

mask2=MT_Adddiff(mask2, t)
Consistently gives a different result.
EDIT: putting u=0, v=0 on every MT function in my script also yields this result.

In my script atleast.

Chris

yup
7th December 2010, 09:13
As for mt_lutxyz cache coherency : the lut array is lut[x][y][z], so it's better if the first parameter is always constant. However, it's even better if you manage to avoid mt_lutxyz altogether...
Yes when I replace one mt_lutxyz to two mt_lutxy my script load faster and VirtualDub consume less memory.
mt_lutxyz use very big table 256*256*256*4 by comparing to 256*256*3 for mt_lutxy and do not have chance place this at cache.
May be I wrong about size for table but I hope You understand.
yup.

Amateur
19th December 2010, 15:46
I tried using an older version, mftoon2 (mfToon-v0.54.avsi), but it keeps telling me that the "Unsharpmask" function cannot be found... I can't this function anywhere. Is it part of an older package I might be missing?

i too am getting this error and i didn't see an answer to his problem in this thread. i got the newest version of mask tools from manao's signature so where can i find unmask?

Didée
19th December 2010, 16:06
You go here (http://avisynth.org/warpenterprises/#warpsharp), download the ZIP for "warpsharp package". From that archive, you extract *only* the warpsharp.dll file to your plugins folder. (Do not extract any other files, unless you're asking for problems!);)

I'm not quite sure if that dll is compatible with auto-loading. In case it's not, load it manually with LoadPlugin().

Amateur
19th December 2010, 17:09
i have warpsharp.dll in the proper folder and still no luck. even tried adding a manual load plugin but i get the same error.

it says it's from line 78 of mftoon. do i have to actually change the mftoon script?

Amateur
22nd December 2010, 23:35
any more advice? i still haven't found a fix for this...

Didée
23rd December 2010, 09:36
Hmh. Maybe you get trapped by the plugin overloading feature. Empty your plugin folder from ALL plugins that smell like "warpsharp". Then manually load the warpsharp.dll from the linked package. (Here, locally, I've renamed the DLL to "warpsharp_package.dll" to avoid confusion with other warpsharp DLLs.)

Amateur
29th December 2010, 01:48
so i got your warpsharp package and now it's saying there is no maskedmerge. guess i'll try adding back things one by one to see if i can ever get this to work

edit: after adding everything back to my warpsharp package it now says that there is no function named YV12Layer from mftoon line 93.

edit 2: well replaing my previous warpsharp with the one you linked me to seemed to fix my problem with vmtoon (used to give me lots of white spots in all of my lines). maybe i'll see how that helps me. would still like to fix my mftoon problem though if possible

Didée
29th December 2010, 02:09
Well, yeah ... YV12Layer belongs to an outdated revision of the outdated v1.x branch of MaskTools (YV12Layer was in v1.4, and has been removed in v1.5 of MaskTools ... while the whole v1.x branch usually isn't used anymore.)

Short of saying mftoon is outdated. Get a time machine and travel 7 years back.

Amateur
29th December 2010, 04:13
oh so i should just stick with vmtoon? is that the improved mftoon? the guides i have found are probably old in that case. maybe you could pm me a list of your usual filters so i know what to read up on? that would be awesome

jmac698
29th December 2010, 13:26
I have a request that would make my life a lot easier. I'd like logic arithmetic operators available in the polish notiation, and I'd like to set the rounding mode to also truncate.
Try adding two 16 bit numbers with mt_lut, it's really a pain! I can't get a high byte because /256 will round, and there's no AND, so my only choice is to subtract expr 256 % 256 / to do it. Now try testing for carry from adding two 16bit numbers. That's a huge expression.
It seems like you could just not limit &. ie 255 15 & (should) gives 15 (but now 1) and still 1 1 == 0 0 == ^ gives 1, 1 1 == gives 1, so why limit & to 1 bit?

Gavino
29th December 2010, 17:02
It seems like you could just not limit &. ie 255 15 & (should) gives 15 (but now 1) and still 1 1 == 0 0 == ^ gives 1, 1 1 == gives 1, so why limit & to 1 bit?
The issue here is that the arithmetic is all done on floating point, so how would you interpret 246.1 & 14.8 ? There is also the question of backwards compatibility.

One possibility would be to introduce a separate integer mode, controlled by a new boolean parameter, in which internal values are manipulated as integers rather than float.

jmac698
29th December 2010, 20:07
That's easy, & only takes integers so cast it first, with truncate. There is perfect backward compatibility, the inputs to boolean are only 0 and 1 and a full range & handles this case. I see no problem.

Manao
29th December 2010, 20:12
Done (and a meaningless text for the 5 chars rule) (http://manao4.free.fr/masktools-v2.0a47.zip)

Gavino
29th December 2010, 20:58
That's easy, & only takes integers so cast it first, with truncate. There is perfect backward compatibility, the inputs to boolean are only 0 and 1 and a full range & handles this case. I see no problem.
But currently "1 2 &" produces 1, whereas a binary 'and' will give 0. Fortunately, Manao has solved that by using a different symbol for the arithmetic operators (&u, &s, etc).
Done
Impressively fast response (and not for the first time)! :)

By the way, how do you type the symbol for xor?
In the docs, it looks like "°" - I've always wondered if that was a typo. :confused:

Manao
29th December 2010, 21:18
It's not really a typo. I just never noticed that while the html file opened as a text file shows °, it appears as ° once displayed by browser. I guess I'll come around fixing that with the next release.

Gavino
29th December 2010, 21:31
If I open mt_masktools.html in Notepad, I still see "°".
And I don't have a "°" on my keyboard either. :(

jmac698
29th December 2010, 22:17
First of all, thanks Manao!! This just made 3 of my scripts at lot easier to finish :) Second of all, arghh! I'll explain why in a minute.
The mathematical symbol for XOR is a circle with a + in it. I'd guess he chose the degree symbol as a close replica. The problem is, on some keyboards (even english ones) no one knows how to type it. The answer is, hold ALT, type 248 on the numeric keypad only, then release ALT.
Now the argh.. I can't even type the symbol, because the moment I touch another key after it, Firefox thinks I hit "Back". I don't know why. It's like the 4th time I had to type this :)
I would suggest another symbol with exactly the same function, so we can use either one. I can see XOR in my future because it has uses for finding edges and filling. How do people feel about ` (it vaguely reminds me of ~) Really, the only other choices on my keyboard are _ or @.
Again, do these symbols appear on your keyboards?

Btw for the documentation try &deg; because it doesn't work for me either. Must be a different codepage or whatever you call it.

Update: Wait!! Thanks for adding again, but this doesn't solve my problem. I need to x y ff00 &u 256 /, so this helped for only one line and in fact, I still have to try the old technique for all other cases :( You must think I'm crazy but I don't use this for making masks at all, I have many other uses which are mostly pure arithmetic on entire videos.

Didée
29th December 2010, 23:06
There are true per-bit binary operations available through mt_logic. Perhaps the operation could be split up in smaller steps, with a combination of mt_lutxy and mt_logic?

BTW, on a german keyboard the ° sign is very easy to type. Here's another: °there°. And °some°°more°. Y°i°p°p°i°e°h - a°y - e°y! :p

jmac698
29th December 2010, 23:14
Nope, that's not the point. I'm working with higher precision intermediate values. It can't be broken down by definition that it's not an 8bit value.
My value that I'm working with only exists temporarily in a subexpression.

Manao
30th December 2010, 10:33
Wait!! Thanks for adding again, but this doesn't solve my problem. I need to x y ff00 &u 256 /, so this helped for only one line and in factYour operation is lacking (at least) one operator. What exactly are you trying to do ? I can drop the (arbitrary) clipping of operands to [0..255] or [-128..127], and clip instead to Uint32, Int32 or even Uint64 / Int64 (going over that couldn't make sense, since Int64 has more precision than the integer part of a double)

jmac698
30th December 2010, 12:03
Thanks for being understanding manao. I agree the limiting was arbitrary, the other operators (+-*/) don't have such rule. 32bit would be fine for me. Another idea I had is to include bit shifting, like 512 8 >> equals 2. I'm not sure what is the best order here, maybe 8 512 >> makes more sense.
Btw, I'd really love to have 4 clip expressions, but I realize the table method would reach it's limits. I did something crazy and tried to compute a correlation completely in masktools, it's almost but not quite possible without 4 values. I wasn't a plugin programmer then. But, if you wanted to add a correlation function, that would be fantastic ;) "x y corr"
Like I said, I found 3 completely different uses to operate on video with large valued intermediate results. In these cases I need to return the high byte and low byte.
Here's what I wrote so far:

#Set up some numbers in a video
Global v1=blankclip(pixel_type="YV12").tweak(bright=-255,coring=false).tweak(bright=0,coring=false)#v1=0
Global v2=blankclip(pixel_type="YV12").tweak(bright=-255,coring=false).tweak(bright=1,coring=false)#v2=1
mt_lut(v2,yexpr=highbyte("x 255 +"))#long winded way to get int(x/256)
#messageclip(highbyte("x 255 +"))#Use AvsP to read pixel values for the answer as well.
# Change the custom status line to print YUV values.

function highbyte(string s) {
s+" "+s+" 256 % - 256 /"#Expression to get high byte, needed to avoid rounding of x/256.
#So I am doing (x-(x%256))/256. Try this to get the 3rd high byte - it's ridiculous!
#Also warning this doesn't work for values >65535
}

function var(int v, string s) {
string(v)+" "+s#Make expression by substituting one variable
}

function highvar(int v, string s) {
highbyte(var(v,s))#High byte of a one variable expression
}

function lowbyte(string s) {
s+" 256 %"#Low byte of an expression
}

function lowvar(int v, string s) {
lowbyte(var(v,s))#Low byte of one variable expression
}

A shift function or no limit boolean arthmetic, and correlation (I know that's a big request, but I have the formula for you as well) either feature would make me extremely happy right now.

Manao
30th December 2010, 12:16
Expression to get high byte, needed to avoid rounding of x/256What rounding ?

jmac698
30th December 2010, 13:07
v1=blankclip(pixel_type="YV12")
expr="128 256 /"#128/256=1 shows rounding. int(128/256)=0
mt_lut(v1,yexpr=expr)
subtitle(expr+"=")
ScriptClip("""
subtitle(string(AverageLuma,"%1.0f"),x=84)
""")

Gavino
30th December 2010, 13:27
Perhaps all you need is the addition of an 'int' operator ('floor' and 'ceil' might be useful too).

jmac698
30th December 2010, 13:48
Yes, that's one of the options I mentioned: rounding mode including also truncate, meaning floor.
Whichever is easier - floor, >>, unrestricted boolean.
>> becomes pointless if there's floor. And can you include an alternate &deg; in your next build?
Thanks.

Manao
31st December 2010, 18:19
I've added trunc, ceil, floor (round already existed), left & right shifts (signed and unsigned), and @ can be used instead of °. Finally, before binary operations, it doesn't clip to an 8-bits integer anymore, but to a 64-bits one.

jmac698
31st December 2010, 19:25
Fantastic! I will be testing, trust me :)
I haven't seen this level of uesr satisfaction since AvsP development, and what a great tool that is now...

jmac698
2nd January 2011, 02:42
Is there a way to detect a minimum version 2.0a48 is loaded? Some way to get the version number?

jmac698
2nd January 2011, 06:07
It's working. Are repeated subexpressions optimized? I have to repeat a long subexpression 4 times to do what I want.

250 x y 256 * + + 60160 > 60160 250 x y 256 * + + ? 4096 < 4096 250 x y 256 * + + 60160 > 60160 250 x y 256 * + + ? ? 255 &u
Isn't that crazy? :) There's two improvements to this; one is to allow variables "10 a = a 2 +" gives 12, or include a clamp command "250 16 235 clamp" gives 235 and "65535 64 60160 clamp 8 >>" gives 235.
In my example, I could dramatically reduce the code to:
250 x y 256 * + + 4096 60160 clamp 255 &u
Btw, I know my use case is weird but clamp is perfectly usable for 8 bit uses.

Also, being able to specify hex numbers would be nice too, 60160=0xff00

What do you think of these ideas;
210 255 235 softthresh#pixels above 210 are set to 235, untouched otherwise
16 23 20 softthreshn#posterized to 32 levels starting at 20, 28...
5 27 16 softthreshn#posterize to 8 levels
would need floating point for the softthreshn to get say 219 ranges divided evenly. With color you could do some cartoon recoloring or Sin City effects, like a range of red to pure red lipstick etc. You can't specify tint without two channels at once though... would make a really nice mask though. How would you do that now?
What about color swapping, you need at most to replace two colors at once, ie switch red with green in ranges, with or without setting to a single color. What about
40 48 138 144 44 142 recolor#make close to yellow into pure yellow ulow vlow uhigh vhigh ureplace vreplace
40 48 138 144 76 62 68 54 swapcolor#switch near yellow with near green ulow1 vlow1 uhigh1 vhigh1 ulow2 uhigh2 vlow2 vhigh2
and bluescreen effects:
208 110 216 118 x recolor#replace near blue with part of second clip
You could even replace specific shades with lutspa like functionality.. like if you had a sunset you could match all shades of it and replace with a new smoothly generated one based on y coordinate.

kypec
3rd January 2011, 10:17
Though I don't use MaskTools in any other way than what is provided by more experienced users (-Vit-, LaTo, Dideé) I have to ask: what is wrong with ^ symbol for XOR operator? Seeing how many of you are struggling with ° and others are proposing @ for that purpose I just had to ask...

jmac698
3rd January 2011, 11:04
It's used for exponentiation. The whole symbol set could be redone but that would break compatibility. @ is being used now in the latest alpha.

jmac698
3rd January 2011, 14:50
Me again :) Rand would be really useful right about now, I'm working on dithering. I can work around it with another plugin, however.
I think low high RAND would be good. Clipping RAND is not the same; the probabilities of 16 and 235 would increase. Luckily I only need an 8bit random number today.

Didée
3rd January 2011, 15:03
Luckily I only need an 8bit random number today.
At some point, the thing you really need is a compiler. ;)

jmac698
3rd January 2011, 15:59
lol, true, true :)
It's a long term thing, steep learning curve. I find scripting more productive in general, because of the write/test cycle.
A compiler can't keep up with the rate I generate ideas - you're inspired for a week, and that's all you got to get something done.

Manao
3rd January 2011, 18:15
If you want a rand, use mt_lutxy(clip, clip.addgrain).

cretindesalpes
3rd January 2011, 19:11
I'm working on dithering.
Maybe you would be interested by my dithering package? See my signature below.

IanB
3rd January 2011, 22:08
Remember when dealing with "random" elements in frame data the frame data must be the same every time you generate that frame.

Very early versions of addgrain() just grabbed a new random sequence for every GetFrame(N) call independant of N. This caused strange behaviour when accessing the same frames multiple times and only some were able to be cached. The fix was to remember the random key for each frame N, such that whenever frame N was rendered the exact same results could be returned.

Manao's solution, mt_lutxy(clip, clip.addgrain), is a good one because addgrain() is now well behaved and you get different randomness for each frame, but a given frame is always the same.

Remember all the mt_lux* are using static Look Up Tables that are created once in the filter constructor (compile time) and reused very fast in the GetFrame calls (run time). So having rand in the expression would still have the same LUT for every frame, which I suspect would be not quite what would be wanted. And as an added bonus for confusion repeated runs of the same script might produce different random results.

Mini-Me
19th January 2011, 03:33
Hey, can anyone point me to the documentation for mt_lutspa? It's not in the Readme with masktools-v2.0a48, and it's not at http://manao4.free.fr/MaskTools.htm or http://manao4.free.fr/mt_masktools.html. I've done a search on this forum, but the most I've found is a debate in this thread over placement of the "relative" parameter.

EDIT: I've pretty much figured it out now, but it'd still be nice to see the documentation so I can learn some more of the options. :)

Manao
19th January 2011, 08:23
There's an up to date mt_masktools.htm bundled in the zip package, in the directory masktools/documentation. I'll take care to place it in the root directory in the next releases.

Mini-Me
19th January 2011, 08:43
There's an up to date mt_masktools.htm bundled in the zip package, in the directory masktools/documentation. I'll take care to place it in the root directory in the next releases.

Thanks, Manao! :)

Dogway
9th February 2011, 18:57
with mt_edge, how can I shift one pixel without degrading chroma?

I use:
move = "
0 0 0
0 0 0
0 0 1 1"
mt_edge(move,0,255,0,255,U=3,V=3)

But chroma misaligns.

Also there is a possibility that mt_edge would leave black pixels when shifted?

Manao
9th February 2011, 19:33
If you want to do it with mt_edge, do move_luma = "
0 0 0
0 0 0
0 0 1 1"
move_chroma = "
0 0 0
0 1 1
0 1 1 4"
mt_edge(move_luma,0,255,0,255,Y=3,U=2,V=2).mt_edge(move_chroma,0,255,0,255,Y=2,U=3,V=3)You could also use one of the resize function of avisynth (they have crop parameters that ought to do what you want too).

Dogway
9th February 2011, 19:45
Thanks! it was worth asking as I see. Im mainly doing so to avoid resizing.
Now its aligned but I guess degrading can't be avoided.

What about the black border?


EDIT: upss! the chroma subsampling, got it.

Nephilis
13th February 2011, 19:38
İs it possible to add the laplacian-gaussian edge detection method in mt_edge function ?

Didée
13th February 2011, 23:52
blur(1).mt_edge("laplace")

Gavino
16th February 2011, 01:11
I've added trunc, ceil, floor (round already existed), left & right shifts (signed and unsigned), and @ can be used instead of °.
None of these new operators seem to be recognised by mt_polish().
trunc, ceil and floor are also missing from the body of the documentation (but are mentioned in the changelog).

yup
16th February 2011, 13:30
Hi all!

Please advice how create mask. If one pixel in horizontal line true (255) all pixel line could be true (255).

yup.

Didée
16th February 2011, 13:39
Does this work? (Can't try it right now...)

mask1 = whatever # this' the mask with some 255-white pixels in it

mask2 = mask1.mt_lut(Y=-255)
black = mask1.mt_lut(Y=0)

v1=interleave(mask1,black).assumefieldbased.assumetff.weave
v2=interleave(mask2,black).assumefieldbased.assumetff.weave

mt_hysteresis(v1,v2)
separatefields.selecteven.assumeframebased

yup
17th February 2011, 07:23
Does this work? (Can't try it right now...)

mask1 = whatever # this' the mask with some 255-white pixels in it

mask2 = mask1.mt_lut(Y=-255)
black = mask1.mt_lut(Y=0)

v1=interleave(mask1,black).assumefieldbased.assumetff.weave
v2=interleave(mask2,black).assumefieldbased.assumetff.weave

mt_hysteresis(v1,v2)
separatefields.selecteven.assumeframebased
Didée:thanks:
It is work.
I am not find full description mt_hysteresis.
Please advice.
yup.

Didée
17th February 2011, 12:56
Hehe, I never have used mt_hysteresis before. Now, by actually trying it, I get an all-white screen from the above script. Seems that mt_hysteresis forces full expansion for any pixel that's not exactly black. (?)

thresh = 254 # only pixels brighter than "thresh" will be considered
mask1 = whatever # this' the mask with some 255-white pixels in it
mask1a = mask1.mt_binarize(thresh)

mask2 = mask1.mt_lut(Y=-255)
black = mask1.mt_lut(Y=0)

v1=interleave(mask1a,black).assumefieldbased.assumetff.weave
v2=interleave(mask2,black).assumefieldbased.assumetff.weave

mt_hysteresis(v1,v2)
separatefields.selecteven.assumeframebased

Now it gives the expected result.

yup
18th February 2011, 14:40
Didée!
My mask contain 0 or 255 value after call
SDIad=mt_lutxy(SDI,SDIavg,"x "+THAVG+" y * > x 128 > & 255 0 ?",U=-128,V=-128)
Though I see gray pixel.
yup.

Didée
18th February 2011, 17:04
But my test gave correct result.

Wait - colorspace? Scanline masking smells like VHS capture. VHS capture smells like YUY2. My test was with YV12 video, in Avisynth 2.5.8.

yup
18th February 2011, 17:44
Didée
full script
http://forum.doom9.org/showthread.php?p=1478030#post1478030
Source VHS capture YUY2 colorspace.
Grey point give my mask and after using Your code I see grey line at place grey point and white line at place white point.
I am using only hard threshold with If statement and planing use Your code for mask creation for long black or white line (as noise) with tail from separated pixels.
Please advice.
yup.

Didée
18th February 2011, 19:38
I don't see it. For me it works correctly.

Input image: (random TV show, simple "bob()", followed by "sharpen(1)" so that some pixels get full white)

http://img715.imageshack.us/img715/2305/framewithwhitepoints.th.png (http://img715.imageshack.us/i/framewithwhitepoints.png/)


Result of the script I posted at last:

http://img510.imageshack.us/img510/1460/framewithwhitepointssca.th.png (http://img510.imageshack.us/i/framewithwhitepointssca.png/)


Everything like it should be. The white lines are only there where the input has Y=255 pixels. No grey pixels anywhere. The mask contains only Y=0 and Y=255 pixels. Nothing else.

yup
19th February 2011, 06:57
Didée!
Problem related with my script (see link at previous my post). Your solution work fine. I can not understand how I can get grey value after If statement with output 0 or 255 and after median filtering and series inpand expand call.
yup.

Mini-Me
27th February 2011, 08:27
Manao, I did a quick search on edge-detection kernels tonight to determine which I should use, and I actually stumbled across a new edge-detection kernel you might be interested in. In fact, it's so new that it seems it was just published a day ago or so. (I feel all warm and fuzzy inside being one of the first to see it! ;)) It seems to significantly improve upon the resolution of older edge-detection kernels by leveraging the {1/4, 3/4, 3/4, 1/4} convolution kernel that I think you may be familiar with from your YV12 conversion code. Anyway, you can check it out here:
http://assassinationscience.com/johncostella/edgedetect/

EDIT: FYI, it seems the rest of the website, especially the main page, is...um, highly unrelated and quite political, to say the least. :eek: The kernel itself seems interesting though.

Didée
27th February 2011, 16:22
Interesting presentation of hot air.

(I didn't look at the source code .... and I wouldn't expect to find miracles in there.)

The "magic upsizing" is strikingly similar to what you get with a plain BicubicResize. (Mitchell+Netravali, b=0.333,c=0.333).

Regarding the "magic kernel", compare to this:

imagesource("original.png")
bicubicresize(600,800)
converttoyv12(matrix="PC.601") # keep full range without loss
mt_edge("prewitt",0,255,0,255) # standard.
mt_lut("x 1 1.16 / ^ 1.62 *") # basically not needed. It's just to make local intensities more similar to the comparant
converttorgb32(matrix="PC.601") # undo again
return(last)

The result: (please compare for yourself to what is presented on that site)

http://img26.imageshack.us/img26/1817/magicunmagicked.th.png (http://img26.imageshack.us/i/magicunmagicked.png/)

Aahh - magic!!

:rolleyes:

Mini-Me
27th February 2011, 19:26
Interesting presentation of hot air.

(I didn't look at the source code .... and I wouldn't expect to find miracles in there.)

The "magic upsizing" is strikingly similar to what you get with a plain BicubicResize. (Mitchell+Netravali, b=0.333,c=0.333).

Regarding the "magic kernel", compare to this:

imagesource("original.png")
bicubicresize(600,800)
converttoyv12(matrix="PC.601") # keep full range without loss
edge=mt_edge("prewitt",0,255,0,255) # standard.
mt_lut("x 1 1.16 / ^ 1.62 *") # basically not needed. It's just to make local intensities more similar to the comparant
converttorgb32(matrix="PC.601") # undo again
return(last)

The result: (please compare for yourself to what is presented on that site)

http://img26.imageshack.us/img26/1817/magicunmagicked.th.png (http://img26.imageshack.us/i/magicunmagicked.png/)

Aahh - magic!!

:rolleyes:

Interesting. I wasn't really sold on the "magic" aspect of his upsizing kernel either, but I was under the impression that the upsizing itself was only one aspect of the resolution increase, the other being the upsize's ability to get identical vertical and horizontal gradient sampling positions out of naive finite differences (which operate over single pixel boundaries instead of skipping one, like blurry central differences). The latter is a real issue with finite differences in fluid simulation (which is why MAC grids are generally used), so I thought his method might have made an improvement in that area for edge detection too. Your own result is extremely similar to his though (e.g. the "Uptown" text on the right), so the improvement must be coming primarily from the upsizing alone.

Posting it was still worth it though, since I learned a simple upsize might do the trick for what I'm trying to do today. ;)

Didée
27th February 2011, 19:39
Small note - of course, once again I destroyed the script while making it "readable" in the post editor.:D - In the "edge=mt_edge(..." line, the "edge=" must not be there.

Original script corrected.


Btw, if I interpret the text correctly, assassinscience states that the edge detector was run on the small (=original) image, and only the result was upscaled by x2. But frankly, I'm not fully conviced. When looking closely, there are several locations in his edgemask with very thin strands of black, surrounded only by a few antialiasing pixels. (I.e. similar to 1-pixel-width lines.) It's a bit hard to imagine that this characteristic could be present when the mask was created on x1, then upscaled to x2. If I had to guess, I'd rather suppose that he did the masking on the x2 image in fact. But I might be wrong here.

Mini-Me
27th February 2011, 20:09
Small note - of course, once again I destroyed the script while making it "readable" in the post editor.:D - In the "edge=mt_edge(..." line, the "edge=" must not be there.

Original script corrected.


Btw, if I interpret the text correctly, assassinscience states that the edge detector was run on the small (=original) image, and only the result was upscaled by x2. But frankly, I'm not fully conviced. When looking closely, there are several locations in his edgemask with very thin strands of black, surrounded only by a few antialiasing pixels. (I.e. similar to 1-pixel-width lines.) It's a bit hard to imagine that this characteristic could be present when the mask was created on x1, then upscaled to x2. If I had to guess, I'd rather suppose that he did the masking on the x2 image in fact. But I might be wrong here.

I think he was talking about two separable steps:
1.) Take a naive (biased, adjacent) first difference in the x-direction and upsize (and eliminate the top and bottom rows, I guess).
2.) Take a naive (biased, adjacent) first difference in the y-direction and upsize (and eliminate the top and bottom rows, I guess).
(I'm not sure if he really means to eliminate the top and bottom rows for both the x and y images, or if you're supposed to remove the first and last columns for one of them...but whatever.)
The two upscaled images would then be combined like with any separable edge-detection filters. Since the upscaled x and y gradient images had exactly coinciding sample positions (due to his sampling kernel), that is supposed to account for the resulting high resolution.

That's my understanding, at least. It's clever assuming his math is correct, but it's kind of useless if upscaling and using a Prewitt kernel is just as good (unless there are advantages after downscaling again with the same kernel or something).

Didée
27th February 2011, 20:31
I'm viewing simply from a "common sense" point of view. Look closely at the following, and *think* about it.

http://img830.imageshack.us/img830/8381/detailq.png (http://img830.imageshack.us/i/detailq.png/)

The claim is that this B/W mask was created on the small image. What we see ^here^ is a 200% upscale. Do you really think you'd get such narrow features in a 200% upscale? If the upscale contains 1-pixel-thin features, how would the representation have been at half the size (i.e. "original" size)?? Take into account that the proposed upscaling method apparently is rather "soft", or at least not particularly sharp, as can be seen in the upscale of the base image.

If he upscales a natural image with a given algorithm, then the result is very blurry. But, if he upscales a B/W edgemask with the same algorithm, then the result is ultra-sharp, producing 1-pixel-thin features?

Seems strange to me. Nothing I would bet my money on. ;)

Mini-Me
27th February 2011, 20:57
I'm viewing simply from a "common sense" point of view. Look closely at the following, and *think* about it.

http://img830.imageshack.us/img830/8381/detailq.png (http://img830.imageshack.us/i/detailq.png/)

The claim is that this B/W mask was created on the small image. What we see ^here^ is a 200% upscale. Do you really think you'd get such narrow features in a 200% upscale? If the upscale contains 1-pixel-thin features, how would the representation have been at half the size (i.e. "original" size)?? Take into account that the proposed upscaling method apparently is rather "soft", or at least not particularly sharp, as can be seen in the upscale of the base image.

If he upscales a natural image with a given algorithm, then the result is very blurry. But, if he upscales a B/W edgemask with the same algorithm, then the result is ultra-sharp, producing 1-pixel-thin features?

Seems strange to me. Nothing I would bet my money on. ;)

When I really look at the image, the "1-pixel-thin" features actually look a little wider than that. There's some smoothing involved (the spacing between the centers of the white lines is ~5 pixels rather than 2), even if the darkest parts are only 1 pixel wide. Notice also that the darkest parts are usually some medium-dark gray, not black or very dark gray. I agree that the edges are very high-resolution though, perhaps "suspiciously" high-resolution, but it would be pretty silly of the guy to embarrass himself with a deliberate edge-detection kernel hoax, so I'm not ready to jump to that conclusion. ;)

I'm not at the point where I'd put money on it in either direction, but there's still an explanation that could account for the high resolution edges we're seeing: Most edge detection kernels, including the Prewitt kernel, use a central difference. Although it eliminates bias and lines up horizontal and vertical sampling positions, it inherently halves the resolution of the gradient/edges relative to the original image. Therefore, we're used to seeing half-resolution edge images, and that's our basis for comparison. In order to get full resolution edges, we actually need to upscale the original image and then perform edge detection, as you did in your script above.

In contrast, using a naive difference (like he does) gives us full-resolution edges in a single dimension, without having to upscale first. As an experiment, compare the following two operations:
Detect edges in the x-dimension ONLY using a naive first difference, then upscale. ([0 0 0 0 -1 1 0 0 0] edge-detection kernel, then upscale).
Upscale, then detect edges in the x-dimension ONLY with a central difference. (Upscale, then [0 0 0 -1 0 1 0 0 0].).
Actually, here's a script:

clip = Avisource("whatever.avi")
xedgesnaive = clip.mt_edge("0 0 0 0 -1 1 0 0 0", 0, 255, 0, 255).BicubicResize(clip.Width * 2, clip.Height * 2).Greyscale()
xedgescentral = clip.BicubicResize(clip.Width * 2, clip.Height * 2).mt_edge("0 0 0 -1 0 1 0 0 0", 0, 255, 0, 255).Greyscale()
return Interleave(xedgesnaive, xedgescentral)

You should get extremely similar results, just offset a bit. (You might need to brighten both up with luts or levels though.) In some areas the first clip does better, and in other areas the second clip does, but they're definitely of comparable quality. (EDIT: WROOOOOOOONG. ;))* As another experiment, do it without any resizes at all, and the naive version will have edges as narrow as half the width of the central version. This is because the naive first difference gets full resolution edges, whereas a central difference cannot (and upscaling first is necessary to accomplish that). The problem with naive first differences is that combining x-direction and y-direction edges doesn't usually work well. x-direction edges are shifted a half-pixel horizontally, and y-direction edges are shifted a half-pixel vertically. Without any clever resampling, the mismatched sampling positions will not fit together well, giving ugly combined x-and-y-direction edges. However, his goal was to cleverly upsample the x-direction and y-direction edges in such a way that the sampling positions lined up in the upscaled image (without blurring too much), and supposedly his kernel accomplishes this. If this is the case, I think it makes sense for him to be getting the results he's getting.

* EDIT: Actually, it turns out this is incorrect. I was getting comparable quality for my test clip, but using the test image he used and you used, the central difference in my comparison is WAY better. Upscaling a naive differenced-image looks like total crap. In short, you're right, and I have to agree with you that either:
a.) His description does not match his code.
b.) He's a wizard, or his kernel is way better at anti-aliasing than any of the upsizers I've tried (doubt it).

ajp_anton
10th April 2011, 01:02
You've "recently" added the function "mt_lutspa".
Wouldn't it make more sense to build it into the regular mt_lut(xy(z))? For example, "cx" and "cy" could return the x and y coordinates of the current pixel. Also, you could take it further and add "y-5,+1" which would return the value from clip y at a position (-5,1) from the current position ("y0,0" would be the same as old "y"). This way you could do basically anything (even simple blurring) with one function.
It may go beyond the original intention of *mask*tools, but does it matter? =)

Manao
10th April 2011, 08:51
Not really. I'm limited by the size of the LUT :
- mt_lut uses 3 * 256 bytes
- mt_lutxy uses 3 * 256 * 256 bytes
- mt_lutxyz uses 3 * 256 * 256 * 256 bytes
- mt_lutspa uses 1.5 * width * height bytes

Merging mt_lutxy with mt_lutspa would take up 3 * 256 * 256 * width * height, which is more than 2GB.

Of course, I could go the generic way, and compute the results of the arithmetic expression for each pixels. But I shudder thinking how slow that would be (hint : a script mt_lutxyz takes a long time to open, and the longer the expression, the slower it gets. And that's just to compute 16 millions values, ie 8 frames in 1920x1080).

ajp_anton
10th April 2011, 14:13
Ah, didn't realize that's how it works.
It's just a lot of work to make a mt_lut that depends on for example the height... I have to make a gradient with mt_lutspa and use it as the second clip in mt_lutxy, and because the video is only 8-bit, for heights over 256 pixels I have to use another finer gradient as the 3rd clip in mt_lutxyz.

jmac698
23rd April 2011, 08:46
Manao,
Thanks again for the features of a48 - but now I'm doing something else advanced. Do the lutf modes return full precision? It seems not. I really need this. I made a script to calculate a correlation, and it works great with std. But if I multiply std by 2 I always get even numbers, which shows there's no more precision.

#a source....
scriptclip("""
std=mt_lutf(x,x,"std",expr="x 2 *").averageluma
subtitle(y=80,"std="+string(std))
""")

The loss of precision is too much for me to use my correlation reliably. Note that the runtime variable averageluma does give a real floating point number.

yup
3rd May 2011, 10:17
Hi All!
I find error
http://forum.doom9.org/showthread.php?p=1496587#post1496587
Today I tested with official 2.6 build, the same error message. 2.5 version masktools work fine. QTGMC script need use other conversion not Interleaved2Planar for 2.6 masktools version?
yup.

Manao
3rd May 2011, 20:12
yup : both avisynth 2.6 and masktools 2.6 support planar YV16, so instead of using interleaved2Planar (which is a hack for avisynth 2.5) just use converttoyv16.

jmac698 : noted, I'll add a parameter to increase the precision of std/average when used in mt_lutf

yup
5th May 2011, 06:29
Manao :thanks: for clarification.
Will be waiting until other plugin writer will be support planar colorspace for Avisynth 2.6.
yup.

jmac698
5th May 2011, 09:54
Manao,
Would it be possible to create a corr mode in lutf? For correlation.

Manao
5th May 2011, 11:40
jmac698 : not really. To compute a correlation, I would need two sets of values. Right now, mt_lutf's mode works only on pixels that comes from one clip, then use the computed value in another lut, that uses pixels from another clip. What it seems you want to do is working on both clips in the first step, is that it ? I can do that, but it starts getting quite specific. Would you care to explain what you want to achieve ? What's the bigger picture here ?

jmac698
5th May 2011, 22:20
You're right, that doesn't work well with lutf. What I can see a need for is collecting the pixels of one or two clips to return a single (and internally high precision) value. This value can't necessarily be applied in a formula to the pixels of another clip.
In my case I'm using lutf(x,x) and never referring to y as a workaround. But there are even functions where it makes no sense to apply to y. This new command would retain some features of lutf and add more operations, like lutfx(mode,x) where mode is std, avg, median, min, max, peak, and lutfxy(mode, x, y) where mode is corr, sad, sub. Peak means to return the position of the brightest pixel in the clip. But how to return two values? I probably want to use the position information to do a shift in another clip. Maybe add a new "x y shift" operation in the strings?

As for the big picture, correlation returns exactly the same number between two lists/images even if:
-one has some constant value added to each pixel (differences in brightness)
-one has each pixel multiplied by some value (differences in contrast)
-each has the same type of noise (grain, noise, salt n pepper) (same expected value at least)
-one is shifted (line jitter, but the black filler adds some error)
The use of compariing two noisy and different levels pictures helps find same/different or duplicate frames, which can be used to find cuts/dropouts/insertions/dupes in film, or analog video.
I'm using it to find missing frames between two analog recordings where each has random (but sparse) frame drops, and different noise and horizontal shift and even recording levels. You can also use it to detect re-edits and censoring, frame rate conversion, IVTC.
I also use correlation to find relative spatial shifts of the same image. If I use known images, I can have the correlation give the pixel shift directly. I could record a short sine and then learn the horizontal line jitter precisely.
So I am using the output of the collected pixels of the clip(s) for raw calculations or to apply an image shift.

StainlessS
23rd May 2011, 17:00
Manao :thanks: for clarification.
Will be waiting until other plugin writer will be support planar colorspace for Avisynth 2.6.
yup.

I've just come across similar breakage in a script of mine.
I sort of, rectified the problem by renaming the 2.5 dll from

"mt_masktools-25.dll" to "mt_masktools_25.dll"
(NOTE the underscore rather than hyphen)

and used eg:-

msadf = sadf.mt_masktools_25_MT_Binarize()


to select the Planar YUY2 functional dll.

Also, renamed 2.6 with underscore, unfortunately, calling
2.5 dll with the dll name made a second anadorned call
(without dll name specification) also call the 2.5 dll.
Looks like the pluginin call order will then default to the
2.5 dll, so you would need to make all calls using the
extended calling convention.

Documentation for extended calling convetion in :-

Avisynth 2.5.8 help / AviSynth Syntax - Plugins /
Plugin autoload and conflicting function names v2.55

Suggest ALL future dll's use names valid for script variables and
script functions (with the ".DLL" appended).
From Avisynth help:

A variable name can be a character string of practically any
length (more than 4000 characters in Avisynth 2.56 and later)
that contains (English) letters, digits, and underscores (_), but
no other characters. The name cannot start with a digit.

Not any kind of convienient fix, doubt it will be of any help, but thought I should mention the above.
Shame that the dll name has a hyphen in it, ALL similarliy named dll's will break the above calling convention.

EDIT:- There does not seem to be any indication in the
MaskTools Changelog about the point at which the
interleaved2planar hack was removed, presumably, all
2.6 versions are without it.

leeperry
30th May 2011, 21:15
Bonjour,

Thanks for the great masktools, all my fav plugins use it :)

I was wondering, I use LSF and GrainFactory3 in realtime in ffdshow, is there a way you could implement 16bit? like the hack recently added to SmoothAdjust() that I also use: http://forum.doom9.org/showpost.php?p=1504207&postcount=210

I run Avisynth 2.6 if that matters.

:thanks: for considering it!

jmac698
27th July 2011, 05:05
I second that. I think I am one of the first pushing for 16bit. Keep asking for any useful new plugin.
Also, I found a need for atan2, that would be finding the angle from cartesian coordinates. Wikepedia has a good formula for implementation. atan2(x,y)->-pi to +pi.
ps I can't tell you how useful this plugin is, especially since a48. I make a lot of weird scientific scripts, and always I need it for calculations. I would never be so productive if I had to compile all my ideas into plugins each time.

LaTo
27th July 2011, 09:15
Bonjour,

Thanks for the great masktools, all my fav plugins use it :)

I was wondering, I use LSF and GrainFactory3 in realtime in ffdshow, is there a way you could implement 16bit? like the hack recently added to SmoothAdjust() that I also use: http://forum.doom9.org/showpost.php?p=1504207&postcount=210

I run Avisynth 2.6 if that matters.

:thanks: for considering it!
I second that. I think I am one of the first pushing for 16bit. Keep asking for any useful new plugin.
Also, I found a need for atan2, that would be finding the angle from cartesian coordinates. Wikepedia has a good formula for implementation. atan2(x,y)->-pi to +pi.
ps I can't tell you how useful this plugin is, especially since a48. I make a lot of weird scientific scripts, and always I need it for calculations. I would never be so productive if I had to compile all my ideas into plugins each time.


For a simple LUT (mt_lut) you can use SmoothCustom16(Yexpr="...",Uexpr="...",Vexpr="...",smooth=0) in SmoothAdjust v2.0beta7

:)

jmac698
27th July 2011, 14:15
Hmm, if that does standard deviation in 16bit, you're my new BFF :) I need high precision std in order to do a correlation.
Hey, could you do a correlation function in your plugin? x y corr calculate the corr correlation returning -1 to +1.
There is a corr 2d plugin but it's mostly for finding spatial shift. You could read the pixel value at no shift but you'd only get an 8 bit value.

um3k
27th July 2011, 18:12
Would it be possible to implement 32-bit intermediates? This would make it possible to use multiple MaskTools filters without dropping to 8-bit in between them. Obviously it would need to be a bit of a hack, I'm thinking dividing up the 32 bit values into 8 bit by simple binary means, and then interleaving them horizontally. Should be pretty simple to support within MaskTools, I would think. Seems like it would be a simple matter of interpreting the image as 32 bit. Given, the intermediate images would look like garbage data, but with an additional filter to convert between 8 bit and 32 bit and vice versa (to be used on either end of a chain of masktools filters), it should be quite usable.

One possible use: Generating a high bit depth mask with mt_lutspa, then applying it with another MT filter.

jmac698
27th July 2011, 20:10
If you look at my deepcolor tools, you'll see there's a way to calculate the high then low bits of a result in the expression, but using 8 >> and 255 &&. I store my MSB and LSB in differenent clips, smoothlevels uses vertically stacked videos. Smoothlevels should be able to do what you want anyhow.

I'm thinking of writing a package for precise manipulation that handles all the details, with an extra line of video containing meta data like chroma sampling and colorspace, and you need to open the video with the package and also specify the destination codec so it can handle the chroma placement and colorspace conversions at the end, and also hold intermediates in high bit and even linear colorspaces. And no more "hints" being hidden in the low bits of the video like from dgindex (?).

leeperry
27th July 2011, 22:27
Would it be possible to implement 32-bit intermediates? This would make it possible to use multiple MaskTools filters without dropping to 8-bit in between them.
I already discussed this point w/ Manao as I'd love to be able to use a 16bit pipeline w/ SmoothLevels() and all...he told me that he was too busy atm and might think about it when time allows.

jmac698
29th July 2011, 11:09
Hey,
I have my first request that's actually a mask function! I've been reading up on algorithms and I need a Euclidean distance mask. How it would work is you have a white mask of some pixels, and an original clip. For each pixel, output the distance to the nearest mask pixel. This will be used as a weight.

cretindesalpes
29th July 2011, 11:34
I need a Euclidean distance mask.
Check Tritical's tcanny (http://web.missouri.edu/~kes25c/), it has a tdtrans() function doing exactly what you need.

jmac698
6th August 2011, 18:30
Thanks! I discovered that custom weights in luts doesn't take -ve numbers, but I found a workaround with lutsx. Can you support -ve weights?
Also found offx=1 doesn't work. Why can I have 1 pixel access in my other calculations, but not with offset? It seems like the offset handling could be moved into the pixel loop or something.
I'd really like to be able to access u,v in my formulas for y. Though I can fudge it with lutxyz(utoy,vtoy..), I run out of arguments, and also it would be faster.
I'm using some functions for the first time, masktools is just brilliant. I think it will be "finished" with just a few more tweaks.

wonkey_monkey
7th August 2011, 13:22
Could someone explain the following behaviour for me?

video=mpeg2source("loop.d2v") # yv12
blank=video.blankclip
mt_lutxy(video,blank,"x y +")
return interleave(video,last)


The output frames are lighter than the input, but I was expecting them to be identical. I assume it's some kind of 16-235 range thing - can I stop masktools behaving that way?

David

ajp_anton
7th August 2011, 15:10
It's because blankclip creates pixels with value 16 (TV-levels black).
Don't know if you can create PC-levels there, but otherwise you can tweak it down to 0 (using coring=false).

um3k
7th August 2011, 17:11
This:
video=mpeg2source("loop.d2v") # yv12
blank=video.blankclip
mt_lutxy(video,blank,"x 16 - y 16 - + 16 +")
return interleave(video,last)
Should give you the effect you're looking for. What it does is subtract 16 from both clips, making black=0. It then adds them, then adds back 16.

Didée
7th August 2011, 22:26
Or as a possible alternative, use mt_lut instead of blankclip

video=mpeg2source("loop.d2v") # yv12
blank=video.mt_lut(Y=0,U=-128,V=-128) # luma=black, chroma=grey
mt_lutxy(video,blank,"x y +")
return interleave(video,last)

SSH4
7th August 2011, 23:13
looks like mt_lut(Y=0,U=-128,V=-128) use less memory ot less buggy than blankclip. Because the changing blanclip to mt_lut stable my script in Setmtmode(2) mode Avisynth.

yup
28th September 2011, 08:58
Hi All!

Please advice how implement pixels set n-1 pixels from left and current, I can write '"0 0 0 -1 0 -2.... 0 n-1", but I want make n variable. It is need for xx_pand and mt_luts functions.

yup.

jmac698
28th September 2011, 16:54
@rean

the same operation
as "add", but only when the result is BRIGHTER than the
base the new values are used.

So it's something like x y + x > ? x y + x
In other words, if (x+y)>x ? x+y : x

@yup

mt_rectangle : int hor_radius(1), int ver_radius(1), bool zero(true)

so mt_rectangle(1,n,true)

yup
29th September 2011, 06:25
jmac698!
mt_rectangle(1,n,true)
give rectangle with side 3 vertical pixel and 2*n+1 horizontal.
I need only line to left or right side n pixels length.
Can implement with recursive call but work slowly.
yup.

jmac698
29th September 2011, 17:49
Ok, easier way

n=2
LineStr="0 0 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 "
LineN=LeftStr(LineStr,n*4-1)

SSH4
29th September 2011, 18:42
Is this bug or limitation on latest mt_merge when i want overlay smaller size clip over bigger size with mask like i can made with Overlay(b,a,left,top,mask=z_mask)
when i try made this with mt_merge(biger,smaller,z_mask,luma=true,offX=left,offY=top)

i have this on AvsP:
Traceback (most recent call last):
File "AvsP.pyo", line 8071, in OnSliderReleased
File "AvsP.pyo", line 11075, in ShowVideoFrame
File "AvsP.pyo", line 11662, in PaintAVIFrame
File "pyavs.pyo", line 343, in DrawFrame
File "pyavs.pyo", line 320, in _GetFrame
File "avisynth.pyo", line 277, in GetFrame
WindowsError: exception: access violation reading 0x46688000
Traceback (most recent call last):
File "AvsP.pyo", line 9067, in OnFocusVideoWindow
File "AvsP.pyo", line 10493, in SetVideoStatusText
File "AvsP.pyo", line 10615, in GetVideoInfoDict
TypeError: %d format: a number is required, not float

biger clip have size about 1968x1064 smaller 1920x1080.

cretindesalpes
29th September 2011, 21:40
Actually I never could make the Masktools functions work with clips of different sizes. It always crashes.

SSH4
29th September 2011, 22:15
oh. this is my fault. mt_merge and overlay have different purpose of "offset".
and you right mt_merge work only with same size clips.

jmac698
12th October 2011, 07:41
@yup
I just discovered mt_rectangle(n,0) works
mt_rectangle(2,0) gives
-2 0 -1 0 0 0 1 0 2 0
If you really need left of current, just use something like
leftstr(mt_rectangle(n,0),5*n+3)
gives
-2 0 -1 0 0 0

jmac698
12th October 2011, 08:07
I wanted to find the min pixel per line. It was really slow, but you could do

mt_luts(last, last, mode="min", pixels=mt_rectangle(719,1), expr="y")

It would be really nice if you could do

mt_luts(w=1,offx=360,last, last, mode="min", pixels=mt_rectangle(359,0), expr="y")

Which would be instant. The theory being, you are processing only 1 pixel per line, at x=320. The relative coordinates refer to the entire line, +-360. So I am finding the minimum of the entire line and placing it in the output clip at x=360.
Instead, all computed coordinates out of bounds are ignored. This certainly makes sense for processing the full size clip, but I'd like to have a flag to include referencing pixels outside the window but still within the image.

yup
12th October 2011, 08:18
@yup
I just discovered mt_rectangle(n,0) works
mt_rectangle(2,0) gives
-2 0 -1 0 0 0 1 0 2 0
If you really need left of current, just use something like
leftstr(mt_rectangle(n,0),5*n+3)
gives
-2 0 -1 0 0 0
If n>9 need if statement.
yup.

jmac698
12th October 2011, 08:37
--UPDATED--

@all
Please see http://forum.doom9.org/showthread.php?t=162758 for new function, mt_line
mt_line(int hor_radius(1), int ver_radius(0), bool zero(true), int position(0))

@yup
The mt_line demo function is exactly what you need

jmac698
12th October 2011, 09:36
Bug:

mt_freerectangle

Gives invalid arguments, but the docs say they have defaults.

mt_freerectangle(-1,-1,1,1,false)

Gives
-1 0, 0 -1, 0 0, 0 1, 1 0
so the (0,0) is not taken out; it's also giving the shape of a cross! Amazing, I guess no one ever used this function before.
Using the zero=false for a rectangle makes it a cross and doesn't remove the (0,0); using zero=false for a line doesn't remove the (0,0)

jmac698
12th October 2011, 09:44
@yup

mt_freerectangle(-n,0,0,0)

Works directly.

yup
12th October 2011, 10:08
@yup

mt_freerectangle(-n,0,0,0)

Works directly.
:thanks:
i read old doc wo this function.
yup.

jmac698
12th October 2011, 10:41
manao,
Could you please update the documentation page on your webserver to a48, it's confusing several people. Thanks.

(again, my message above was updated to reference the new mt_line function)

jmac698
12th October 2011, 13:13
Another bug:

shift=stackvertical(src.blankclip(color_yuv=$000000,height=240),src.blankclip(color_yuv=$080000,height=240))
src=colorbars(pixel_type="YV12")
src_16=src.shift(-16,0)#shift to right 8 pixels
mt_lutxyz(src, src_8, shift, expr="z 8 & y x ?",chroma="process")

This should result in the bottom half shifted, but the chroma is acting like copy second even though I specified process. I should get chroma from either x or y.

Manao
12th October 2011, 21:16
jmac698 : This should result in the bottom half shifted, but the chroma is acting like copy second even though I specified process. I should get chroma from either x or y.No. color_yuv = $080000, so z 8 & for U & V is always false. Use color_yuv = $080808 instead (that is, if I understand what you're wanting to do...)

As for the rest :
- Zero parameter is buggy for all form creators. Instead of removing (0, 0), it only keeps pixels with x or y equal to 0.
- I'll remove default values from the form creators documentation.
- If you still need to find the minimum value on a line : try recursively do the following : src1 = mt_luts(src, src, mode = "min", pixels = "0 0 1 0").pointresize(src.width / 2, src.height)
src2 = mt_luts(src1, src1, mode = "min", pixels = "0 0 1 0").pointresize(src1.width / 2, src1.height)
etc...It'll even be faster with mt_inpand(mode = "horizontal").pointresize(width / 3, height), since that one runs in SIMD
- I'll try printing a nice error message whenever resolutions don't match.

jmac698
12th October 2011, 23:57
Manao,
Thanks so much! I was stuck at the problem. I think it would be nice to have a special luma mode just like in mt_merge. Anyhow, I'll have to copy the luma over to u,v to make it work.

Feel free to include mt_line in your package, if you want, I know that two people have found it useful at least. I declare is GPL. There, takes care of the formalities :)

Thanks for the speed tip, I see what you're doing there. You can see how nice it would be in this case if I could run the analysis just once and fill the entire line (pixels) with the min (mode) values. I can see other uses for this, such as blurring out faces or making a mosaic, what do you think? I think a flexible approach would be a stepX and stepY. So a mosaic would be mt_square(8), stepX=8, stepY=8, mode="avg". Now that's nice :)

Another thought - instead of luma modes, a really flexible approach would be to be able to refer to the other color planes in the expression, so I could do z.y & 8. You could also use this to do colorspace conversion. I've wished for this many other times too. I've wanted to do more than lutxyz and I could start using color planes as calculation proxies :) This is just from the user perspective; I don't know what this implies behind the scenes.

In general I'm getting to a point where I really need to start making plugins, but for now I still think scripting for prototyping is easier to develop.

jmac698
13th October 2011, 01:20
Bug?
I compared these

#mt_luts(w=256,last, last, mode="min", pixels=linecoord, expr="y")
mt_inpand(w=256, mode=linecoord)

I'm getting some weird issues, the entire screen was black even though the cursor showed y=255. I refreshed a few times and then the screen turned green. I also tried process chroma to make sure, it's still unstable.

SSH4
15th October 2011, 17:56
mod4, yv12?

redfordxx
2nd November 2011, 08:18
Hi, after long time...
Manao, I have few efficiency questions.
1) I have no idea how fast is the lookup, so... is better to use two chained lutxy than one lutxyz when possible?
2) Do functions like mt_luts and mt_lutsx behave differently (more efficiently) when there is one variable missing in the expression, or it is always same procedure?
3) Is mt_lutspa calculated only once or every frame?

Thanx

R.
BTW: accidentally found out this:
mt_luts(mode="1 1 1 -1"), pixels="-1 0 0 0 1 0"...)
Interesting...I don't know whether that's feature or bug, but keep it...it can do nice things

redfordxx
2nd November 2011, 10:49
Moreover, I have new feature proposal:
It would be some kind of "downscale" parameter for functions which operate on field of values (convolution, luts, lutf...not lutxy, lut)

The idea is, that I need only some of the values and not all in the frame...
I better start with example:
I need to calculate range of pixels every 8x8 block. How do I do it?
mt_luts(mode="range", pixels="mt_freerectangle(0,0,7,7),........)
PointResize(w/8,h/8)
PointResize(w,h)
Now I have what I needed....every block of the video has the "color of difference" of its max and min.
However, I needed only 1/64 values I calculated...which is very unefficient.
Better would be:
mt_luts(mode="range", pixels="mt_freerectangle(0,0,7,7),downscalex=8,downscaley=8........)
PointResize(w,h)

Thanx for considering it;-)
R.

jmac698
2nd November 2011, 12:06
Yep, that's exactly the feature I need. I proposed a general stepx, stepy parameters to process in tiles.
In your case just stepx=8, stepy=8

cretindesalpes
2nd November 2011, 13:07
I need to calculate range of pixels every 8x8 block. How do I do it?

Anything using pixels=... will be excessively slow. Try this, instead (set uv according to your needs) :
uv = 1

w = Width ()
h = Height ()

w1 = (w + 15) / 16 * 2
h1 = (h + 15) / 16 * 2

PointResize (w1 * 9, h1 * 9, 0, 0, w1 * 8, h1 * 8)
mi = mt_inpand (u=uv, v=uv)
ma = mt_expand (u=uv, v=uv)
mi = mi.PointResize (w1 * 3, h1 * 3, 1, 1, w1 * 9, h1 * 9)
ma = ma.PointResize (w1 * 3, h1 * 3, 1, 1, w1 * 9, h1 * 9)
mi = mi.mt_inpand (u=uv, v=uv)
ma = ma.mt_expand (u=uv, v=uv)
mi = mi.PointResize (w1, h1, 1, 1, w1 * 3, h1 * 3)
ma = ma.PointResize (w1, h1, 1, 1, w1 * 3, h1 * 3)
mt_lutxy (ma, mi, "x y -", u=uv, v=uv)
PointResize (w1 * 8, h1 * 8)
Crop (0, 0, w, h)

jmac698
2nd November 2011, 13:58
Interesting... it seems you are performing inpand/expand on 3 different scales in order to cover an 8x8 area, then simply subtracting the results to get the range. It's very fast. Expand is the maximum in a 3x3 pixel area, inpand is the minimum.
There's still some redundancy however?

redfordxx
2nd November 2011, 14:45
Anything using pixels=... will be excessively slow. Try this, instead (set uv according to your needs) :


Yep, but when there is more complex op...similar things won't help...

Btw, looking at your signature...just few days ago I found about dither..awesome stuff

redfordxx
2nd November 2011, 14:46
stepx=8, stepy=8
even better idea....not always resize suitable...

redfordxx
2nd November 2011, 16:58
Try this, instead (set uv according to your needs) :

At second look, it won't work for chroma...some shifting needed...maybe using mt_convolution ("0 0 1","0 0 1"...

I dont know how else to shift clip

jmac698
2nd November 2011, 17:05
function shift(clip v, float x, float y) {
v#shift an image, x>0 shifts left, y>0 shifts up
bilinearresize(last.width,last.height,x,y,last.width,last.height)
}

redfordxx
2nd November 2011, 19:26
function shift(clip v, float x, float y) {
v#shift an image, x>0 shifts left, y>0 shifts up
bilinearresize(last.width,last.height,x,y,last.width,last.height)
}

1]i dont think is more efficient than mt_convolution
2]i need to shift the chroma half the speed of luma

redfordxx
2nd November 2011, 19:41
played a little and made it more general...on block size 27 I really tested it its more efficient than luts
may not work correctly when bx != by
w = c.Width
h = c.Height
w1 = ((w + 2*bx-1) / bx/2) * 2
h1 = ((h + 2*by-1) / by/2) * 2
bx1=int(Pow(3,Ceil(log(bx)/log(3))))
by1=int(Pow(3,Ceil(log(by)/log(3))))
#min max per block
c1=c.PointResize(w1 * bx1 , h1 * by1 , 0, 0, w1 * bx , h1 * by)
mi = c1.mt_inpand (y=y, u=u, v=v).mt_convolution("0 0 1","0 0 1",y=2,u=u, v=v).PointResize (w1 * bx1 / 3, h1 * by1 / 3, 1, 1, w1 * bx1, h1 * by1)
ma = c1.mt_expand (y=y, u=u, v=v).mt_convolution("0 0 1","0 0 1",y=2,u=u, v=v).PointResize (w1 * bx1 / 3, h1 * by1 / 3, 1, 1, w1 * bx1, h1 * by1)
mi = (bx1<9) ? mi : mi.mt_inpand (y=y, u=u, v=v).mt_convolution("0 0 1","0 0 1",y=2,u=u, v=v).PointResize (w1 * bx1 / 9, h1 * by1 / 9, 1, 1, w1 * bx1 / 3, h1 * by1 / 3)
ma = (bx1<9) ? ma : ma.mt_expand (y=y, u=u, v=v).mt_convolution("0 0 1","0 0 1",y=2,u=u, v=v).PointResize (w1 * bx1 / 9, h1 * by1 / 9, 1, 1, w1 * bx1 / 3, h1 * by1 / 3)
mi = (bx1<27)? mi : mi.mt_inpand (y=y, u=u, v=v).mt_convolution("0 0 1","0 0 1",y=2,u=u, v=v).PointResize (w1 * bx1 /27, h1 * by1 /27, 1, 1, w1 * bx1 / 9, h1 * by1 / 9)
ma = (bx1<27)? ma : ma.mt_expand (y=y, u=u, v=v).mt_convolution("0 0 1","0 0 1",y=2,u=u, v=v).PointResize (w1 * bx1 /27, h1 * by1 /27, 1, 1, w1 * bx1 / 9, h1 * by1 / 9)
mt_lutxy (ma, mi, "x y -", y=y,u=u, v=v)
PointResize (w1 * bx, h1 * by)
Crop (0, 0, w, h)

I wonder if using nonsquare morfology drops the efficiency..

When I am writing scripts, I always also wonder, whether avisynth is "smart enough" to ignore unused clips... so the lines bx1<27 and whatever more does not affect the processing when the bx is 9...

Gavino
2nd November 2011, 19:47
When I am writing scripts, I always also wonder, whether avisynth is "smart enough" to ignore unused clips... so the lines bx1<27 and whatever more does not affect the processing when the bx is 9...
That's right.
The unused branch of a conditional is not even evaluated.

redfordxx
3rd November 2011, 02:56
And how about this one:
function F (clip c, int b)
{

e=blabla..lot of something computing

d= (b==0) ? c : e
return d
}
Or even
function F (clip c, int b)
{

e=blabla..lot of something computing

d=c
return d
}Or
function F (clip c, int b)
{
c
blabla..lot of something computing

d=c
return d
}
Is "blabla" ignored in these cases?

redfordxx
3rd November 2011, 04:14
fc1=c.mt_convolution(horizontal="0 1 1",vertical="0 1 1", y=y,u=u, v=v)
fc2=c.mt_convolution(horizontal="0 1 1",vertical="0 1 1.0", y=y,u=u, v=v)
gives different results. Namely the float version is mostly one bit darker.
I know that one is calculated in float and one not, but in this case, shouldn't it be same? Probably differently solved rounding or truncating the result?

Gavino
3rd November 2011, 09:32
Is "blabla" ignored in these cases?
In each example, it will not be used at 'run-time', ie no video frames will be requested from the filters concerned. However, it is still processed at 'compile-time', which means the expression is evaluated and the filters are loaded, potentially taking time and memory. Some filters reserve memory on startup, others do not, and this is not necessarily related to the complexity of processing it would do later on to deliver video frames.

Note then the difference between
e=blabla..lot of something computing
d= (b==0) ? c : e
and
d= (b==0) ? c : blabla..lot of something computing
In both cases, if b=0, the blabla expression is not used at run-time.
But in the first case, it is evaluated at compile-time with the potential consequences I described.

Since this is the MaskTools thread, it's worth mentioning that mt_lutxyz is a prime example of a filter that uses a lot of time and memory at startup, and so if it is to be used only conditionally in a script, is best called in a conditional statement.

redfordxx
5th November 2011, 03:46
Hi please can anyone tell me, why the two following methods to calculate SAD (average of absolute differences in this case) over block give different results? And significantly, not just rounding error...function SAD(clip o)
{
y=3
u=3
v=3
#dimensions prep
bx=8
by=8
w = o.Width
h = o.Height
w1 = ((w + 2*bx-1) / bx/2) * 2
h1 = ((h + 2*by-1) / by/2) * 2
hor=(((bx % 2)==0) ? "0 " : "")+RightStr("1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1",bx*2-1)
ver=(((by % 2)==0) ? "0 " : "")+RightStr("1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1",by*2-1)
#sad method 1
c1= o.PointResize(w1*bx, h1*by, 0,0, w1*bx, h1*by)
c_avg= c1.mt_convolution(horizontal=hor,vertical=ver, y=y,u=u, v=v)
c_avg= mt_luts (c_avg,c_avg,mode="min",pixels=string((bx+1)/2-1)+" "+string((by+1)/2-1), expr="y", y=y,u=u, v=v)
c_avg= c_avg.PointResize(w1, h1, 0, 0, w1*bx, h1*by).PointResize(w1*bx,h1*by)
c_sadc= mt_lutxy(c_avg,c1,"x y - abs",y=y,u=u,v=v)
c_sadc=c_sadc.mt_convolution(horizontal=hor,vertical=ver, y=y,u=u, v=v)
c_sadc= mt_luts (c_sadc,c_sadc,mode="min",pixels=string((bx+1)/2-1)+" "+string((by+1)/2-1), expr="y", y=y,u=u, v=v)
c_sadc=c_sadc.PointResize(w1, h1, 0, 0, w1*bx, h1*by).PointResize(w1*bx,h1*by).Crop(0,0, w, h).Subtitle("sadc")
#sad method 2
c1= o.PointResize(w1*bx, h1*by, 0,0, w1*bx, h1*by)
c_avg= mt_luts(c1 ,c1,mode="avg", pixels=mt_freerectangle(0,0,bx-1,by-1), expr="y",y=y,u=u,v=v)
c_sadl= mt_luts(c_avg,c1,mode="avg", pixels=mt_freerectangle(0,0,bx-1,by-1), expr="y x - abs",y=y,u=u,v=v)
c_sadl=c_sadl.PointResize(w1, h1, 0, 0, w1*bx, h1*by).PointResize(w1*bx,h1*by).Crop(0,0, w, h).Subtitle("sadl")
Interleave(c_sadl,c_sadc)
return last
}

I have the results of the functions interleaved for better visual comparision and labeled. sadc is much faster than sadl...

EDITED: now I tested sadc gives correct results and sadl wrong

redfordxx
7th November 2011, 08:05
In each example, it will not be used at 'run-time', ie no video frames will be requested from the filters concerned.


Well, to be exact on this, I ended up with millions of conditions. Messy.
So I decided to write everything with Eval function.

I believe Eval() is processed at startup time, so there will be no inefficiency, right?

Gavino
7th November 2011, 10:06
Well, to be exact on this, I ended up with millions of conditions. Messy.
So I decided to write everything with Eval function.

I believe Eval() is processed at startup time, so there will be no inefficiency, right?
That's right.
I take it you mean you are doing things like:
condition ? Eval("""
... statements ...
""" : Eval("""
... other statements ...
""")

You might find it useful to use the if-else construct of GScript, which is less ugly and allows arbitrarily nested conditions.

redfordxx
8th November 2011, 20:43
So, back to my question some time ago...I did some performance testing...lutspa renders every frame again and again...is tiny piece faster than lut and twotimes slower than eg merge or makediff. So, before this is fixed this is the workaround with zero processing demand:mt_lutspa(o1,"x", y=3,u=3,v=3).trim(1,1).Loop(o1.framecount,0,0)

IanB
9th November 2011, 00:39
Nitpick:-).trim(0,-1).is preferred over).trim(1,1).The 1,1 fails for 1 frame clip case and requests frame 1 from the downstream graph instead of frame 0.

Also the trim plus loop method affect the audio. FreezeFrame(0, FrameCount()-1, 0) may be a viable alternative if audio matters.

redfordxx
9th November 2011, 21:49
Also the trim plus loop method affect the audio. FreezeFrame(0, FrameCount()-1, 0) may be a viable alternative if audio matters.
Trim, understood, Freezeframe not OK.
Freezeframe doesnot kill the CPU time.

For example my measurements:
testclips o1,o2,o3=Blankclip YV12 8192x4096 500frames

Cpu time in seconds
o1...........................0
mt_merge(o1,o2,o3)....... ..16
mt_lutspa(o1)...............27
mt_lutspa.trim.freezeframe....27
mt_lutspa.trim.loop...........0
Freezeframe probably also can use some tweaking

IanB
9th November 2011, 22:47
:confused:

o1...FreezeFrame(0, o1.FrameCount()-1, 0)

o1...trim(0,-1).Loop(o1.FrameCount,0,0)

Should be identical sans the audio.

Did you have the correct end frame number to FreezeFrame or was it 1 (perhaps due to the Trim, FreezeFrame(0, 0, 0) will be a no-op.)

redfordxx
16th November 2011, 04:11
Did you have the correct end frame number to FreezeFrame or was it 1 (perhaps due to the Trim, FreezeFrame(0, 0, 0) will be a no-op.)I just copied exactly what you posted and tried again. Freezeframe eats CPU, Loop doesnot...

IanB
16th November 2011, 08:06
Very very :confused:

Add a "ShowFrameNumber()." to the front of the FreezeFrame call to confirm it is actually always hitting frame 0.

Whose Avisynth.dll are you using, in all of mine Loop and FreezeFrame result in functionally identical graphs and the cache functions correctly. All of the current MT builds are based on my old 2.5.6 very screwed cache code which misbehaves God know how.

Gavino
16th November 2011, 10:13
mt_lutspa.trim.freezeframe....27
mt_lutspa.trim.loop...........0
Is this a typo?
The freezeframe version should not have a trim before it.
You should be measuring o.mt_lutspa.freezeframe(0, o.Framecount-1, 0).

redfordxx
16th November 2011, 14:01
Is this a typo?
The freezeframe version should not have a trim before it.
You should be measuring o.mt_lutspa.freezeframe(0, o.Framecount-1, 0).
Yes, typo..i measured it correctly

redfordxx
16th November 2011, 14:04
Very very :confused:

Add a "ShowFrameNumber()." to the front of the FreezeFrame call to confirm it is actually always hitting frame 0.

Whose Avisynth.dll are you using, in all of mine Loop and FreezeFrame result in functionally identical graphs and the cache functions correctly. All of the current MT builds are based on my old 2.5.6 very screwed cache code which misbehaves God know how.
Me too :confused:
because with ShowFrameNumber the processor load is zero
without ShowFrameNumber there is noticable CPU usage.

redfordxx
16th November 2011, 14:10
My avisynth.dll is 2.6.0.2
Date modified 25.5.11. 11:10

Gavino
16th November 2011, 15:59
Just a thought, but I wonder if mt_lutspa does something strange to the cache, by implementing SetCacheHints(). By putting a filter (any filter) after it, you would then return to normal caching for the next filter, which seems to be what you are seeing.

redfordxx
29th November 2011, 17:21
I am working on a set of filters in this (http://forum.doom9.org/showthread.php?t=163018) thread and I made my own merge filter (name is RMerge).

I compared it in performance to mt_merge.
The test clip was 8192x4096 and have about 1.5GB free memory.
Then I realized it was about 50%... well thats too much difference.
The hard numbers are about 9GByte/s for RMerge and 6Gbyte/s for mt_merge.
So I digged deeper and my rookie guess is that the thing which is slowing down mt_merge is calling MakeWritable method.
I am pretty sure that this speed difference is not caused by the algorithm but by the memory transfer limitation. So there is maybe room for improvement.

But of course, this is just only newbie guess

Dogway
22nd December 2011, 17:57
I know YUY2 is not officially supported but I found this to crash the application:

interleaved2planar
SeparateFields()
mt_lut(yexpr="x", expr="x 2 +", y=3, u=3,v=3)

The trigger is processing chroma in this scenario. It's strange because everything else works for planar YUY2.

edit: funnier facts; adding removegrain(0,planar=true) before mt_lut makes it workeable...

wOxxOm
16th January 2012, 15:34
a48, yv12: when width specified is one mt_lut(y=-255,w=1) the result is either two lines being affected or an access violation exception.

jmac698
18th January 2012, 01:47
width isn't really working :(

mastrboy
25th February 2012, 14:14
The documentation "documentation/mt_masktools.html" for masktools has not been updated since 2.0 alpha 43, i was wondering about all the CPU instruction values, are they all autodetectable? Or do i have to set f eks: SSE4=true to initiate SSE4 instructions?
This info is missing from the documentation...

jmac698
26th February 2012, 11:39
The docs that come with it are more up to date.

canuckerfan
5th March 2012, 10:30
Anybody know how to change this old function so that it's compatible with MaskTools2?
function Deflicker(clip clp)
{
o = last
screen = mt_lutf(o,o,mode="average",yexpr="x",U=1,V=1) #.greyscale
screenTS = screen.temporalsoften(1,9,0,9,2).merge(screen,0.249).temporalsoften(2,5,0,5,2)
calmed = o.mt_makediff(mt_makediff(screen,screenTS),U=2,V=2)
masky = o.mt_lut("x 32 < x 16 - 16 * x 204 > 255 204 x - abs 255 30 / * - 255 ? ?").removegrain(11,-1) #.greyscale
final = o.mt_merge(calmed,masky,U=2,V=2)
return final
}

Didée
5th March 2012, 10:35
That script *is* in MaskTools2 syntax. What problem do you face with it? I don't see anything that would cause a problem.

canuckerfan
5th March 2012, 10:38
avisynth gives me " Script error: invalid arguments to function "mt_lutf" "

Didée
5th March 2012, 11:00
Oh, what's that? Just tried, getting the same error. Sorry, can't help ATM. The syntax should be correct, as far as I can see.

A temporary workaround would be to replace the mt_lutf with

bicubicresize(24,16).bicubicresize(o.width(),o.height(),1,0)

which I would prefer anyway, since it gives a little bit of localisation. (I remember that using the naked plane-average could - unter certain circumstances - sometimes even increase the flicker locally.)

Didée
5th March 2012, 11:07
Ah, forget the above post. Well, not the suggested change, which is still true and valid. But for the error, it's very simple ...

function Deflicker(clip clp)
{
o = last
screen = mt_lutf(o,o,mode="average",yexpr="x",U=1,V=1) #.greyscale
[...]

That can't work. It must be

function Deflicker(clip clp)
{
o = clp
screen = mt_lutf(o,o,mode="average",yexpr="x",U=1,V=1) #.greyscale

That should work now. (Though, I'd really prefer the way via bicubicresize.)

canuckerfan
6th March 2012, 02:12
Changing "last" to "clp" did the trick. I tried replacing the mt_lutf line with the bicubic line and I get a different error that says invalid arguments to function "bicubicresize". Here's my script: function Deflicker(clip clp)
{
o = clp
screen = bicubicresize(24,16).bicubicresize(o.width(),o.height(),1,0) #.greyscale
screenTS = screen.temporalsoften(1,9,0,9,2).merge(screen,0.249).temporalsoften(2,5,0,5,2)
calmed = o.mt_makediff(mt_makediff(screen,screenTS),U=2,V=2)
masky = o.mt_lut("x 32 < x 16 - 16 * x 204 > 255 204 x - abs 255 30 / * - 255 ? ?").removegrain(11,-1) #.greyscale
final = o.mt_merge(calmed,masky,U=2,V=2)
return final
}

Gavino
6th March 2012, 09:12
screen = o.bicubicresize(24,16).bicubicresize(o.width(),o.height(),1,0)

canuckerfan
6th March 2012, 17:58
screen = o.bicubicresize(24,16).bicubicresize(o.width(),o.height(),1,0)
:o thanks

Granit
12th April 2012, 02:49
Hello, my first question on this board. I'm wondering about "mt_LUTs", the documentation for this filter seems off from the actual behavior of the filter. So I ask here to be certain that I'm not the error... Is this correct?
mt_square(1)?

y | y | y
y | x | y
y | y | y

mt_diamond(1)?

| y |
y | x | y
| y |
If this is correct, then why two input clips?

lansing
12th April 2012, 04:58
i have a noob question about mt_merge as in this line

mt_merge(clip1, clip2, mask, U=3,V=3)

does it read: merge U and V color plane of clip1 and clip2, according to the mask? So if the mask is mt_edge, it will then merge the edge area only?

Gavino
12th April 2012, 11:44
I'm wondering about "mt_LUTs", the documentation for this filter seems off from the actual behavior of the filter. So I ask here to be certain that I'm not the error... Is this correct?
mt_square(1)?

y | y | y
y | x | y
y | y | y

mt_diamond(1)?

| y |
y | x | y
| y |
If this is correct, then why two input clips?
Your diagrams are wrong - all entries should be 'y' as they define a neigbourhood in 'clip2'.
There is no 'x' there, as x corresponds to the pixel from 'clip1'.

The examples in the docs all use the same clip for both clip1 and clip2, but in the general case these need not be the same.

mt_merge(clip1, clip2, mask, U=3,V=3)
does it read: merge U and V color plane of clip1 and clip2, according to the mask? So if the mask is mt_edge, it will then merge the edge area only?
Yes (and it will also merge the Y planes in the same way).

Didée
12th April 2012, 12:05
@lansing
Yes, exactly that. However: with that syntax, the edge-mask has to contain "the edges" in its U+V planes (i.e. mt_edge() must have also been run with U=3,V=3). And moreover, this can turn out problematic - local contrast usually is rather low in the UV planes, and therefore edge masking usually gives a weak mask on U+V.
Often it is better to use the luma edge mask for the UV planes, that's what the "luma=true" switch in mt_merge is for. In the same breath it might be benefitial to expand the mask, to compensate for the lower chroma resolution.

mt_merge(clip1, clip2, emask.mt_expand(), luma=true, Y=2,U=3,V=3)

(It's not necessary to do this luma->chroma plane linking ... but quite often this is "what the user in fact is trying to do").



@Granit
You are mixing up two different things. The LUTs with two input clips are using pixel values from both input clips to compute new output pixels. The morphological operators mt_diamond/square/etc are defining the pixel neighborhood on which the "mode" operation should be computed on.

Hmh, clear as mud.:D - Example:

mt_lutf(c1,c2,mode="median",pixels=mt_diamond(2),expr="x y * 0.5 ^",Y=3,U=2,V=2)

Does the following:

On clip c1, for each pixel "X" compute the median of the following neighborhood n:

o o o o o o o
o o o n o o o
o o n n n o o
o n n X n n o
o o n n n o o
o o o n o o o
o o o o o o o


Now the median has been computed for each pixel of c1.

Next in this example is to compute the geometric mean {sqrt(x*y), that's what I've written for "expr"} for each c1<>c2 pixel pair, where the "x" in the lut is the median from c1, and the "y" in the lut is the pixel value from c2.

Gavino
12th April 2012, 13:03
mt_luts(c1,c2,mode="median",pixels=mt_diamond(2),expr="x y * 0.5 ^",Y=3,U=2,V=2)

Does the following:
On clip c1, for each pixel "X" compute the median of the following neighborhood n:

o o o o o o o
o o o n o o o
o o n n n o o
o n n X n n o
o o n n n o o
o o o n o o o
o o o o o o o


Now the median has been computed for each pixel of c1.

Next in this example is to compute the geometric mean {sqrt(x*y), that's what I've written for "expr"} for each c1<>c2 pixel pair, where the "x" in the lut is the median from c1, and the "y" in the lut is the pixel value from c2.
No, what you have described is mt_lutf.
For mt_luts, it evaluates the expression with x as the pixel in clip1 and y as each pixel in the corresponding neigbourhood in clip2, giving a set of results. The median (or the specified function) is then applied to that set to give the result value for that pixel.

Didée
12th April 2012, 13:23
Oh, you fell for my unreadable handwriting - my "f" and "s" are almost indistinguishable.

Blame on me, blame on me, blame on me ... :o :o :o

lansing
12th April 2012, 17:16
thanks Gavino and Didée. So by merging, clip1 and clip2 will each contribute 50% to the mask? What if I wanted to replace the edge of clip1 with clip2? I do mt_merge(...chroma="copy second")?

Gavino
12th April 2012, 17:57
So by merging, clip1 and clip2 will each contribute 50% to the mask? What if I wanted to replace the edge of clip1 with clip2? I do mt_merge(...chroma="copy second")?
Each output pixel of mt_merge is produced by mixing the corresponding pixels of clip1 and clip2 in the proportion determined by the corresponding pixel of the mask. As the documentation says, "The bigger the mask value, the more the second clip will be taken into account ( the actual formula is y = ((256 - m) * x1 + m * x2 + 128) / 256 )".

So the idea is to first create a mask which represents the way you want the merging to take place. If you want to replace the edges of clip1, then you would use clip1.mt_edge(...) as the mask.
mt_merge(clip1, clip2, clip1.mt_edge(...), ...)

chroma="copy second" is a separate issue and would take the chroma completely from clip2 regardless of the mask, probably not what you want.

Granit
12th April 2012, 20:13
Thank you Gavino and Didée for clearification. The reason I ask is because I'm trying to learn how to operate avisynth properly, currently I'm on the first knob of a steep learning curve...
I usally load single frames or a single set of frames to learn what I'm doing.
The operation I had in mind would be similar to mt_LUTs, but with only one input clip. Where x is center and y is matris pixel, so that mode="x y 32 + > x y 32 - < | med x ? ". Is such and operation possible with masktools (probably) and how would be a good way of doing that?

@Lansing

Do an mt_Edge(). Study the output. The "whitest" pixels are the ones that are "transparent". With merge, input, filling_clip, mask. filling clip will be put "on top" of input, but only where the mask is "transparent". The the mask is to 0 (black), the more the resulting clip will be a mix of input and filling_clip.

Gavino
12th April 2012, 23:25
The operation I had in mind would be similar to mt_LUTs, but with only one input clip. Where x is center and y is matris pixel, so that mode="x y 32 + > x y 32 - < | med x ? ".
Can you explain in words what this operation actually means?
For a given input pixel (x), is the condition evaluated for each neigbourhood pixel (y)? And then what happens to derive the single output pixel?

Granit
13th April 2012, 01:46
@Gavino: I Apologize if I'm not very clear or articulate, english isn't my native language.
What I mean is; If all of the matris pixels were mapped to the y (or any other) variable, and the center pixel to the x (or any other) variable then it would look as such (in an 3 by 3 matris):

Y Y Y
Y X Y
Y Y Y

Now with such a filter, being very generic, many different computations could be possible. e.g in my above post or, perhaps something as such: expr=”x avg 1.25 * > med ?”. In this example it would look for single pixels that are >25% above its eight surrounding neighbors and mediate the ones it finds. With a matris of say 1 by 20 pixels, it could be used for looking for aliases or perhaps remaining scan-lines, or or or... I, in my own humble opinion, think that such a filter is very possible and would be very useful. I also think, perhaps mistakenly, that it, or something similar, could be done with existing filters / framework.
Thank you for invested patience and, perhaps, sanity.

lansing
13th April 2012, 07:42
Each output pixel of mt_merge is produced by mixing the corresponding pixels of clip1 and clip2 in the proportion determined by the corresponding pixel of the mask. As the documentation says, "The bigger the mask value, the more the second clip will be taken into account ( the actual formula is y = ((256 - m) * x1 + m * x2 + 128) / 256 )".

So the idea is to first create a mask which represents the way you want the merging to take place. If you want to replace the edges of clip1, then you would use clip1.mt_edge(...) as the mask.
mt_merge(clip1, clip2, clip1.mt_edge(...), ...)

chroma="copy second" is a separate issue and would take the chroma completely from clip2 regardless of the mask, probably not what you want.

thank you for the explanation, and Granit.

i'm currently trying to finalize my attempt of stabilizing flickering line in anime, with mt_merge+mt_edge here (http://forum.doom9.org/showthread.php?p=1569657#post1569657). Things seem to work out so far until scene with night sky and stars. The problem is that mt_edge also considered the stars as edges, so when my script is to clean the edge mask, it will also clean the stars, and most of the time just wiped them out completely.

What I'm thinking is to create a mask of the star, and then have it subtracted from the edge mask, resulting in a edge mask without the star. Is this idea possible?

I've checked out LaTo's MCTD, he has an option to protect the star from denoised, and it read somewhat like



cutoff = 64 #Luma cutoff (process only brighter areas than this value) [0=all,1...255]
threshold = 16 #Luma threshold (minimal change needed to be filtered, the higher = the lesser areas are filtered) [0...127]
maxdiff = 4 #Maximum change allowed between source and result (the lesser, the brighter) [0=source,1...255]


i = defined(source) ? source : denoised
smP = denoised

chr21 = chroma?2:1

### PROTECTING
rg17 = smP.removegrain(17,-1)
iOB = i.mt_lut("x "+string(cutoff)+" >= x 0 ?",U=1,V=1)
mB = mt_makediff(iOB,rg17,U=1,V=1).mt_binarize(128+threshold,upper=false,U=1,V=1).removegrain(5,-1)
lB = mt_lutxy(smP,i,"x y - abs "+string(maxdiff)+" <= x x y - 0 < y "+string(maxdiff)+" - x ? ?",U=1,V=1)
smB = mt_merge(smP,lB,mB,U=chr21,V=chr21)



i have difficulty understanding what the script does and how to create a star mask from it.

Gavino
13th April 2012, 10:34
Oh, you fell for my unreadable handwriting - my "f" and "s" are almost indistinguishable.
Looking at this again, mt_lutf doesn't work that way either.
It doesn't have a pixels parameter, and the median (or whatever) operation is applied to the entire frame, not a neighbourhood of the relevant pixel.

Gavino
13th April 2012, 10:36
Now with such a filter, being very generic, many different computations could be possible. e.g in my above post or, perhaps something as such: expr=”x avg 1.25 * > med ?”. In this example it would look for single pixels that are >25% above its eight surrounding neighbors and mediate the ones it finds.
I don't think that can be done currently.
mt_luts goes part of the way, but the median or (whatever) operation is always applied to a fixed number of values (the size of the specified neighbourhood) - there is no way to conditionally select a subset of that neighbourhood and take the median of that subset.

cretindesalpes
13th April 2012, 12:16
I don't think that can be done currently.
mt_luts goes part of the way, but the median or (whatever) operation is always applied to a fixed number of values (the size of the specified neighbourhood) - there is no way to conditionally select a subset of that neighbourhood and take the median of that subset.

Arbitrary number of values can be achieved using BucketMedian (http://csbarn.blogspot.fr/2012/04/bucketmedian-2.html) by setting the rejected values to 0 (or 255) and setting min to 1 (or max to 254). However the clip would need to be cooked to present distinct groups of 3x3 pixels before processing.

w = Width ()
h = Height ()

# 3x3 pixel blocks
a = group3lines ().TurnRight ().group3lines ().TurnLeft ()

# Average of the 8 surrounding pixels
b = RemoveGrain (19)
b = b.PointResize (w*3, h*3)

# Rejected pixels are set to 0
x = mt_lutxy (a, b, "x y 1.25 * > x 0 ?", u=3, v=3)

x = x.BucketMedian (radius=1, min=1)
x = x.PointResize (w, h, 1, 1)
mt_lutxy (x, last, "x 0 == y x ?", u=3, v=3)

Function group3lines (clip c)
{
c
w = Width ()
h = Height ()
c0 = c.PointResize (w, h, 0, 0)
c1 = c.PointResize (w, h, 0, 1)
c2 = c.PointResize (w, h, 0, 2)
c02 = Interleave (c0, c2).AssumeFieldBased ().AssumeTFF ().Weave ()
c12 = Interleave (c1, c2).AssumeFieldBased ().AssumeTFF ().Weave ()
c0122 = Interleave (c02, c12).AssumeFieldBased ().AssumeTFF ().Weave ()
PointResize (c0122, w, h*3)
}

I don't know if it's exactly what you wanted to do.

Granit
13th April 2012, 19:39
I don't think that can be done currently.
mt_luts goes part of the way, but the median or (whatever) operation is always applied to a fixed number of values (the size of the specified neighbourhood) - there is no way to conditionally select a subset of that neighbourhood and take the median of that subset.

That's a shame. I guess it was just my wishful thinking then, atleast now I know I'm the error...

Result of cretindesalpes fine code can be seen (after download) here
http://www.streamfile.com/myid/FlYaXqchViIW

The code suggested in my last post was just an example, I wished for ”pixels=” and ”expr=” because I thought such a filter would be very handy sometimes.
Thank you all for your help.

cheeseboy
20th June 2012, 20:17
I'm trying to port Masktools2 to avxsynth (linux) but it kinda took a shit on me. I got it to build and load but it doesn't seem to work correctly at all. Heres a video of the fail http://dl.dropbox.com/u/26289275/masktoolsfail.ogv . And heres my git with all the changes https://github.com/fundies/MaskTools2-linux .

sl1pkn07
23rd June 2012, 11:56
wo! thankius!!

EDIT: masktools/common/common.cpp:3:21: fatal error: windows.h: No such file or directory

cheeseboy
24th June 2012, 13:30
that file shouldn't even be built... its explicitly commented out in the makefile.

sl1pkn07
24th June 2012, 13:48
doh. my fail. run genmake.sh before make. sorry.

for the info. to build need install boost

greetings and good work

EDIT:
i'm making package for my distro (archlinux). the namcap (package tester) say:

avxsynth-plugin-masktools2 W: ELF file ('usr/lib/avxsynth/libmasktools.so') has executable stack.


sl1pkn07@sL1pKn07 masktools-build $ readelf -l libmasktools.so

Elf file type is DYN (Shared object file)
Entry point 0x61300
There are 7 program headers, starting at offset 64

Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000142582 0x0000000000142582 R E 200000
LOAD 0x0000000000142f50 0x0000000000342f50 0x0000000000342f50
0x0000000000004dd8 0x0000000000005df8 RW 200000
DYNAMIC 0x0000000000144d88 0x0000000000344d88 0x0000000000344d88
0x00000000000001f0 0x00000000000001f0 RW 8
NOTE 0x00000000000001c8 0x00000000000001c8 0x00000000000001c8
0x0000000000000024 0x0000000000000024 R 4
GNU_EH_FRAME 0x000000000012dff0 0x000000000012dff0 0x000000000012dff0
0x00000000000022cc 0x00000000000022cc R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RWE 8
GNU_RELRO 0x0000000000142f50 0x0000000000342f50 0x0000000000342f50
0x00000000000030b0 0x00000000000030b0 R 1

Section to Segment mapping:
Segment Sections...
00 .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .rdata .eh_frame_hdr .eh_frame .gcc_except_table
01 .init_array .fini_array .jcr .data.rel.ro .dynamic .got .got.plt .data .bss
02 .dynamic
03 .note.gnu.build-id
04 .eh_frame_hdr
05
06 .init_array .fini_array .jcr .data.rel.ro .dynamic .got


sl1pkn07@sL1pKn07 masktools-build $ execstack libmasktools.so
X libmasktools.so


fixed warning with execstack -c libmasktools.so

Chikuzen
6th September 2012, 13:11
today, I tried to test whether masktools would work by VapourSynth (http://forum.doom9.org/showthread.php?t=165792).

>>> import vapoursynth as vs
>>> core = vs.Core()
>>> core.avs.LoadPlugin("mt_masktools-26.dll")
>>> core.list_functions()

then, there was an unfamiliar function on the displayed list.

mt_gradient(c1:clip;c2:clip;distorsion:data:opt;size_x:int:opt;size_y:int:opt;min:int:opt;max:int:opt;precision:int:opt;
Y:int:opt;U:int:opt;V:int:opt;chroma:data:opt;offX:int:opt;offY:int:opt;w:int:opt;h:int:opt;
mmx:int:opt;isse:int:opt;sse2:int:opt;sse3:int:opt;d3now:int:opt;d3now2:int:opt;ssse3:int:opt;sse4:int:opt;)


What's mt_gradient() ?

StainlessS
6th September 2012, 15:59
only references to 'gradient' I could find

wrapper.cpp

extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env)
{
...
...
...
Avisynth2x::Filter<Gradient::Filter>::create( env );
...
...
...
return("MaskTools: a set of tools to work with masks");
}


gradient\filter.h

class Filter : public MaskTools::Filter<ChildFilter>
{

ProcessorList<Processor> processors;
int nX[3];
int nY[3];
int nMinimum;
int nMaximum;
int nPrecision;

protected:

virtual void process(int n, const Plane<Byte> &dst, int nPlane)
{
UNUSED(n);
processors.best_processor( constraints[nPlane] )( dst, dst.pitch(), frames[0].plane(nPlane), frames[0].plane(nPlane).pitch(), \
frames[1].plane(nPlane), frames[1].plane(nPlane).pitch(), dst.width(), dst.height(), nX[nPlane], nY[nPlane], nMinimum, nMaximum, \
nPrecision );
}

public:
Filter(const Parameters &parameters) : MaskTools::Filter<ChildFilter>( parameters )
{
/* add the processors */
if ( parameters["distorsion"].toString() == "sad" )
{
processors.push_back(Filtering::Processor<Processor>(sad_c, Constraint(CPU_NONE, 1, 1, 1, 1), 0));
nMinimum = parameters["min"].is_defined() ? parameters["min"].toInt() : 0;
nMaximum = parameters["max"].is_defined() ? parameters["max"].toInt() : 65535;
}
else
{
error = "unknown distorsion";
return;
}

nX[0] = parameters["size_x"].is_defined() ? clip<int, int>(parameters["size_x"].toInt(), 0, nCoreWidth - 1) : nCoreWidth / 2;
nY[0] = parameters["size_y"].is_defined() ? clip<int, int>(parameters["size_y"].toInt(), 0, nCoreHeight - 1) : nCoreHeight / 2;
nPrecision = parameters["precision"].toInt();

for ( int i = 1; i < plane_counts[C]; i++ )
{
nX[i] = nX[0] / width_ratios[i][C];
nY[i] = nY[0] / height_ratios[i][C];
}
}

InputConfiguration &input_configuration() const { return TwoFrame(); }

static Signature filter_signature()
{
Signature signature = "mt_gradient";

signature.add(Parameter(TYPE_CLIP, ""));
signature.add(Parameter(TYPE_CLIP, ""));
signature.add(Parameter(String("sad"), "distorsion"));
signature.add(Parameter(0, "size_x"));
signature.add(Parameter(0, "size_y"));
signature.add(Parameter(0, "min"));
signature.add(Parameter(65535, "max"));
signature.add(Parameter(1, "precision"));

return add_defaults( signature );
}

};


gradient\filters.cpp

#include "filter.h"

using namespace Filtering;

typedef int (Distorsion)(const Byte *pSrc, ptrdiff_t nSrcPitch, const Byte *pRef, ptrdiff_t nRefPitch, int nPrecision);

template<int nBlockSizeX, int nBlockSizeY> int sad(const Byte *pSrc, ptrdiff_t nSrcPitch, const Byte *pRef, ptrdiff_t nRefPitch, \
int nPrecision)
{
int nSad = 0;

for ( int y = 0; y < nBlockSizeY; y++, pSrc += nSrcPitch * nPrecision, pRef += nRefPitch * nPrecision )
for ( int x = 0; x < nBlockSizeX; x++ )
nSad += abs<int>( pSrc[x * nPrecision] - pRef[x * nPrecision] );

return nSad;
}

template<Distorsion distorsion, int nBlockSizeX, int nBlockSizeY> void generic_c(Byte *pDst, ptrdiff_t nDstPitch, \
const Byte *pSrc, ptrdiff_t nSrcPitch, const Byte *pRef, ptrdiff_t nRefPitch, int nWidth, int nHeight, int nX, \
int nY, int nMinimum, int nMaximum, int nPrecision)
{
int x, y;

pSrc += nX + nY * nSrcPitch;

for ( y = 0; y < nHeight - nBlockSizeY * nPrecision + nPrecision; y++, pRef += nRefPitch, pDst += nDstPitch )
{
for ( x = 0; x < nWidth - nBlockSizeX * nPrecision + nPrecision; x++ )
pDst[x] = clip<Byte, int>( (distorsion( pSrc, nSrcPitch, &pRef[x], nRefPitch, nPrecision ) - nMinimum) \
* 255 / (nMaximum - nMinimum) );

for ( ; x < nWidth; x++ )
pDst[x] = pDst[nWidth - nBlockSizeX * nPrecision + nPrecision - 1];
}
for ( y = 0; y < nBlockSizeY * nPrecision - nPrecision; y++ )
memcpy( &pDst[y * nDstPitch], pDst - nDstPitch, nWidth );
}

namespace Filtering { namespace MaskTools { namespace Filters { namespace Gradient {

Processor *sad_c = &generic_c<sad<16, 16>, 16, 16>;

} } } }


all I could find

kurish
10th November 2012, 01:58
Is it possible to simply expand a mask by an arbitrary number of pixels?

e.g., the first mask below is turned into the second by expanding outwards 15 pixels. This was done manually in an image editing program, however, and I'd like MaskTools to do it automatically:

http://i.imgur.com/tAi1S.jpg http://i.imgur.com/RCg8q.jpg

Apologies for such a super-noob question; I have read up on the subject but can't find a solution. Thank you.

Edit: looks like it's as easy as multiple calls of mt_expand(u=2,v=2). The u/v=2 thing really threw me off...

wOxxOm
12th November 2012, 19:49
kurish, mt_expand_multi(sw=15,sh=15)

leeperry
19th November 2012, 14:36
Hi Manao, a while ago you told me that you would consider adding 10/16bit capabilities to mvtools.....any news on that matter by any chance please?

There are working P016 hacks for several other major Avisytnh plugins, but every script based on yours(SVP frame interpolation or many/most of Didée's scripts) is still stuck in YV12 land....which defeats the purpose of using madVR to begin with, it's like processing audio in 16int instead of 64fp :(

:thanks:

Keiyakusha
19th November 2012, 22:08
There is no point it what you ask in every thread. Avisynth doesn't work/support or whatever with P016 with hacks or without. It won't output P016. You need vapoyrsynth for that.

leeperry
19th November 2012, 22:22
Well, SmoothLevels can output 16bit using hacks and Manao told me like a year ago that he'd think about it. Once more and more plugins will support 16bit, it will only be a matter of having ffdshow modified in order to recognize those hacks.

There are far more chances of seeing this being successfull than someone adding VS support in ffdshow and all those plugin coders rewriting them for VS you know.

Keiyakusha
19th November 2012, 22:24
if it outputs 16bit it doesn't means it outputs P010 (or actually its P016 for 16bit). P016 is just one out of many 10bit colorspaces. And what avisynth outputs, even if its 10-16bit is hacked YV12. You need to hack every host software as well if you want it to accept it. There won't be P010 support in avisynth ever. I don't see it happening judging by how it is developed and that we have vapoursynth now anyway.

leeperry
19th November 2012, 22:29
Anything more precise than 8bit YV12 that wouldn't require drastic changes/rewriting will make my day...it will only be a matter of processing a lossless conversion to a format that mVR could understand inside ffdshow. Don' be so negative ;)

Keiyakusha
19th November 2012, 22:36
But you want to output it undithered to something like madvr right? Not possible if you won't hack madvr. And if you want only processing and output dithered yv12 is ok, then I believe you can process 16bit with mvtools as long as it uses stack16format. There was sctipts that automate the process for denoising, But not sure how we would go with frame doubling (and you seem to want that)...

But without proper high bitdepth support, all of this is probably too slow for realtime processing anyway. Especially in avisynth.

TheFluff
19th November 2012, 22:49
Anything more precise than 8bit YV12 that wouldn't require drastic changes/rewriting will make my day...it will only be a matter of processing a lossless conversion to a format that mVR could understand inside ffdshow. Don' be so negative ;)

In the last two years the Avisynth 2.6 alpha (which you are putting your hopes in) has progressed very little. It has one active developer (the tireless IanB), the interface is still not finished and it will not have support for more than 8 bits per sample in any colorspace even when it eventually gets a finished interface.

In the last two weeks, VapourSynth has gotten a pile of new plugins, it has a stable interface and a whole crowd of active developers and testers.

Extending a) masktools, b) the ffdshow avisynth interface, and c) the avisynth core itself so that it can process and output high bitdepth video is most definitely not something that "wouldn't require drastic changes". At the very least, you're talking about rewriting the processing core of a huge filter collection (the codebase of which is an incredible mess) and mucking around to quite a significant degree in ffdshow (a nasty piece of work to maintain even under optimal circumstances), and that's if you disregard the Avisynth API and output in one of the "hack" modes (which means you'll manually have to tell ffdshow what the input is). To be brutally honest; while all of these changes are theoretically possible, they will never actually happen. People have been asking for high bitdepth support in various places for years, and pretty much the only thing that's happened is dithertools, whose author is now working on vapoursynth stuff.

leeperry
20th November 2012, 08:52
alright, thanks for the explanation! so my only golden ticket will be to wait for PS script in mVR(processed in 32fp) and then wait for N-1 frames access so someone can write a frames interpolation script then =/

8bit video processing is really caveman technology..

martin53
20th November 2012, 21:48
Manao,
I'd like to suggest additional operators for RGBLUT/VY12LUT/YV12LUTxy.

( I am working with v1.5.8 - please comment if I should switch to mt_vxyz? )

min, binary operator, returns minimum of top 2 operands on stack
max, binary operator, returns maximum of top 2 operands on stack
dup, unary operator, duplicates top operand
swap, binary operator, swaps top 2 operands on stack

Didée
20th November 2012, 22:22
Seven years of MaskTools v2, and you're still working with v1? Is that serious, or are you trying to pull legs?

min and max are implemented in MaskTools v2. For dup and swap, I don't see any need?


@leeperry

There are a few minor problems. E.g. with mt_lutxy, being "the barebone" of custom scripting - take two clips, and compute whatever you need to compute. In 8bit land, one LUT table takes 64kB RAM. In the paradise of 16bit land, one LUT table takes 4096 MB RAM. Yes, that's 4 GB. That's obviously nonsense, you can't work with tables that big. Well, compute it at runtime then. Ooops, now the darn crap is 100 times slower than before. Hmm-hmm.

martin53
20th November 2012, 22:50
Seven years of MaskTools v2, and you're still working with v1? Is that serious, or are you trying to pull legs?


Yes, I am working with v1. I feel that I already spend much time in finding plugin updates. To be honest, I upgraded from v1.4.16 to v1.5.8 yesterday. On Manao's website, I saw e.g. masktools-v2.0a48.zip from December 2010 - but there are hundreds of files there, and how can I judge their matureness...?

As for 'dup': With min/max and the ? operator, it may be unneccessary. Without the min/max operators, I wondered how i can check if x-128 is positive and then take x-128, or else take 0: "x 128 - 0 < 0 x 128 - ?" But I admit that because of the order of operands for '?', 'dup' would not help. I would need the dup'ed operand on top of the comparison and the other operand, so more stack manipulation operators would be needed, and although it is cumbersome, maybe redundant entry is best. Or storage variables, please see the xyremap thread.

leeperry
21st November 2012, 00:38
In 8bit land, one LUT table takes 64kB RAM. In the paradise of 16bit land, one LUT table takes 4096 MB RAM.
Hah, thanks for the input! Make it 10 or 12bit then? So many successive 8bit passes can't do much good to the PQ IMHO, but life is about compromises and 10/12bit will already be an improvement w/o too much extra load maybe?

Mug Funky
21st November 2012, 04:56
the big LUT problem is interesting, as float 3d luts are routine in colour grading land. is this the difference that GPU computing makes?

most LUT formats used in grading (and increasingly the rest of the post workflow) are computed from a 16x16x16 "colour cube" that is input to the program. presumably they use bicubic interpolation or some such.

operating on 2 or 3 input clips would certainly complicate things though.

Chikuzen
21st November 2012, 06:19
In 8bit land, one LUT table takes 64kB RAM. In the paradise of 16bit land, one LUT table takes 4096 MB RAM. Yes, that's 4 GB.
In 16bit land, each value of the table needs 2bytes.
Thus, 2 * 65536 *65536 = 8GB :p

martin53
24th November 2012, 14:21
Seven years of MaskTools v2, and you're still working with v1?

Didée,
first I was a bit annoyed 'cause I never had come across a clear statement that v2 is the version designed for public - it is alpha and so on - my fault for sure.
The functions inside are great! And thanks for the hint about mt_lutspa!

bennynihon
19th March 2013, 19:17
Using the SET's latest Avisynth 2.6 MT and Masktools 2.0a48, I'm having an issue with frames being processed out of order when I enable MT via SetMTMode. In my output video (encoded by x264), I'll occasionally see a few interchanged frames which is noticeable as jumpiness in the output clip. When I comment out the SetMTMode lines, the issue disappears.

My clip is something as simple as this:

# Video Source
SetMemoryMax(1024)
SetMTMode(3)
FFVideoSource("e:\mymovie.mkv")

SetMTMode(2)
# Crop to 1920x800 (2.40:1 AR)
vSrc=Crop(0,140,0,-140)

# Degrain
bs = 16
super = vSrc.MSuper(pel=2, sharp=1)
bvec2 = MAnalyse(super, isb = true, delta = 2, blksize=bs, overlap=bs/2)
bvec1 = MAnalyse(super, isb = true, delta = 1, blksize=bs, overlap=bs/2)
fvec1 = MAnalyse(super, isb = false, delta = 1, blksize=bs, overlap=bs/2)
fvec2 = MAnalyse(super, isb = false, delta = 2, blksize=bs, overlap=bs/2)
vSrc.MDegrain2(super,bvec1,fvec1,bvec2,fvec2)

Overdrive80
20th March 2013, 01:04
Try with this (http://forum.doom9.org/showthread.php?p=1619023#post1619023). Thanks to -Vit- and 06_taro

bennynihon
20th March 2013, 21:52
Try with this (http://forum.doom9.org/showthread.php?p=1619023#post1619023). Thanks to -Vit- and 06_taro

Thank you! I'll give this a try.

~ VEGETA ~
20th July 2013, 20:47
how can I apply some filters only on dark areas? and the opposite too?

and, applying them on edges too...

thanks

martin53
23rd July 2013, 19:27
I am insecure if I misunderstand the manual or there is a bug in mt_luts() in V2.0a48 (as of dec. 31, 2010).

The manual says "x" is taken from clip1, "y" is taken from the "pixels" environment of clip2.

◾It computes the mode operation on the result of the function defined by expr, where x is the pixel from clip1, and y a pixel from the neighbourhood in clip2, defined by pixels.


Now if I define a "pixels" environment of just 1 pixel, I can see the direct expression result with e.g. the mode "avg". The most simple expression expr="x" should reflect clip1, right?

But in fact it does reflect clip2 instead.

mt_luts(blankclip(color_yuv=$400000, pixel_type="yv12"), colorbars(pixel_type="yv12"), mode="avg", pixels="0 0", expr="x", chroma="128")

foxyshadis
23rd July 2013, 23:52
how can I apply some filters only on dark areas? and the opposite too?

and, applying them on edges too...

thanks

Create a new named clip that is the original plus a filter. Then combine them with mt_merge and either mt_binarize to work on specific ranges of light, or mt_edge to work on edges. There are tons of scripts out there that do both, just look around this forum a bit.

TurboPascal7
24th July 2013, 03:06
I am insecure if I misunderstand the manual or there is a bug in mt_luts() in V2.0a48 (as of dec. 31, 2010).

The manual says "x" is taken from clip1, "y" is taken from the "pixels" environment of clip2.



Now if I define a "pixels" environment of just 1 pixel, I can see the direct expression result with e.g. the mode "avg". The most simple expression expr="x" should reflect clip1, right?

But in fact it does reflect clip2 instead.

mt_luts(blankclip(color_yuv=$400000, pixel_type="yv12"), colorbars(pixel_type="yv12"), mode="avg", pixels="0 0", expr="x", chroma="128")


Yes, this is a bug. mt_luts uses the value of the second clip as x instead of the first one. So whatever you pass as clip1 won't change the output.

Since people usually provide the same clip as both clip1 and clip2, no one ever noticed.

~ VEGETA ~
8th August 2013, 13:13
Create a new named clip that is the original plus a filter. Then combine them with mt_merge and either mt_binarize to work on specific ranges of light, or mt_edge to work on edges. There are tons of scripts out there that do both, just look around this forum a bit.

Thank you, but can you give me a quick example of both?

using a filter on edges and using a filter (say deband) on the dark areas only.

thanks in advance.

foxyshadis
10th August 2013, 00:22
Edges:

original = last
filtered = SomeFilter()
mask = mt_edge()
mt_merge(original,filtered,mask)

See the docs for masktools v2 if you want to refine the edgemask. You can use mt_merge(original,filtered,mask,luma=true) if you want to include the chroma channels in the filtering.

Dark areas:

original = last
filtered = SomeFilter()
mask = blur(1.4).mt_binarize(64)
mt_merge(original,filtered,mask)

Play with the threshold value. The "blur" is to make sure it applies even when there's a bit of noise on transitions, but even that won't be perfect. Might want to blur the results, so the threshold isn't so hard, or use levels instead for a somewhat smoother transition:

mask = Invert().Levels(128,1,191,0,255,coring=true)

Because it's inverted, this means process everything fully up to 64 (191=255-64), scaled from full to nothing 64 to 128, and nothing beyond that.

~ VEGETA ~
10th August 2013, 04:49
thanks for the reply.

See the docs for masktools v2 if you want to refine the edgemask. You can use mt_merge(original,filtered,mask,luma=true) if you want to include the chroma channels in the filtering.


luma=true is for chroma?

mt_merge(original,filtered,mask)

does the order matter and how?

mask = blur(1.4).mt_binarize(64)

I didn't understand the meaning of blur, but is 64 the threshold here? what does it really mean (bright, dark,..)?

this is important to understand (how to make thresholds).

mask = Invert().Levels(128,1,191,0,255,coring=true)

Because it's inverted, this means process everything fully up to 64 (191=255-64), scaled from full to nothing 64 to 128, and nothing beyond that.

hmm this is what I didn't understand the most.

___

so if I wanna filter the dark areas of some clip with f3kdb() and filter the really bright ones with say Deen (just an example)... and filter the edges with something else like an anti-aliasing filter. what is the full script with explanation?

thanks in advance.

Gavino
8th February 2014, 12:07
mt_polish parses nested conditionals incorrectly

For example,
mt_polish("x > 128 ? 255 : x > 64 ? 128 : 0")
produces
x 128 > 255 x 64 > ? 128 0 ?
instead of
x 128 > 255 x 64 > 128 0 ? ?

It can be worked round by putting the inner conditional in parentheses
mt_polish("x > 128 ? 255 : (x > 64 ? 128 : 0)")
but this should not be necessary.

Test script:
BlankClip(pixel_type="YV12")
Subtitle(mt_polish("x > 128 ? 255 : x > 64 ? 128 : 0"))
Subtitle(mt_polish("x > 128 ? 255 : (x > 64 ? 128 : 0)"), y=30)

Motenai Yoda
1st December 2014, 14:58
there is a little bug into mt_motion about tht/sc_value?
actually on scenechange whenever it should return a blank mask it return a plain mask at tht value.
meanwhile sc_value has no effect at all.

martin53
17th February 2015, 18:46
I am very happy to find the MaskTools2 b1 wiki page (http://avisynth.nl/index.php/MaskTools2) - thanks! tp7, Kurosu, Manao, mg262 -
and have a question and a feature request.

The question is: do all of the filters in the AviSynth 2.6 version now support all planar 2.6 formats (or at least YV24)? Explicitly it is only stated that mt_merge supports YV24.

The feature request is a new value 6 for u and v and chroma = "follow" setting u = v = 6.
The meaning of 6 should be "process the same U and V pixels as the luma pixels". Maybe my memory tricks me, but when I last worked with the package, I think that edge masks and all that worked completely independently on the three planes when I chose u = v = 3.
Given the problem that I want to isolate areas with not too sharp luma change, I can use the edge function on the luma plane. But then I was interested to also set the U and V components of these same pixels to 128 (or maybe 0 as a special hint value for the next function) for the further processing, and I found that this was hard to achieve: only with a separate Y8 mask clip which was then used on three other Y8 clips, previously separated from the YV24 clip. I hoped that one single function call with u = v = 6 could do the thing much faster.
Sorry what I write remains a bit vague here, will try to find another specific example where it gets clear and edit the post or add a new one.

EDIT I think I cancel the feature request at least for the moment. mt_merge has the 'luma' parameter which fulfills it for mt_merge. It had to do with mt_lutxy etc, where I found it would be useful if one were able to choose, whether for U and V planes, U and V from the 2nd clip are taken, too, or for U Plane of result, U only of clip 1, but Y of clip 2 were used (for V plane of result, V plane of clip 1 and Y plane of clip2). That could simplify some operations, when clip2 is a control clip, but it is possible to create a YV24 control clip with 3 identical planes with YToUV(3 times the same Y8 clip), and surely this is not a widely needed feature.

Reel.Deel
17th February 2015, 20:06
The question is: do all of the filters in the AviSynth 2.6 version now support all planar 2.6 formats (or at least YV24)? Explicitly it is only stated that mt_merge supports YV24.

In the last sentence of the introduction (http://avisynth.nl/index.php/MaskTools2#Introduction) it says:
All filters only work with planar colorspaces (Y8, YV12, YV16, and YV24 (AviSynth 2.5.8 only supports YV12!).

It's easy to miss, whenever I get some time I'll make it more obvious.

martin53
17th February 2015, 21:33
Thanks, you're right. Not that I Intend to use YV411 ;) but... not YV411?

Reel.Deel
18th February 2015, 03:16
Yup, no love for YV411 (I've yet to see anyone complaining, maybe it's because no one really uses it :)) . Anyways, I tried it with YV411 and I got this message:
unsupported colorspace. masktools only support planar YUV colorspaces (YV12, YV16, YV24) (https://github.com/tp7/masktools/blob/master/masktools/common/base/filter.h#L161)

Kind of odd it doesn't mention Y8 since it's indeed supported. :confused:

LouieChuckyMerry
15th August 2015, 12:49
Hello, and Happy Saturday! I'm trying to get AviSynth running on my oldest laptop--Windows 7 x64, AMD Turion II M500, 4GB RAM; why waste any encoding time, ha ha--but I'm having problems with MaskTools2. AviSynth is seemingly properly installed, as I can use this setup to successfully encode sources with x264 and no added filters. However, any call requiring MaskTools2 results in the error message "Script error: there is no function named 'mt_xxx'"--"xxx" varies depending on the call--despite the fact that the MaskTools2 .dll is in my plugins folder. I've tried using the newest tp7 and Vit modded .dlls, as well as the standard version, but all result in the same error, like the .dll isn't in my plugins folder even though it is. Perhaps the processor is too old? Is there a simple MaskTool2 call I can use to test things? Thanks for any help.

Groucho2004
15th August 2015, 14:04
Hello, and Happy Saturday! I'm trying to get AviSynth running on my oldest laptop--Windows 7 x64, AMD Turion II M500, 4GB RAM; why waste any encoding time, ha ha--but I'm having problems with MaskTools2. AviSynth is seemingly properly installed, as I can use this setup to successfully encode sources with x264 and no added filters. However, any call requiring MaskTools2 results in the error message "Script error: there is no function named 'mt_xxx'"--"xxx" varies depending on the call--despite the fact that the MaskTools2 .dll is in my plugins folder. I've tried using the newest tp7 and Vit modded .dlls, as well as the standard version, but all result in the same error, like the .dll isn't in my plugins folder even though it is. Perhaps the processor is too old? Is there a simple MaskTool2 call I can use to test things? Thanks for any help.
You could run my Avisynth Info Tool (http://forum.doom9.org/showthread.php?t=170647) to see what's wrong. Probably some runtimes missing.

LouieChuckyMerry
15th August 2015, 14:48
I actually ran your AviSynthInfoTool before posting, but nothing seemed horribly wrong, which of course means nothing given my ignorance. I probably missed something. What should I look for? Your AviSynthInfoTool indicates that all is well, as far as I can tell.

feisty2
15th August 2015, 14:51
got msvcr2012?

Groucho2004
15th August 2015, 15:48
What should I look for? Your AviSynthInfoTool indicates that all is well, as far as I can tell.
Did you run Plugin info from the "Tools" menu?

LouieChuckyMerry
16th August 2015, 09:28
Did you run Plugin info from the "Tools" menu?

I'm embarrassed to admit that I did not :o . Now having done so, and after staring at the Dependency Walker GUI for a goodly stretch while dreaming of deciphering the hieroglyphics therein, I was ready to return here seeking more help. Then my eye caught feisty2's comment and, after repeating it slowly a few times until my mental switch flicked, I installed Microsoft Visual C++ Redistributable 2012 and solved the problem. A fine way to really enjoy a slight hangover ;) . Anyway, thanks for your help, and AVSInfoTool, and thank you too, fiesty2 :) .

Groucho2004
16th August 2015, 10:30
Now having done so, and after staring at the Dependency Walker GUI for a goodly stretch while dreaming of deciphering the hieroglyphics therein, I was ready to return here seeking more help. Then my eye caught feisty2's comment and, after repeating it slowly a few times until my mental switch flicked, I installed Microsoft Visual C++ Redistributable 2012 and solved the problem.
Next version I'll add hints for these MS VC Restributable issues so the user can try these before consulting Dependency Walker.

LouieChuckyMerry
17th August 2015, 02:16
Next version I'll add hints for these MS VC Restributable issues so the user can try these before consulting Dependency Walker.

That would certainly make AVSIntoTool even more useful. Perhaps you'd consider a dedicated GUI button, bright and obvious, for "Tools/Plugin Info..." ;) .

real.finder
10th April 2016, 18:34
can someone make makstools 2 linked with avstp (http://forum.doom9.org/showthread.php?t=164407) in order to control the number of threads or even turn multithreaded off

I think this will solve QTGMC slowdown issue (http://forum.doom9.org/showthread.php?p=1747055#post1747055) and avs mt crashes

AzraelNewtype
10th April 2016, 21:21
can someone make makstools 2 linked with avstp (http://forum.doom9.org/showthread.php?t=164407) in order to control the number of threads or even turn multithreaded off

I think this will solve QTGMC slowdown issue (http://forum.doom9.org/showthread.php?p=1747055#post1747055) and avs mt crashes

The problem was solved on avisynth+ by wildly rewriting its internal buffering code, so I sort of doubt fixing a plugin will do it on its own for vanilla.

real.finder
11th April 2016, 09:26
The problem was solved on avisynth+ by wildly rewriting its internal buffering code, so I sort of doubt fixing a plugin will do it on its own for vanilla.

it still there http://forum.doom9.org/showthread.php?p=1744902#post1744902

TurboPascal7
11th April 2016, 12:21
Masktools 2 doesn't use threading internally and in fact doesn't know anything about it. So linking it against avstp will solve absolutely nothing.

StainlessS
8th September 2016, 11:39
Think I know the answer to this already but,

Is there any way to expand (as in mt_expand()) white on black mask only in 1 direction, ie expand white upwards, or , white downwards ?

(well you can hope, can't you:) )

EDIT:
I am aware of the horizontal and vertical only modes, maybe some kind of convolution would work, if so could you please give solutions for all four directions.
Results need to be 0,255 only.
EDIT: So only originally black pixels should be affected.

StainlessS
9th September 2016, 20:32
What, nobody, no idea? EDIT: Clues welcome !

raffriff42
9th September 2016, 23:26
maybe some kind of convolution would work...
so only originally black pixels should be affected.
How about mt_expand(mode=something) ?

http://manao4.free.fr/mt_masktools.html#mt_expand_mt_inpand
...
mt_expand, mt_inpand
mode select the local neighbourhood. It can take the values : "square" : 3x3 square neighbourhood - isse optimized. [default]
"horizontal" : 3x1 horizontal neighbourhood.
"vertical" : 1x3 horizontal neighbourhood.
"both" : a 3-long cross ( "horizontal" + "vertical" ) neighbourhood. [like default but with rounder corners]
a custom mode, where you give a list of coordinates. "0 0 -1 0 1 0" is for example equivalent to "horizontal".
OK, the custom mode documentation is pretty unclear, but this is what I found through trial and error:
mt_expand(mode=" 1", chroma="-128") ## shift left
mt_expand(mode="-1", chroma="-128") ## shift right
mt_expand(mode=" 0 1", chroma="-128") ## shift up
mt_expand(mode=" 0 -1", chroma="-128") ## shift down
mt_expand(mode=" 1 1", chroma="-128") ## shift left+up
mt_expand(mode="-1 -1", chroma="-128") ## shift right+down
mt_expand(mode=" 0 0 0 1", chroma="-128") ## expand up
mt_expand(mode=" 0 0 0 -1", chroma="-128") ## expand down
mt_expand(mode=" 0 0 0 0 1", chroma="-128") ## expand left
mt_expand(mode=" 0 0 0 0 -1", chroma="-128") ## expand right
mt_expand(mode=" 0 0 -1 0 1", chroma="-128") ## expand left+right (same as 'horizontal')
mt_expand(mode=" 0 -1 0 1 0", chroma="-128") ## expand up+down (same as 'vertical')
mt_expand(mode=" 0 0 0 1 1", chroma="-128") ## expand left+up
mt_expand(mode=" 0 0 0 -1 -1", chroma="-128") ## expand right+down

EDIT please ignore this...scroll down

StainlessS
10th September 2016, 08:16
RaffRiff42, you are my hero

Ta very much :)

StainlessS
10th September 2016, 16:35
There seems to be a MaskTools bug when using Expand Left as posted in RaffRiff42 post, two posts ahead #570.
This line

mt_expand(mode=" 0 0 0 0 1", chroma="-128") ## expand left

Assuming that the line is not in error.

This script weirdly exhibits the problem

BlankClip(pixel_Type="YV12")
Subtitle("Whats the recipe today Jim ...",align=5)
mt_expand(mode=" 0 0 0 0 1", chroma="-128") # expand left
Greyscale


Load into VDubMod, and repeatedly press one of the refresh keys (F5 or F7)

You will sometime get one of the below results, sometimes the other,

https://s20.postimg.cc/p5qwj5u2l/One_zpsrvcxitha.png (https://postimg.cc/image/4lm2koebd/)

https://s20.postimg.cc/u5sy4up31/Two_zpszptq3tfn.png (https://postimg.cc/image/5pasadoc9/)

There is something not quite right somewhere :confused::confused:

EDIT: XP32. AVS v2.6. Masktools latest on Wiki.

Gavino
10th September 2016, 16:48
There seems to be a MaskTools bug when using Expand Left as posted in RaffRiff42 post, two posts ahead #570.
This line

mt_expand(mode=" 0 0 0 0 1", chroma="-128") ## expand left

Assuming that the line is not in error.
Since (as the docs state) the numbers represent coordinates, there should be an even number of them.
Here you have (0,0), (0,0), (1,?), with one coordinate incomplete (and the other two being equal).
This probably gives rise to undefined behaviour within MaskTools.
Try "0 0 1 0", or "-1 0 0 0".

StainlessS
10th September 2016, 16:52
Thanx big G, that explains it just fine :)
Was drivin' me nuts because I kept gettin' different results.

raffriff42
10th September 2016, 19:33
OK sorry, I had mt_convolution arguments on the brain there.
So mode seems to be a list of (x,y) coordinates, relative to the current pixel (0,0).
The coordinate system is as follows (EDIT: updated in light of Gavino's post #582 (http://forum.doom9.org/showthread.php?p=1780550#post1780550))Above,left
-1,-1 0,-1 1,-1
-1,0 0,0 1,0
-1,1 0,1 1,1
Below,rightThe coordinates can extend beyond what's shown here (±1 horizontal & vertical), to at least ±1000. The list of coordinates can be in any order.

Each pixel is replaced by its local maximum : the brightest pixel in its "local neighborhood," as defined by the mode argument.

For example, mt_expand(mode="0 0 -1 0") defines a local neighborhood of two pixels: the source pixel itself (0,0) and the one to its left (-1,0). In the output, bright areas will appear to "expand" to the right.
(end of edit)

So my previous post should have been something like:mt_expand(mode="-1 0", chroma="128") ## shift right
mt_expand(mode="-1 0 0 0", chroma="128") ## expand right

mt_expand(mode=" 0 1", chroma="128") ## shift up
mt_expand(mode=" 0 1 0 0", chroma="128") ## expand up

mt_expand(mode=" 0 -1", chroma="128") ## shift down
mt_expand(mode=" 0 -1 0 0" , chroma="128") ## expand down

mt_expand(mode=" 1 1", chroma="128") ## shift left+up
mt_expand(mode=" 1 1 0 0", chroma="128") ## expand left+up

mt_expand(mode="-1 -1", chroma="128") ## shift right+down
mt_expand(mode="-1 -1 0 0", chroma="128") ## expand right+down

mt_expand(mode=" 1 0 0 0 -1 0", chroma="128") ## expand left+right (same as 'horizontal')
mt_expand(mode=" 0 1 0 0 0 -1", chroma="128") ## expand up+down (same as 'vertical')

StainlessS
10th September 2016, 20:02
You are still my hero Raff, we got it sorted now. :)

You might want to copy over the fixed list to the original post.

EDIT: You seem to have missed out

mt_expand(mode=" 1 0", chroma="-128") ## shift left
mt_expand(mode=" 1 0 0 0", chroma="-128") ## expand left

raffriff42
10th September 2016, 23:46
Didn't miss it - omitted it on purpose! My trick seems to have worked!

OK let's have some demo images, and experiment with mt_square, mt_diamond and mt_circle
These func's generate strings you can use as mode arguments. So there's no longer any need for...mt_expand.mt_expand.mt_expand.mt_expand.mt_expand.mt_expand # ...etc

https://www.dropbox.com/s/qz1wuqhmcf6usmc/mtexpand-test-00-org.png?raw=1 https://www.dropbox.com/s/hpuiiwpvymlqe2d/mtexpand-test-01b-down-x3.png?raw=1 https://www.dropbox.com/s/tszsgb7wwxqgzkv/mtexpand-test-02-sq-x4.png?raw=1 https://www.dropbox.com/s/19wfasc2lmsmi0u/mtexpand-test-03-sq-x16.png?raw=1 https://www.dropbox.com/s/8l9h1wzwoxvyuue/mtexpand-test-04-dia-x16.png?raw=1 https://www.dropbox.com/s/vzuzxl7zz3ipuir/mtexpand-test-05-circ-x16.png?raw=1


BlankClip(width=260, height=120, pixel_type="YV12", color=$0)
Subtitle("M A S K\n- - - -", size=Height/3, align=5, text_color=$ffffff, lsp=0)
AddBorders(8, 8, 8, 8, $ffffff)
AddBorders(48, 32, 48, 32, $0)

return Interleave(
\ EvalShow2("""# (input)""")
\ , EvalShow2("""mt_expand(mode="0 -1 0 0", chroma="-128") # down""")
\ , EvalShow2("""mt_expand(mode="0 0 -1 -1 -2 -2 -3 -3", chroma="-128") # down-right x3""")
\ , EvalShow2("""mt_expand(mode=mt_square(radius=4, zero=true), chroma="-128")""")
\ , EvalShow2("""mt_expand(mode=mt_diamond(radius=4, zero=true), chroma="-128")""")
\ , EvalShow2("""mt_expand(mode=mt_circle(radius=4, zero=true), chroma="-128")""")
\ , EvalShow2("""mt_expand(mode=mt_square(radius=16, zero=true), chroma="-128")""")
\ , EvalShow2("""mt_expand(mode=mt_diamond(radius=16, zero=true), chroma="-128")""")
\ , EvalShow2("""mt_expand(mode=mt_circle(radius=16, zero=true), chroma="-128")""")
\ )

### execute a script snippet and show it on screen
function EvalShow2(clip C, string s)
{
C
Eval(s)
Subtitle(s, size=12, align=1)
return Last
}

colours
11th September 2016, 02:57
These func's generate strings you can use as mode arguments. So there's no longer any need for...mt_expand.mt_expand.mt_expand.mt_expand.mt_expand.mt_expand # ...etc

What?

The mt_expand chain is good because the square and diamond modes are SIMD-optimised, whereas the custom modes aren't. (And obviously using a chain is O(n) whereas specifying all the pixels is O(n^2), so even if SIMD optimisations weren't relevant, you still lose out.)

Just for comparison, mt_expand_multi(sw=10,sh=10) runs about 477 times as fast as mt_expand(mode=mt_square(radius=10)) on my old and flaky laptop (815.2 fps versus 1.709 fps).

There's also a constant-time algorithm for the specific case of rectangular erosion and dilation (http://www.sciencedirect.com/science/article/pii/016786559290069C), but practically speaking, the O(n) algorithm is fast enough for reasonable radii.

StainlessS
11th September 2016, 03:12
Very sexy :)

But how would cope with something like,

HALO_L = 3 # Left Halo width in pixels
HALO_R = 4 # Right Halo width in pixels
HALO_T = 5 # Top Halo height in pixels
HALO_B = 6 # Bot Halo height in pixels

Above, as now implementing the subtitle detector.

raffriff42
11th September 2016, 05:00
@colours, I spoke before testing it. You are right of course, thank you.

@StainlessS, this seems to be accurate ± one pixel:
(EDIT rewritten with mt_expand_multi, part of Dither_tools (http://avisynth.nl/index.php/Dither_tools#Content))
https://www.dropbox.com/s/cjj7vzqaclf3p6q/mtexpand-test-10-3456-over.png?raw=1#M=mt_expand(255, 0,
#\ mt_rectangle(
#\ Round(0.5*(HALO_L+HALO_R)),
#\ Round(0.5*(HALO_T+HALO_B))),
#\ chroma="copy") ## 32fps
M=mt_expand_multi(
\ sw=Round(0.5*(HALO_L+HALO_R)),
\ sh=Round(0.5*(HALO_T+HALO_B)),
\ chroma="copy") ## 220fps
M=M.UUOffsetF(HALO_R-HALO_L, HALO_B-HALO_T)

## test - show semitransparent mask
return Overlay(M, mode="lighten", opacity=0.75)

## shift a clip up-down and left-right (sub-pixel shift)
function UUOffsetF(clip C, float offh, float offv) {
return C.BilinearResize(Width, Height, -offh, -offv, Width, Height)
}

Here is a function to work with half-size custom masks for an approximate 10x speedup. (EDIT deleted it; use above)
StainlessS, you could hack this for your needs.
Note the built-in "free" blurring; you're gonna want that, or something like it. (EDIT use GaussianBlur or something)
https://www.dropbox.com/s/11wj55lb9fbisj9/mtexpand-test-11-ex2.png?raw=1

StainlessS
11th September 2016, 05:44
Dear me !!!
You seem to have the bull by the horns :)

I cant actually feather until after detection with RT_YInRangeLocate(), so we need full size masks.

I'll have another look in the morrow, got to get some sleep before I fall down.

EDIT: Rethink, maybe I can.
Edit, nah, forget that.

Gavino
13th September 2016, 10:00
So mode seems to be a list of (x,y) coordinates, relative to the current pixel (0,0). The coordinate system is as follows:Above,left
1,1 0,1 -1,1
1,0 0,0 -1,0
1,-1 0,-1 -1,-1
Below,rightThe coordinates can extend beyond what's shown here (±1), to at least ±1000.

The pixel value at (0,0) is copied to each relative coordinate point in the list. If there are overlaps, the brightness values are OR'd together.
Perhaps you already know this, but your description works only for masks that contain just 0 and 255.
More generally, what the filter actually does is to replace each pixel by the maximum from its local neighbourhood, which is defined according to the mode.
The coordinate system used for mode is the other way round:

Above,left --> x
-1,-1 0,-1 1,-1 |
-1,0 0,0 1,0 v y
-1,1 0,1 1,1
Below,right

In the case of (0,255) masks, the overall effect is the same as with your description, but that's not how the filter actually works.

raffriff42
13th September 2016, 12:47
Thanks Gavino. Re-reading the documentation (http://manao4.free.fr/mt_masktools.html#mt_expand_mt_inpand)now, it actually makes sense. If you could similarly elucidate mt_hysteresis ("Grows the small mask into the big mask by connex components"), I would really appreciate it.

StainlessS
13th September 2016, 15:41
Thanks Gavino... If you could similarly elucidate mt_hysteresis ("Grows the small mask into the big mask by connex components"), I would really appreciate it.

++ on that :)

Gavino
13th September 2016, 16:48
If you could similarly elucidate mt_hysteresis ("Grows the small mask into the big mask by connex components"), I would really appreciate it.
I could never understand that one either, so I asked the question myself some time ago.
Here is the reply by cretindesalpes:
mt_hysteresis will keep each solid areas of the second mask depending if there is at least one pixel of the first mask in these areas. It's like a fill function trying to color the second mask from each pixel set in the first mask. Masks are considered as binary, so you'll need some mt_merge wizardry to restore the shades of grey.
See also this thread: Use spots from one mask to select spots on another mask

StainlessS
14th September 2016, 00:39
That hit the spot (so as to speak) big G. :thanks:

blaze077
23rd October 2016, 05:27
Could someone explain to me how mt_luts and mt_lutsx work?

From what is written in the documentation:
It computes the mode operation on the result of the function defined by expr, where x is the pixel from clip1, and y a pixel from the neighbourhood in clip2, defined by pixels.

I do not understand how the neighbourhood value is calculated. Does it take the value of the central pixel or does it calculate the average of all the pixels?

Also, is there a description of mt_lutsx somewhere?

Thank you.

Gavino
23rd October 2016, 11:18
I do not understand how the neighbourhood value is calculated. Does it take the value of the central pixel or does it calculate the average of all the pixels?
The form of the neighbourhood is defined by the pixels argument of the filter.
The simplest way to supply this is to use one of the helper functions. For example, pixels=mt_square(1) defines the 3x3 neighbourhood surrounding the pixel being processed.
By default, the helper functions include the centre pixel - to omit it, add zero=false to the arguments of the helper.
If none of the helper functions give you the neighbourhood you want, you can instead supply for pixels an arbitrary list of relative coordinates to define your own neighbourhood. See post #581 above for how these coordinates work.

The function mt_luts() itself works as follows.
For each output pixel:
1) Set x = corresponding pixel in input clip1
2) For each pixel in the corresponding neigbourhood of input clip2, set y to the value of that pixel and compute the relevant expression (from expr, etc). This give a set of results (one for each neighbourhood pixel).
3) The mode function (eg avg) is then applied to that set to give the value of the output pixel.

Also, is there a description of mt_lutsx somewhere?
It's in the MaskTools docs - here's my understanding of it.
mt_lutsx() has three input clips (clip, clip1 and clip2) and works differently from mt_luts().
Here, for each pixel:
1) Set x = pixel from clip
2) Set y = result of computing the mode function on the neighbourhood pixels of clip1
3) Set z = result of computing the mode2 function on the neighbourhood pixels of clip2
4) Compute the relevant expr to give the value for the output pixel.

blaze077
23rd October 2016, 18:00
Thank you for your explanation, Gavino. But I'm still not clear about one thing.

2) For each pixel in the corresponding neigbourhood of input clip2, set y to the value of that pixel and compute the relevant expression (from expr, etc). This give a set of results (one for each neighbourhood pixel).

So if a pixel is not included in the neighbourhood, then are the expression and mode both not carried out on that excluded pixel, or is the expression carried out and not the mode or vice versa?

StainlessS
23rd October 2016, 18:38
Dont know if this will help at all, but this Didée post seems to be the one upon which mt_lutsx is based:- http://forum.doom9.org/showthread.php?p=987955#post987955

Gavino
23rd October 2016, 19:42
So if a pixel is not included in the neighbourhood, then are the expression and mode both not carried out on that excluded pixel, or is the expression carried out and not the mode or vice versa?
My understanding (just from the docs - I can't remember ever actually using it!) is that if a pixel (from clip2) is not in the neighbourhood, it is simply ignored and does not contribute to the result.

For a given output pixel, the expression is evaluated for each clip2 pixel in the corresponding neighbourhood positions, and then the mode function is applied to the set of results obtained.

So in the case of a 3x3 neigbourhood and mode="avg", it evaluates the expression separately for each of the nine neighbourhood pixels, then takes the average of those nine expression results to compute the value of the output pixel.

blaze077
24th October 2016, 22:01
Thank you, Gavino. Now I understand how it works.

Dont know if this will help at all, but this Didée post seems to be the one upon which mt_lutsx is based:- http://forum.doom9.org/showthread.php?p=987955#post987955

Indeed, that looks like mt_lutsx. Seems I will have to improve on my Math to understand a lot of new things. :)

real.finder
5th February 2017, 05:43
Annoying things in masktools

aside of 422 support lack in luma=true in mt_merge, that already support in dither_merge16

luma=true with Y8 in mt_merge, ex:- https://github.com/tp7/masktools/issues/19

it should be 'luma' parameter is ignored for input clip without chroma channel as tophf said there

and another annoying thing is if U=3 or V=3 with Y8 clip then I will get error message, it should (or better) u and v ignored in Y8/Y clip

pinterf
9th February 2017, 21:47
Good evening. Hey, I have successfully compiled tp7's project under vs2015.

@real.finder:
mt_merge: luma=true with 422 is done, autofallback to chromaless mode on Y-only clip is done.

Just saying, that the work on 16 bit masktools has been started, using tp7's 16bit branch which was unfortunately abandoned much earlier than the final 8 bit release but nevertheless, quite usable.

The high bit depth addition to the framework is done, all avs+ color spaces, including planar rgb will be supported, though float will going to be supported only in phase two I think. Now come the filters one by one. The original code was aimed to work on 16 bit data only, I have to support 10-16 bits.

The first bird, binarize_16 is working nice in native 10-16 bits. Next is mt_merge16, these are classic filters, no expressions, they are very good for getting into closer relationship with the code.
You can follow the project here (https://github.com/pinterf/masktools)

real.finder
10th February 2017, 02:27
Good evening. Hey, I have successfully compiled tp7's project under vs2015.

@real.finder:
mt_merge: luma=true with 422 is done, autofallback to chromaless mode on Y-only clip is done.

Just saying, that the work on 16 bit masktools has been started, using tp7's 16bit branch which was unfortunately abandoned much earlier than the final 8 bit release but nevertheless, quite usable.

The high bit depth addition to the framework is done, all avs+ color spaces, including planar rgb will be supported, though float will going to be supported only in phase two I think. Now come the filters one by one. The original code was aimed to work on 16 bit data only, I have to support 10-16 bits.

The first bird, binarize_16 is working nice in native 10-16 bits. Next is mt_merge16, these are classic filters, no expressions, they are very good for getting into closer relationship with the code.
You can follow the project here (https://github.com/pinterf/masktools)

:goodpost:

just wonder, the existing script that use 0-255 range (in lut or other) will work in more than 8 bit? or we will need to edit hundreds of .avsi?

DJATOM
10th February 2017, 06:24
Guess it's sane to introduce option for automatic range scaling or implement it by default.

pinterf
12th February 2017, 15:47
New toy, but do not delete your existing masktools versions, although the previous (2.0b1) version had a rather nasty bug.
Report back how it works, speedwise, new bugs, etc., and a big thanks to tp7.

I actually spent more time with coding than doing tests, but nevertheless the filters were tested to give visually identical results for 8 bit, stacked 16 bit, native 10 and 16 bit processing.

Masktools v2.2 - test (https://github.com/pinterf/masktools/releases/tag/2.2.0)

### MaskTools 2 ###

Masktools2 v2.2.0.0 (20170212)

Test version

Changed:
- mt_merge accepts 4:2:2 clips when luma=true
- mt_merge to discard U and V automatically when input is greyscale
- Some filters got native 10-16 bits support with recent Avisynth+ versions for YUV and planar RGB data
(no alpha plane at the moment)
- 16 bit filters accept stacked clips. Specify stacked=true for them.
Stacked support is not intentional, but since tp7 did it, I did not remove the feature.
Filters that will be ported later, probably will not support stacked format.
- Compiled with Visual Studio 2015 Update 3,
with XP support in mind
(but it does not work :(
remark: it seems that mt_infix and mt_polish uses boost spirit vc140 library, if these
boost libs (named vc140) are linked to the masktools dll, then it is not loading in XP.)
Require VS2015 Update 3 redistributables.

Fix
- mt_merge (and probably other multi-clip filters) may result in corrupted results
under specific circumstances, due to using video frame pointers which were already released from memory

New filters that work for 10-16 bit data on Avisynth+ or stacked data on previous Avisynth versions
- mt_binarize16
- mt_lut16
- mt_logic16
- mt_merge16
- mt_average16
- mt_makediff16
- mt_adddiff16
- mt_clamp16
- mt_inflate16, mt_deflate16
- mt_inpand16, mt_expand16

Notes:
- There is no automatic range scaling in expressions.
- In future versions the base filters (e.g. mt_merge) will accept any-format clip automatically.
No separate mt_merge16 will be necessary for non-8 bit clips.

Masktools2 info:
http://avisynth.nl/index.php/MaskTools2

Project:
https://github.com/pinterf/masktools/tree/16bit

Original version: tp7's MaskTools 2 repository.
Thanks tp7, you did a great job.
https://github.com/tp7/masktools/

yup
12th February 2017, 16:51
pinterf!
:thanks:
I am testing on my scripts and see some speed up. luma=true help me (for main filter), now I can full colour from my source (captured VHS YUY2) without additional trick. Some filter do not support YV16, but this not problem because I am using only luma plane for this plugin.
yup.

real.finder
12th February 2017, 18:52
Masktools v2.2 - test (https://github.com/pinterf/masktools/releases/tag/2.2.0)


:thanks:

I try it in VirtualBox with winxp but can't load it by loadplugin(), will get error 0x3e6

and something else, b1 and a48 don't supports yv411 and if anyone work with ntsc dv will need to convert color format just for this, so can we have yv411 supports too?

tormento
12th February 2017, 20:02
New toy, but do not delete your existing masktools versions, although the previous (2.0b1) version had a rather nasty bug.
Works ok here. Minor fps improvement ~1,5%, no visible artifacts or problems.

DJATOM
12th February 2017, 20:43
pinterf
Native mode is broken: http://diff.pics/fJ6BMfn0glF4/1

pinterf
12th February 2017, 21:13
pinterf
Native mode is broken: http://diff.pics/fJ6BMfn0glF4/1
Nice painting. What function/filter was used? Perhaps clip info, processor type (There are SSE4/SSE2 code paths, even C for non-mod16 leftovers)

pinterf
12th February 2017, 21:22
I try it in VirtualBox with winxp but can't load it by loadplugin(), will get error 0x3e6

and something else, b1 and a48 don't supports yv411 and if anyone work with ntsc dv will need to convert color format just for this, so can we have yv411 supports too?
O.K. yv411 is supported, even in the merge luma=true sse2 speedups. Regarding XP: a special build works under XP for me but I had to omit boost library (there is a conditional directive for this), I don't know what else is affected if I switch it off. Functions mt_infix and mt_polish are giving error message. But I will wait a bit more, to have other issues for a hotfix.

DJATOM
12th February 2017, 22:23
Nice painting. What function/filter was used? Perhaps clip info, processor type (There are SSE4/SSE2 code paths, even C for non-mod16 leftovers)

Sure, script:
v1=DGSource("I:\KEIJO_3\BDMV\STREAM\00001.dgi").ConvertBits(16)
v2=DGSource("I:\KEIJO_3\BDMV\STREAM\00000.dgi").ConvertBits(16)
mask=v1.masktools2_z_mt_edge("prewitt",u=3,v=3)
masktools2_z_mt_merge16(v1,v2,mask,true,false).ConvertToStacked()

Just random 2 videos, it doesn't matter.
Ah, I just renamed new dll to masktools2_z.dll for having old one. CPU - i5-4670k.

pinterf
12th February 2017, 23:10
Sure, script:
v1=DGSource("I:\KEIJO_3\BDMV\STREAM\00001.dgi").ConvertBits(16)
v2=DGSource("I:\KEIJO_3\BDMV\STREAM\00000.dgi").ConvertBits(16)
mask=v1.masktools2_z_mt_edge("prewitt",u=3,v=3)
masktools2_z_mt_merge16(v1,v2,mask,true,false).ConvertToStacked()

Just random 2 videos, it doesn't matter.
Ah, I just renamed new dll to masktools2_z.dll for having old one. CPU - i5-4670k.
Ahh, mt_edge is not yet for 16 bits, I think. I didn't have time to write proper error messages for all 8 bit-only filters to reject 10+ bit clips. 8 bit processing on 16 bit data, nice :)

pinterf
13th February 2017, 22:35
:goodpost:
just wonder, the existing script that use 0-255 range (in lut or other) will work in more than 8 bit? or we will need to edit hundreds of .avsi?
I was thinking of the problem, let's see a sample expression, that streches the range 16-235 to 0-255 for luma, and 16-240 -> 0-255 for the chroma.

8 bit: new_x = (x - 16) / 219 * 255, where 219 = 235-16
10 bit: new_x = (x - 64) / 876 * 1023 where 876= 940-64
16 bit: new_x = (x - 4096) / 56064 * 65535 where 56064 = 60160-4096

For an mt_lut/mt_lut16 the reverse polish expression is:
expr8 = "x 16 - 219 / 255 *"
expr10 = "x 64 - 876 / 1023 *"
expr16 = "x 4096 - 56064 / 65535 *"

Provided you have generic script, there are many ifs or conditional Evals.

New#1: With the next masktools version you can use a new #B (or #F) operator that autoscales a 8 bit value for the current bit depth

expr_luma = "x 16 #B - 219 #B / 255 #F *"
expr_chroma = "x 16 #B - 224 #B / 255 #F *"

New#2: You can use predefined constants in your expression script, the above sample can be written as:
expr_luma = "x ymin - ymax ymin - / range_max *"
expr_chroma = "x cmin - cmax cmin - / range_max *"


New constants I have implemented:

bitdepth: automatic silent parameter of the lut expression
range_half --> autoscaled 128 or 0.5 for float
range_max --> 255/1023/4095/16383/65535 or 1.0 for float
range_size --> 256/1024...65536
ymin, ymax, cmin, cmax --> 16/235 and 16/240 autoscaled.


And there are two autoscale operators:
#B Method: bit shifts (use this for YUV) e.g. "235 #B" -> always results in max luma
#F Method: full-span stretch e.g. x/255*65535 for 16 bit rgb)

other samples
expr = "x 40 #B +"
expr = "210 #B" # scale const 210!
expr = "x 16 #B - 219 #B / 255 #B *"
expr = "x ymin - ymax ymin - / range_max *"
expr = "x ymin - ymax ymin - / range_max * range_half 2 / +"

Opinions?

real.finder
14th February 2017, 07:37
pinterf, that seems good to me (but you should wait for others as I don't have many experiences with lut)

I see TheFluff said that vs expr (https://forum.doom9.org/showpost.php?p=1773737&postcount=36) is fast even in 8 bit, did you have look at expr (http://www.vapoursynth.com/doc/functions/expr.html)?

and another thing, cretindesalpes did mt_xxpand_multi.avsi back then, can this be in masktools.dll? I think this will be faster than what cretindesalpes did in .avsi

pinterf
17th February 2017, 09:55
I'm in the middle of porting lut functions for high bit depth, and had to do the realtime calculation for them, which is default when lut tables are too big (but nevertheless implemented optional 16 bit lutxy for hardcore x64 users with plenty of RAM :-) )
Now I know what a JIT could help speedwise, because realtime computing is really not a speed champion. Obviously using JIT would be the next logical evolution step.

TheFluff
18th February 2017, 15:07
https://github.com/vapoursynth/vapoursynth/blob/master/src/core/exprfilter.cpp

blaze077
18th February 2017, 23:43
Thank you for the release, pinterf. :)

martin53
25th February 2017, 11:16
Just for all readers reference:
New masktools2a.48 successor (masktools2 pfmod) thread here (http://forum.doom9.org/showthread.php?t=174333)