Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion. Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules. |
![]() |
#1 | Link |
dumber every day
Join Date: Dec 2006
Location: Planet Earth
Posts: 154
|
Remove Logos Again
After I made changes to the delogo script I promised myself I would not work on any other delogo functions BUT the avsinpaint function just called me back.
![]() In the Avsinpaint thread Reuf Toc made a very nice script (wish I could code that nice !) but I wanted to add my own twists that I learned from modding the delogo script and experimenting with avsinpaint. So I did some combining and adding and the result is rm_logo. Basic usage is as follows: 1) Get a clip with a logo that you want removed. 2) Save a frame from that clip and edit it in your favorite graphics program, paint the logo pure white and everything else black. Save it as a logo.bmp (any name you want) 3) Make a avs script such as: Code:
LOADCPLUGIN("AVSINPAINT.DLL") Import("rm_logo.avs") avisource("videowithlogo.avi") rm_logo(last,logomask=logo.bmp",loc="br",par=4.0/3.0,mode="both",percent=20,pp=1) logomask -- the name of the black and white bmp you created loc -- TR, TL, BR, BL this is the location of the logo on the video, top right, top left, bottom right, bottom left. There is also a tweak you can supply here called cutsize set it to small medium or large. It refines the size of the corner cut somewhat. If you have to much video and not enough logo in a cut you can get less optimal results, you want the logo to fill the cut (within reason). par -- pixel aspect, no harm if you don't specify it, it just helps grow masks correctly in all directions. mode -- how to remove the logo, deblend (for purely transparent logos. inpaint for purely solid logos and both for logos with both. percent -- The percent of total frames to use in computing the masks, the more the better and the slower. pp -- Post Process, 1,2 or 3. Apply some additional post processing of the removed area to further hide the logo and artifacts. The first time the script runs expect it to take a little time, it has to compute the color and alpha masks so it will appear to lock up on you for a min or two while its doing this. Once done it will save a analysis bmp file so it will be responsive from then on. There are other things to tweak, look in the script for more information. Script in the next post. |
![]() |
![]() |
![]() |
#2 | Link |
dumber every day
Join Date: Dec 2006
Location: Planet Earth
Posts: 154
|
Code:
# rm_logo() Version 0.5 -- 23.04.08 # # Script to help in the removal of channel logos or other distracting objects # # Required filters: # AVSInpaint: Ver 2008-01-06 # Discussion & Code : http://forum.doom9.org/showthread.php?t=133682 # ExInpaint: Ver 0.1+ # Code http://avisynth.org.ru/exinpaint/exinpaint.html # mt_masktools: Ver 2.0.32+ # Code http://manao4.free.fr/masktools-v2.0a32.zip # removegrain: Ver 1.0 (8/2005) # Code http://www.removegrain.de.tf # fft3dfilter: Ver 2.1.1 or later # Code http://avisynth.org.ru/fft3dfilter/fft3dfilter.html # ttempsmoothf Ver 0.9.4 or later # Code http://bengal.missouri.edu/~kes25c/ # medianblur Ver 0.8.4 # Code http://www.avisynth.org/tsp/medianblur084.zip # function rm_logo( clip clp, string "logomask", string "loc",float "par", string "mode",int "percent",int "deblendfalloff",\ int "AlphaToRepair", float "RepairRadius", float "InpaintRadius", float "InpaintSharpness",\ float "InpaintPreBlur", float "InpaintPostBlur", string "cutsize", bool "lmask", int "pp", bool "debug", \ int "cutwidth", int "cutheight") { logomask = default( logomask, "" ) # file location of the logo, the must be masked in pure white loc = default( loc, "" ) # where is the logo, TR, TL, BR, BL for top right, top left, bottom right, bottom left cutsize = default( cutsize, "small" ) # how big a cut to make, small, medium, large cutwidth = default( cutwidth, 0 ) # how wide a cut to make in pixels, -1 for full width of frame cutheight = default( cutheight, 0 ) # how tall a cut to make in pixels, -1 for full height of frame par = default( par, 1.0 ) # pixel aspect ratio mode = default( mode, "both" ) # deblend, inpaint or both percent = default( percent, 25 ) # how much of the clip to analyse in creating color&alpha masks, more is better but slower deblendfalloff = default( deblendfalloff, 5 ) # graidient fallout from logo mask AlphaToRepair = default( AlphaToRepair, 130 ) # what is the luma value of the solid part of the logo RepairRadius = default( RepairRadius, 1.0 ) # used to expand the mask for none alpha ie solid areas InpaintRadius = default( InpaintRadius, 6.0 ) # radius around a damaged pixel from where values are taken when the pixel is inpainted. Bigger values prevent # inpainting in the wrong direction, but also create more blur InpaintSharpness = default( InpaintSharpness, 25.0 ) # Higher values can prevent blurring caused by high Radius values. InpaintPreBlur = default( InpaintPreBlur, 1.5 ) # Standard deviation of the blur which is applied to the image before the structure tensor is computed. Higher values # help connecting isophotes which have been cut by the inpainting region, but also increase CPU usage. PreBlur=0.0 # disables pre-blurring. InpaintPostBlur = default( InpaintPostBlur, 5.0 ) # standard deviation of the blur which is applied to the structure tensors before they are used to determine the # inpainting direction. Higher values help gather more directional information when there are only few valid pixels # available, but increases CPU usage lmask = default( lmask, true ) # apply post process through a repair mask PP = default( PP, 1 ) # Post process function 0,1,2 to help reduce damage left behind by logo removal debug = default( debug, false ) # show mask to help in tunning the output # set up some values that we need to run clp_width = width( clp ) clp_height = height( clp ) RGB = isRGB( clp ) RGB32 = isRGB32( clp ) RGB24 = isRGB24( clp ) par = ( par!= 1.0 ) ? float( clp_height ) / float( clp_width ) * par : 1.0 percent = ( percent < 0) ? 25 : (percent > 100) ? 100 : percent # Get the always fun input error checking done assert ( logomask != "" , "You have to define a logomask") assert ( loc != "" , "You must provide a value for Loc UL,UR,LL,LR") assert ( loc == "TR" || loc == "TL" || loc == "BR" || loc == "BL" , "Loc must be one of TR, TL, BR, BL") assert ( mode == "both" || mode == "inpaint" || mode == "deblend", "Specified mode doesn't exist.") # Get our crop locations based on the passed location loc = UCase( loc ) cutsize = UCase( cutsize ) multi = ( cutsize == "SMALL" ) ? 2.25 : ( cutsize == "MEDIUM" ) ? 2.15 : 2 chunk = ( clp_height > 720 ) ? 2.9 : 3 cutwidth = ( cutwidth == 0 || cutwidth == -1 ) ? cutwidth : m4(cutwidth) cutheight = ( cutheight == 0 || cutheight == -1 ) ? cutheight : m4(cutheight) a = ( Rightstr( loc, 1 ) == "L" ) ? 0 : ( cutwidth == 0 ) ? m4( ( clp_width / chunk ) * multi ) : ( cutwidth == -1 ) ? 0 : (clp_width - cutwidth) b = ( Leftstr( loc, 1 ) == "T" ) ? 0 : ( cutheight == 0 ) ? m4( ( clp_height / chunk ) * multi ) : (cutheight == -1 ) ? 0 : (clp_height - cutheight) c = ( Rightstr( loc, 1 ) == "R" ) ? 0 : (cutwidth == 0) ? -m4( ( clp_width / chunk ) * multi ) : (cutwidth == -1 ) ? 0 : -(clp_width - cutwidth) d = ( Leftstr( loc, 1 ) == "B" ) ? 0 : (cutheight == 0 ) ? -m4( ( clp_height / chunk ) * multi ) : (cutheight == -1) ? 0 : -(clp_height - cutheight) cropped = clp.crop(a,b,c,d) # Anaylse the entire clip or a percentage for speed. snipSize = round( framecount( cropped ) / (framecount( cropped ) * (percent / 100.0) )) analyse = ( percent != 100 ) ? cropped.SelectRangeEvery( snipSize, 1 ) : cropped # Read in our logo mask, prepare it and crop out the corner of interest logo_mask = imagesource(logomask,start=0,end=1) logo_mask = logo_mask.crop(a,b,c,d) logo_mask = logo_mask.ConvertToYV12(Matrix="PC.601") logo_mask = logo_mask.DistanceFunction(255/deblendfalloff,PixelAspect=par).Greyscale # Clean the analyse clip to improve results analyse = (IsYV12(analyse)) ? analyse : analyse.ConvertToYV12 analyse = analyse.TTempSmoothF(maxr=2,lthresh=256,cthresh=256,scthresh=255).converttoRGB24() input = ( RGB24 == true ) ? cropped : cropped.converttoRGB24() # seperate out the directory and logo names so we can save a unique ebmp file sl = logomask.revstr().findstr("\") - 1 Assert((sl >= 0),"specify a fully qualified directory and logomask name to use") logo_name = (sl < 0 ) ? "" : rightstr(logomask,sl) # name and extension s2 = logo_name.findstr(".") - 1 # find the length of the extension logo_name = leftstr(logo_name,s2) # just the name ! Analyse_Name = logo_name + loc + string(percent) + "AnalyzeResult%06d.ebmp" # Time to run the analysis on the logo, we want the color map and alpha map out of the file. try { # Analyze is a bit slow so we only do it once and store the result in a file, check if it exists or if it has changed ImageSource(Analyse_Name,0,0) (Interleave( AssumeFPS(input.FrameRate), input.Trim(0,-2).AnalyzeLogo(logo_mask) ).FrameCount > 3) ? last : last } catch( dummy ) { # Nice catch, we are here since we need to perform our logo analysis as none already exists analyse.AnalyzeLogo(logo_mask) # The analysis is complete, save a frame (all frames are the same) Trim( 0, -1 ) ImageWriter( logo_name + loc + string(percent) + "AnalyzeResult", 0, 1, "ebmp" ) } # The color map is the top half of the Analyze result, The alpha channel is in the bottom half AssumeFPS(analyse.FrameRate) LogoColor = Crop(0,0,0,last.Height/2) LogoAlpha = Crop(0,last.Height/2,0,0).ConvertToYV12(Matrix="PC.601") # Create a Deblend mask, this is a mask that falls off the marked logo area, we use this to blend the delogoed area back into the clip DeblendMask = logo_mask.DistanceFunction( 255.0 / DeblendFalloff, PixelAspect=par ) # Create a repair mask for pixels that cannot be deblended LogoAlpha.Invert.mt_lut(expr="x " + " " + string(alphatorepair) + " " + "< 255 0 ?").mt_expand.mt_inflate RepairMask = ( RepairRadius > 0.1 ) ? DistanceFunction( 84.0 / RepairRadius, PixelAspect=par ) : last # InpaintLogo and DeblendLogo based on user preferance deblend = ( mode == "both" ) ? input.DeblendLogo(LogoColor,LogoAlpha) \ : ( mode == "deblend" ) ? input.DeblendLogo(logoColor,logoAlpha) : input repaired = ( mode == "both" ) ? deblend.InpaintLogo(RepairMask, Radius=InpaintRadius, Sharpness=InpaintSharpness, \ PreBlur=InpaintPreBlur, PostBlur=InpaintPostBlur, PixelAspect=par) \ : ( mode == "inpaint" ) ? deblend.InpaintLogo(RepairMask,Radius=InpaintRadius, Sharpness=InpaintSharpness, PreBlur=InpaintPreBlur,\ PostBlur=InpaintPostBlur, PixelAspect=par) : deblend #repaired = ExInpaint (repaired.converttorgb32, repairmask.converttorgb32, color=$ffffff,xsize=5, ysize=3, radius=36) output = Layer(input.ConvertToRGB32, repaired.ConvertToRGB32.Mask(DeblendMask.ConvertToRGB32(Matrix="PC.601"))) output = output.converttoyv12 # post processing of the results if requested postmask = LogoAlpha.Invert.mt_lut(expr="x " + " " + string(alphatorepair) + " " + "< 255 0 ?").mt_expand.mt_inflate postmask = postmask.DistanceFunction( 64.0 / RepairRadius, PixelAspect=par ) #postmask = (pp > 0 && lmask) ? repairmask.DistanceFunction( 512.0 / DeblendFalloff, PixelAspect=par ) : blankclip(output,color=$000000) post = ( PP == 1 ) ? output.minblur(1,uv=3).medianblur(3,0,0).removegrain(11) \ : ( pp == 2 ) ? output.fft3dfilter(sigma=16,sigma2=12,sigma3=8,sigma4=4,bt=3,bw=16,bh=16,ow=8,oh=8,plane=4) \ : ( pp == 3 ) ? output.mt_convolution("1 8 28 56 76 56 28 8 1","1 8 28 56 76 56 28 8 1",y=3,v=2,u=2) \ : output output = ( pp > 0 ) ? mt_merge(output,post,postmask) : output aa = debug ? stackhorizontal(logo_mask.ConvertToYV12.subtitle("logo mask"),logocolor.ConvertToYV12.subtitle("Logo Color"),logoalpha.ConvertToYV12.subtitle("Logo Alpha")) : nop bb = debug ? stackhorizontal(deblendmask.ConvertToYV12.subtitle("Deblend Mask"),repairmask.ConvertToYV12.subtitle("Repair Mask"),postmask.ConvertToYV12.subtitle("Post Mask")) : nop cc = debug ? stackhorizontal(cropped.ConvertToYV12.subtitle("Original"),repaired.ConvertToYV12.subtitle("Repaired"),output.ConvertToYV12.subtitle("Post")) : nop # Almost done, lets blend in our repair output = (RGB == true) ? (RGB24 == true) ? output : output.converttoRGB32() : output.converttoYV12() final = clp.overlay(output,a, b) RETURN debug ? stackvertical(aa,bb,cc) : final } FUNCTION MinBlur(clip input, int r, int "uv") { # Nifty Gauss/Median combination # Taken from MCBob.avs: uv = default(uv,3) # process chroma if uv==3, otherwise just luma uv2 = (uv==2) ? 1 : uv rg4 = (uv==3) ? 4 : -1 rg11 = (uv==3) ? 11 : -1 rg20 = (uv==3) ? 20 : -1 medf = (uv==3) ? 1 : -200 # make our blur clips, r controls amount RG11D = (r==1) ? mt_makediff(input,input.removegrain(11, rg11),U=uv2,V=uv2) \ : (r==2) ? mt_makediff(input,input.removegrain(11,rg11).removegrain(20,rg20),U=uv2,V=uv2) \ : mt_makediff(input,input.removegrain(11,rg11).removegrain(20,rg20).removegrain(20,rg20),U=uv2,V=uv2) RG4D = (r==1) ? mt_makediff(input,input.removegrain(4,rg4),U=uv2,V=uv2) \ : (r==2) ? mt_makediff(input,input.medianblur(2,2*medf,2*medf),U=uv2,V=uv2) \ : mt_makediff(input,input.medianblur(3,3*medf,3*medf),U=uv2,V=uv2) DD = mt_lutxy(RG11D,RG4D,"x 128 - y 128 - * 0 < 128 x 128 - abs y 128 - abs < x y ? ?",U=uv2,V=uv2) RETURN (input.mt_makediff(DD,U=uv,V=uv)) } FUNCTION m4(float x) {RETURN( x<16?16:int(round(x/4.0)*4)) } Last edited by Spuds; 7th May 2008 at 18:16. Reason: Version 0.5 |
![]() |
![]() |
![]() |
#3 | Link |
Fighting spam with a fish
Join Date: Sep 2005
Posts: 2,691
|
*cracks fingers*
Looks like I now have two logo removal functions to add to the wiki. Will post a link when done. Note: Typo on line 18. Should say "MedianBlur", not "MediumBlur". Oh, and finished with the wiki page. Have a look: http://avisynth.org/mediawiki/Rm_logo Feel free to upload any new versions there, where they will always be accessible. (Plus, easier to search for.) Last edited by Adub; 17th February 2008 at 05:54. |
![]() |
![]() |
![]() |
#5 | Link |
Registered User
Join Date: Feb 2007
Posts: 65
|
Change lines
Code:
a = ( Rightstr( loc, 1 ) == "L" ) ? 0 : round( ( clp_width / 3 ) * multi ) b = ( leftstr( loc, 1 ) == "T" ) ? 0 : round( ( clp_height / 3 ) * multi ) c = ( Rightstr( loc, 1 ) == "R" ) ? 0 : -round( ( clp_width / 3 ) * multi ) d = ( leftstr( loc, 1 ) == "B" ) ? 0 : -round( ( clp_height / 3 ) * multi ) Code:
a = ( Rightstr( loc, 1 ) == "L" ) ? 0 : round( ( clp_width / 6 ) * multi )*2 b = ( leftstr( loc, 1 ) == "T" ) ? 0 : round( ( clp_height / 6 ) * multi )*2 c = ( Rightstr( loc, 1 ) == "R" ) ? 0 : -round( ( clp_width / 6 ) * multi )*2 d = ( leftstr( loc, 1 ) == "B" ) ? 0 : -round( ( clp_height / 6 ) * multi )*2 |
![]() |
![]() |
![]() |
#6 | Link |
dumber every day
Join Date: Dec 2006
Location: Planet Earth
Posts: 154
|
@K0zi -- I updated the script in post #2 (as well as the wiki) it should take of the issue. If it does not what Reuf Toc posted will work very well.
The changes in this version are fixing the above error, adding some basic input checking and validating the color space is valid for certain functions. |
![]() |
![]() |
![]() |
#12 | Link |
Registered User
Join Date: Feb 2007
Location: ::1
Posts: 1,236
|
I just get an error saying there's no function "DistanceFunction"
![]() At this line (#84): logo_mask = logo_mask.DistanceFunction(255/deblendfalloff,PixelAspect=par).Greyscale I'm pretty sure I have all the required filters? EDIT: Alright, sorry, fixed that. I had to load AviSynth_C.dll and then load AVSInpaint.dll externally with LoadCPlugin. Now waiting to see if it works... LOL, if it is indeed working, this puppy takes forever with 1080p footage xD Last edited by Ranguvar; 22nd February 2008 at 00:09. |
![]() |
![]() |
![]() |
#14 | Link | ||
dumber every day
Join Date: Dec 2006
Location: Planet Earth
Posts: 154
|
Quote:
Quote:
![]() In the 0.3 version I added a debug=true option, it will output some screens to help see what the script is doing as well as see what the parameters are changing. Here is an example: Code:
rm_logo(last,logomask=videos+"cbs2.bmp",loc="br",par=4.0/3.0,mode="both",percent=30,debug=true) ![]() Let me know if you find other problems that need to be addressed and I'll put them in the 0.4 with 1080 improvements. |
||
![]() |
![]() |
![]() |
#16 | Link |
dumber every day
Join Date: Dec 2006
Location: Planet Earth
Posts: 154
|
@K0zi
I posted a 0.4 version, this one saves the analysis.bmp file with a unique name based off the logo name, its location and percentage. This should avoid conflicts if you want to call it twice or more in a single script. This version also has a small change to help with wide screen clips, by allowing it to cut a smaller area for the analysis. |
![]() |
![]() |
![]() |
#18 | Link |
Registered User
Join Date: Nov 2006
Posts: 83
|
Hi Spuds,
just wanted to say thank you for this nice script. I haven't finished testing it, but it seems to be really effective. Would it be possible to add MV based image restoration to the function? It could be something like compute the vectors of the 2 previous and following frames with a radius of the clip height/10 around the logo only in the second pass. When a block moves towards the vector and "disappears" it could be layered over the logo, or be mixed with with the Inpainting. (I hope you understand what i mean). With this limited MV fetching the script shouldn't become unusably slow. It would also really useful, if the function could do a check if the logo is present. On many sources the logo disapears periodically (due to commercial cuts or whatever). This should be doable with Masktools (?!). If no logo is present the frame will not be taken intoaccount for the first pass and won't be delogoed in the second. Keep in mind that logos reappear (and dissapear) smoothly most times, so it should be thresholded. Another killer feature to add could be a function to remove hardcoded subs. With masking, Inpainting and MV based restoration it should be doable, but i'm no expert. To prevent the function from removing words in the movie (cast, director etc.) the processed are could be limited to the middle of the bottom, so one must specifiy how much the processed area expands from the middle of the last line in the x and y axis. But perhaps this should be a separate function. I really hope i can contribute a few lines of code in the future, but atm, i can only make suggestions what could be improved based on my very limited understanding of avisynth's syntax and it's PlugIns. Looking forward to some further development. :-) Regards McCauley Last edited by McCauley; 2nd April 2008 at 02:01. Reason: Made some hopefully useful suggestions |
![]() |
![]() |
![]() |
#19 | Link | ||
Registered User
Join Date: Nov 2006
Posts: 83
|
Hi,
it's me again :-) General hint: It's really important that the logo is present in every analyzed frame (check before!).See below. Should the pure white logo be very precise or should it be a few pixels bolder than the station logo(like in Didée's delogo Function)? Keep in mind that there is always some ringing around the logo. When processing with a clip with sharp black bars, the analyzed area has a soft transition after applying the script. I guess that is caused by the yv12/rgb/yv12 conversion ?! I fixed that with Quote:
cutsize -- Why not just use the center of the logo and expand the cutsize from that? If the logo is not very big, but closer to center of the frame one clould skip analysing the border areas, since they are uzeless anyway pp -- Post Process, 1,2 or 3. Apply some additional post processing of the removed area to further hide the logo and artifacts. What do they in particular?! with my clips changing pp didn't do anything (or almost nothing). Do they only make diffrerence with inpainting? The logos i removed where deblending only. A simple blur(~.3) sometimes does the magic. I refined the description a bit, maybe you want to add it to your first post: 1) Get a clip with a logo that you want removed. Prepare your clip for the analysis pass: check if the logo is at its place from the beginning to the end, often it appears first after a few seconds or even minutes after the movie/series has started (use trim or more advanced functions for that). Sometimes the logo disappears due to commercial cuts or whatever, to check for that insert "selectevery(300)" (values between 100 and 500 should be appriate, the lower the value, the more frames you have to check!) at the end of your script, skipp through them to see if the logo is present in every frame. if not you have you have to trim it out manually to get optimal results for the analysis pass. You can also exclude the credits to save time, because they won't improve the analysis pass. A black background is not very useful to get any alpha information. 2) Save a frame from that clip and edit it in your favorite graphics program, paint the logo pure white and everything else black. Save it as a logo.bmp (any name you want). To make it easy for yourself you should choose a frame frome the credits, or where the logo has a dark background. That helps with the painting if you're not so experienced with image processing. 3) Make a avs script such as: Quote:
stuck due to the analysis pass with suboptimal settings. BEFORE you run the analysis you MUST save the script, otherwise the analysis detects a "change" in the script's name and will run again, when loading it into VDub or any other GUI. After the analysis pass is finished you can remove the trim command(s) and optimize your script with deblocking, denoising, resizing, sharpening or whatever you want to apply, put the filters after the rm_logo call, since this is now your source. percent -- The percent of total frames to use in computing the masks, the more the better and the slower. Values above 50% shoulnd't be useful in any case, except maybe with very, very short clips. The first time the script runs expect it to take a little time, it has to compute the color and alpha masks so it will appear to lock up on you while its doing this. Depending on the size of your clip and the percentage of anaylysis you set, i can take some time. Up to 2 hours or more for 1080p footage on a C2D! Regards McCauley |
||
![]() |
![]() |
![]() |
#20 | Link | |||
dumber every day
Join Date: Dec 2006
Location: Planet Earth
Posts: 154
|
@McCauley
Thanks for all the suggestions on improvements, there are some very good ideas that I'll tinker around with to see what improvements we can get and if there is a way to implement them so they work correctly (ie logo present or not). Quote:
Quote:
Thanks for all the documentation updates, I'll update the readme and wiki with the improvements, I think you listed most of the gotchas with the delogoing process, fun huh ![]() Quote:
Again thanks for the help and suggestions! |
|||
![]() |
![]() |
![]() |
Thread Tools | Search this Thread |
Display Modes | |
|
|