View Single Post
Old 7th April 2004, 13:04   #1  |  Link
Didée
Registered User
 
Join Date: Apr 2002
Location: Germany
Posts: 5,389
BlindDeHalo() - removal of Edge Enhancement artefacts

Hello folks,

once more I did a little scripting, and came up with a procedure that seems quite usable to remove those ugly bright and dark halos from edge enhancement.

One important warning beforehand:

Be careful when using other functions of MaskTools before this script,
or when calling it before iiP() !!!


The MaskTools currently are a little tricky to use - I'll explain this further below.


First, the script:
Code:

# BlindDeHalo - v0.1
#
# This script removes the light & dark halos from too strong "Edge Enhancement"
# Adaption of the parameters has to be done manually for each source, the function is not adaptive.
#
# Needed Plugins: MaskTools.dll >= 1.4.15
#                 undot.dll
#

function BlindDeHalo( clip clp, int "strength", int "radius_x", int "radius_y", float "darkamount", string "mode", float "maskblur", bool "fullframe" )
       {
         strength =   default( strength,  80)
         radius_x =   default( radius_x,   2)
         radius_y =   default( radius_y,   2)
         darkamount = default( darkamount,1.0)
         mode =       default( mode,  "soft")
         maskblur =   default( maskblur, 1.0)
         fullframe =  default( fullframe, false)
         modus = mode=="hard" ? "hardlight" : "softlight"

         ox = clp.width
         oy = clp.height
         rx = sqrt(radius_x)
         ry = sqrt(radius_y)

         clp
         edge=Dedgemask(0,255,0,255,"6 10 6 10 -64 10 6 10 6",setdivisor=true,divisor=64).levels(2,0.5,6,0,255,false).undot#.coloryuv(analyze=true)#

         blur1 = bicubicresize(int((ox/rx)/4 +.5)*4,int((oy/ry)/4 +.5 )*4,-1.0,1.0).lanczosresize(ox,oy)
         blur2 = bicubicresize(int((ox/rx)/4 +.5)*4,int((oy/ry)/4 +.5 )*4, 1.0,0.0).lanczosresize(ox,oy)

         diff = YV12subtract(blur1,blur2)

         overlay(diff,diff,mode="hardlight").levels(0,1.0,255,88,168,false)

         darkamount == 1.0 ? NOP : overlay(last,last.levels(0,1.0,128,int(128-128*darkamount),128,false),mode="lighten")
         overlay(last,last.levels(0,1.0,255,128+strength,128-strength,false)) # levels reversed: no more "invert" in below overlay()

         overlay(clp,last.greyscale.blur(maskblur),mode=modus)
         fullframe ? NOP : MaskedMerge(clp,last,edge.deflate.expand.blur(1.58).inflate,useMMX=true)

         return(last)
       }
#
The most basic usage is as simple as: BlindDeHalo()

However, there are several parameters to adjust the filtering, and you definetly want to setup those parameters manually for each source.

Basically, the following is what is going on:

- The script does not reckognize any halos in the source! It simply looks for hard edges, and reduces the contrast in their neighborhood.

- A gaussian blurred (well, sort of that) version of the clip is subtracted from a sharpened version. This delivers a mask that is suited for the given purpose.

- Then, the source clip is "Softlighted" by this mask, et voilà ...


Parameter description

strength [int]
The overall strength of contrast reduction around hard edges. Default is 80, usuable range is 0 - 128.

radius_x, radius_y [int] [int]
This is [similar to] the radius of a gaussian blur. These radii must be adjusted to match the "thickness" of the halos in your source. Default is 2, usable range is from 2 to about 5.

Note: A radius of 1 disables the processing in the corresponding direction. E.g. for VHS-caps, setting radius_y=1 and radius_x=3|4|5 should be the right thing. (Didn't test this myself.)

darkamount [float]
With this parameter, the removing of dark halos can be reduced. A value of 1.0 will treat both bright and dark halos equally, 0.5 will process dark halos with only half the strength, 0.0 will disable the processing of dark halos.
Explanation: Theroretically, bright & dark haloing should be always equal. But I encountered some sources where the bright halos seemed to be much stronger than the dark ones, and so I implemented this parameter.
Moreover, generally bright halos are more distracting than dark ones. So it might be a good idea to process the dark ones a little weaker, to retain more overall contrast in the clip.
Default is 1.0 however, as this gives the fastest processing speed

mode [string]
This can be either "soft" or "hard", and simply decides wether to use 'softlight' or 'hardlight' in the final 'overlay()' command.
Default is "soft". You might try "hard" along with some lower values for "strength" - dunno if this may turn out useful somewhere.

maskblur [float]
This simply tells how strong the lightmask will be blurred. Stronger blurring will keep a little more sharpness in the clip, but will reduce the halo removal a little.
Default is 1.0, range is 0.0 - 1.58. Play and see for yourself.

fullframe [bool]
This is mainly a bug-workaround for a specific strangeness in the current MaskTools.
"false" is (or should be) the best setting regarding IQ. But if set to false, the YV12LUT command from MaskTools will work *no more* after calling BlindDeHalo! This is poison for e.g. iiP() ...
Set it to "true" if you need YV12LUT() after calling BlindDeHalo(), or if you're going to use it as pre-processor for iiP. (I will integrate it in the near future into iiP, anyway).


IMHO, this function can be set up to be way more effective against halos than e.g. using unfilter(-,-) -- better removal of halos, less damage to fine details and overall sharpness.

However, my testing so far was not very extensive: Your experiences, suggestions and flames are welcome.

(BTW, this script is *fast*, compared to Didée's usual standard: a 16:9 704*432 frame gets processed at ~10 fps on my XP1800.)

Have fun

- Didée
__________________
- We´re at the beginning of the end of mankind´s childhood -

My little flickr gallery. (Yes indeed, I do have hobbies other than digital video!)

Last edited by Didée; 7th April 2004 at 13:13.
Didée is offline   Reply With Quote