#____________________________________________________________________________________ # # ######. ## # .## ### ## # .## ### .##########. ## .#####. .#####.# .#####. # .####### ## ## ## ## ## ## ## ## ## ## # .###### ## ## ## ## ## ## ## ## ## ## # .## ### ## ## ## ## ## ## ## ## ## ## # .## ### ## ## ## ##..... ## ## ##.....## ## ## # .## ### ## ## ## ###### ######## '#####' '#### ## '#####' # ## # .###### #____________________________________________________________________________________ # rm_logo() версия 0.5.1 -- 14.12.2011 # Модифицировано unreal666 на основе версии 0.5 и скрипта InpaintFunc # # Скрипт, помогающий удалять логотипы каналов или другие мешающие объекты #____________________________________________________________________________________ # Требуемые фильтры: # 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.0a48.zip # removegrain: # Code http://www.removegrain.de.tf/ # fft3dgpu: Ver 0.8.2 # Discussion & Code http://forum.doom9.org/showthread.php?t=89941 # medianblur Ver 0.8.4 # Code http://www.avisynth.org/tsp/medianblur084.zip #______________________________________________________________________________________ # # Как делать : #______________________________________________________________________________________ # 1) Получите видео с логотипом, который вы хотите удалить. # Подготовьте видео для анализа. Очень важно, чтобы логотип присутствовал в каждом анализируемом кадре. # Удостоверьтесь, что логотип присутствует с начала до конца. Часто он появляется только после нескольких секунд # или минут с начала видео. Иногда логотип исчезает из-за рекламных вставок. # Для получения после анализа оптимальных результатов вы должны вырезать куски без логотипа. Для экономии времени # вы можете также исключить титры, т.к. они не улучшат результаты анализа. Черный фон не очень полезен для получения # любой альфа-информации. # 2) Сохраните кадр из вышеупомянутого видео и отредактируйте его в граф. программе, закрасив логотип чисто белым цветом, # а остальное - черным. Сохраните его в logo.bmp (с любым желаемым именем). Для облегчения закраски можете выбрать кадр # из титров или где у логотипа темный фон. # 3) Создайте avs-скрипт типа: rm_logo(last,logomask="logo.bmp",loc="br",par=(4.0/3.0)*(576.0/720.0),mode="inpaint",percent=20,PPMode=1) # 4) После окончания анализа можете вставить вырезанные куски обратно в видео и добавить деблокинг, удаление шумов и т.п. после # вызова rm_logo # Примечание: При первом выполнении скрипта приложение как-будто бы зависнет. В данный момент будут вычисляться маска цветов и альфа-маска. # В зависимости от размера части изображения с логотипом, установленного параметром loc, и указанных процентов это может занять некоторое время. # До 2 часов или больше для 1080p на Intel Core 2 Duo! #______________________________________________________________________________________ # # Параметры функции : #______________________________________________________________________________________ # string "logomask" : Расположение файла-логотипа. Маска логотипа должна быть чисто белого цвета, а фона - черного. # Изображение должно быть или 24- или 32-битным. Поддерживаемые форматы изображений см. в описании фильтра ImageSource. # String "loc" : Выбор части изображения, где находится удаляемый логотип. # См. таблицу : # # ______________ ______________ # | TL | TC |TR | | X1 | X2 |X3 | # |____|____|___| |____|____|___| # | ML | MC |MR | or | Y1 | Y2 |Y3 | # |____|____|___| |____|____|___| # | BL | BC |BR | | Z1 | Z2 |Z3 | # |____|____|___| |____|____|___| # # Если удаляемый логотип находится в правом верхнем углу, вы можете выбрать # или loc="TR" или loc="x3". # # Если вы не хотите использовать один из этих пресетов, то для изоляции логотипа вы можете вручную ввести значения кропа (обрезки). # пример : loc = "0,300,-440,-20". В параметре "loc" не разрешены пробелы. # Для помощи установки значений обрезки вы можете использовать функцию InpaintAssist. # # float "par" : Pixel Aspect Ratio (соотношение размеров пикселей) вашего видео. # Например, для видео 16:9 DVD с разрешением 720x576, будет использоваться PixelAspect=(16.0/9.0)*(576.0/720.0)?1.422. # Т.е. PAR = DAR/SAR (DAR - Display Aspect Ratio, SAR - Sample Aspect Ratio). # Результат ф-и DistanceFunction изменяется (искажается) в соответствии с этим значением. # По умолчанию: 1.0 # # string "mode" : 3 выбора: # - Deblend : Если логотип прозрачный, используйте этот режим. # - Inpaint : Если логотип непрозрачный, используйте этот режим. # - Both : Если логотип и прозрачный и непрозрачный, используйте этот режим. # По умолчанию: inpaint # # int "Exmode" : 3 выбора: # - 0 : Никакого влияния # - 1 : В этом режиме после восстановления пикселей в режиме mode дополнительно применяется функция ExInpaint. # - 2 : В этом режиме для восстановления пикселей применяется только функция ExInpaint. В таком режиме значение параметра mode влиять # ни на что не будет, т.е. типа 4-й режим для параметра mode. # По умолчанию: 0 # # float "percent" : Процент анализа клипа для создания маски цвета и альфа-маски. Больше лучше, но медленней. # По умолчанию: 25 # # int "deblendfalloff" : Коэффициент при создании градиентного поля из маски логотипа. Чем больше этот коэффициент, тем больший размер # градиентного поля вокруг точек логотипа и, соответственно, тем сильнее наложение восстановленной части на оригинал. # При положит. значениях градиент создается для области точек со значениями более 127. Каждому пикселю вне этой # области с расстоянием d от этой области будет присвоено значение 255*(1-d/deblendfalloff). При отрицат. # значениях цвет инвертируется до и после расчета. # При значениях больше 255 и меньше -255 (255 < deblendfalloff < -255) изображение просто делается 2-ух цветным # (1-битным). Примерно то же, что и Levels(127,1,128,0,255). # По умолчанию: 5 # # int "AlphaToRepair" : Значение яркости сплошной (т.е. непрозрачной) части логотипа в альфа-канале после анализа. Все, что ниже этого значения, # восстанавливаться/подрисовываться не будет. Используется и при основном восстановлении и при постобработке. # Включайте режим отладки и смотрите, чтобы в Logo Inpaont попало то, что нужно. # По умолчанию: 55. # # float "RepairRadiusPre" : Используется для расширения маски сплошной (т.е. непрозрачной) части логотипа при создании маски LogoInpaint. # По умолчанию: 1.0. # # float "RepairRadiusPost" : Используется для расширения маски сплошной (т.е. непрозрачной) части логотипа при создании маски PostMask. # По умолчанию: 1.0. # # float "InpaintRadius" : Радиус вокруг "поврежденного" пикселя, указывающий область взятия значений при подрисовывании/восстановлении данного пикселя. # Большие значения предотвращают подрисовывание в неправильном направлении, но также и создают больше размытости. # По умолчанию: 8.0. # # float "InpaintSharpness" : Более высокие значения могут предотвратить размывание, вызванное высокими значениями InpaintRadius. # По умолчанию: 50.0. # # float "InpaintPreBlur" : Стандартное отклонение размытости, которое применяется к изображению перед вычислением структурного тензора. Более высокие # значения помогают соединению изофот (кривых равной освещённости), которые были вырезаны областью подрисовки, но также и # увеличивают нагрузку на процессор. PreBlur=0.0 отключает предварительное размывание. # По умолчанию: 8.0. # # float "InpaintPostBlur" : Стандартное отклонение размытости, которое применяется к структурным тензорам перед их использованием для определения # направления подрисовки. Более высокие значения помогают собрать больше информации о направлении, когда доступно только # немного валидных пикселей, но при этом также увеличивается нагрузка на процессор. # По умолчанию: 5.0. # # bool "lmask" : Применить постобработку через маску восстановления (LogoInpaint). По умолчанию в коде строка, использующая данный параметр, # вообще закомментирована. Поэтому убрал ее и из списка параметров функции. # # int "PPMode" : Режим постобработки, применяемый для уменьшения повреждений, оставшихся после удаления логотипа. # Значения от 0 до 3. 0 - отключено. # По умолчанию: 2. # # bool "debug" : Включает режим отладки для помощи настройки параметров функции. #______________________________________________________________________________________ # ФУНКЦИЯ : #______________________________________________________________________________________ function rm_logo( clip clp, string "logomask", string "loc", float "PAR", string "mode", int "Exmode", float "percent",int "deblendfalloff",\ int "AlphaToRepair", float "RepairRadiusPre", float "RepairRadiusPost", float "InpaintRadius", float "InpaintSharpness",\ float "InpaintPreBlur", float "InpaintPostBlur", int "PPMode", bool "debug" ) { x = width (clp) y = height (clp) logomask = default( logomask, "" ) loc = default( loc, "" ) PAR = default( par, 1.0 ) mode = default( mode, "inpaint" ) ExMode = default( Exmode, 0 ) percent = default( percent, 25.0 ) deblendfalloff = default( deblendfalloff, 5 ) AlphaToRepair = default( AlphaToRepair, 55 ) RepairRadiusPre = default( RepairRadiusPre, 1.0 ) RepairRadiusPost = default( RepairRadiusPost, 1.0 ) InpaintRadius = default( InpaintRadius, 8.0 ) InpaintSharpness = default( InpaintSharpness, 50.0 ) InpaintPreBlur = default( InpaintPreBlur, 8.0 ) InpaintPostBlur = default( InpaintPostBlur, 5.0 ) #~ lmask = default( lmask, false ) PPMode = default( PPMode, 2 ) debug = default( debug, false ) RGB = isRGB( clp ) RGB32 = isRGB32( clp ) RGB24 = isRGB24( clp ) YUY2 = isYUY2(clp) cropval = (StrLen(loc) != 2 ) ? true : false bugloc = (loc == "" ) ? true : false par = ( par!= 1.0 ) ? float( clp_height ) / float( clp_width ) * par : 1.0 percent = ( percent <= 0.0) ? 25.0 : (percent > 100) ? 100.0 : percent # Проверка входных параметров на валидность assert ( findstr(loc," ") == 0 , """Space character is not allowed in string "loc".""") assert ( logomask != "" , """You have to define a logomask (string "mymask")""") assert ( bugloc == false , """You must define "Loc".""") assert ( mode == "both" || mode == "inpaint" || mode == "deblend", "Specified mode doesn't exist.") assert ( ExMode == 0 || ExMode == 1 || ExMode == 2, "Specified ExMode mode doesn't exist.") # Определяем координаты обрезки loc = UCase( loc ) null = (cropval == false ) ? eval(""" a = (Rightstr(loc,1) == "L" || Rightstr(loc,1) == "1") ? 0 : (Rightstr(loc,1) == "C" || Rightstr(loc,1) == "2") ? round((x*1/6))*2 : round((x*1/3))*2 b = (leftstr(loc,1) == "T" || leftstr(loc,1) == "X") ? 0 : (leftstr(loc,1) == "M" || leftstr(loc,1) == "Y") ? round((y*1/6))*2 : round((y*1/3))*2 c = (Rightstr(loc,1) == "R" || Rightstr(loc,1) == "3") ? 0 : (Rightstr(loc,1) == "C" || Rightstr(loc,1) == "2") ? -round((x*1/6))*2 : -round((x*1/3))*2 d = (leftstr(loc,1) == "B" || leftstr(loc,1) == "Z") ? 0 : (leftstr(loc,1) == "M" || leftstr(loc,1) == "Y") ? -round((y*1/6))*2 : -round((y*1/3))*2 """) : eval(""" long = StrLen(loc) posvirg1 = findstr(loc, ",") posvirg2 = findstr(rightstr(loc,long-posvirg1), ",") posvirg2 = posvirg2+posvirg1 posvirg3 = findstr(rightstr(loc,long-posvirg2), ",") posvirg3 = posvirg3 + posvirg2 a = int(value(leftstr(loc,posvirg1-1))) b = int(value(leftstr(rightstr(loc,long-posvirg1),posvirg2-posvirg1-1))) c = int(value(leftstr(rightstr(loc,long-posvirg2),posvirg3-posvirg2-1))) d = int(value(rightstr(loc,long-posvirg3))) """) cropped = clp.crop(a,b,c,d) input = RGB24 ? cropped : cropped.converttoRGB24() analyse = percent != 100 ? cropped.SelectRangeEvery( round(100.0/percent), 1 ) : cropped # Анализируем весь клип или процент он него? # Очищаем (сглаживаем) анализируемый клип для улучшения результатов #~ analyse = (IsYV12(analyse)) ? analyse : analyse.ConvertToYV12 #~ analyse = analyse.TTempSmoothF(maxr=2,lthresh=256,cthresh=256,scthresh=255).converttoRGB24() # Во многих случаях подглючивает, поэтому отключил # Читаем файл нашей маски, обрезаем ее и подготавливаем logo_mask = imagesource(logomask,0,0).crop(a,b,c,d) logo_mask = logo_mask.ConvertToYV12() logo_mask = logo_mask.DistanceFunction(255/deblendfalloff, par).Greyscale() # Создаем Deblend маску, которая используется при смешивании "восстановленного" участка с оригиналом DeblendMask = logo_mask.DistanceFunction( 255.0 / DeblendFalloff, PixelAspect=par ) # Отделение каталога и имени логотипа для сохранения уникального ebmp-файла ID = logomask.revstr().findstr("\") - 1 ID = ID <= 0 ? logomask : rightstr(logomask, ID) # имя и расширение ID = LeftStr(ID, StrLen(ID) - ID.revstr().findstr(".")) # только имя ID = ID + + "_" + loc + "_" + string(percent) + "_" # Здесь мы производим анализ, необходимый для последующего создания карты цветов и карты альфа-канала Logo = eval("""try { # Анализ является медленным, поэтому мы делаем его только один раз с проверкой, существует ли он imagesource(ID + "%06d.ebmp",0,0) } catch( dummy ) { # здесь мы выполняем анализ логотипа, т.к. он еще не существует analyse.AnalyzeLogo(logo_mask).trim(0,-1) imagewriter(ID,0,1,"ebmp") }""") # Карта цветов является верхней половиной результата анализа, альфа-канал - нижней половиной Logo = Logo.AssumeFPS(analyse.FrameRate) LogoColor = Logo.Crop(0,0,0,Logo.Height/2) LogoAlpha = Logo.Crop(0,Logo.Height/2,0,0).ConvertToYV12() LogoInpaint = LogoAlpha.Invert.mt_lut(expr="x " + string(255-AlphaToRepair) + " < 255 0 ?").mt_expand.mt_inflate().Greyscale() LogoInpaint = RepairRadiusPre > 0.1 ? LogoInpaint.DistanceFunction( 84.0 / RepairRadiusPre, PixelAspect=par ) : LogoInpaint # InpaintLogo и DeblendLogo, основанные на пользоват. параметрах repaired = (mode == "both") ? input.DeblendLogo(LogoColor,LogoAlpha).InpaintLogo(LogoInpaint, Radius=InpaintRadius, Sharpness=InpaintSharpness, \ PreBlur=InpaintPreBlur, PostBlur=InpaintPostBlur, PixelAspect=par) \ : (mode == "inpaint") ? input.InpaintLogo(LogoInpaint, Radius=InpaintRadius, Sharpness=InpaintSharpness, PreBlur=InpaintPreBlur, PostBlur=InpaintPostBlur, PixelAspect=par) \ : input.DeblendLogo(logoColor,logoAlpha) repaired = (Exmode == 1) ? repaired.converttorgb32.ExInpaint(LogoInpaint.converttorgb32, color=$ffffff, xsize=8, ysize=8, radius=0) \ : (EXmode == 2) ? input.converttorgb32.ExInpaint(LogoInpaint.converttorgb32, color=$ffffff, xsize=8, ysize=8, radius=0) \ : repaired repout = Layer(input.ConvertToRGB32, repaired.ConvertToRGB32.Mask(DeblendMask.ConvertToRGB32())) PostMask = LogoAlpha.Invert.mt_lut(expr="x " + string(255-AlphaToRepair) + " < 255 0 ?").mt_expand.mt_inflate().Greyscale() PostMask = PostMask.DistanceFunction( 64.0 / RepairRadiusPost, par ) #~ PostMask = (PPMode > 0 && lmask) ? LogoInpaint.DistanceFunction( 512.0 / DeblendFalloff, PixelAspect=par ) : blankclip(repout,color=$000000) # постобработка результатов post = ( PPMode == 1 ) ? repout.converttoyv12().minblur(1,uv=3).medianblur(3,0,0).removegrain(11) \ : ( PPMode == 2 ) ? repout.converttoyv12().fft3dgpu(sigma=16,sigma2=12,sigma3=8,sigma4=4,bt=3,bw=16,bh=16,ow=8,oh=8,plane=4) \ : ( PPMode == 3 ) ? repout.converttoyv12().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) \ : repout output = ( PPMode > 0 ) ? mt_merge(repout.converttoyv12(), post, PostMask) : repout aa = debug ? stackhorizontal(cropped.ConvertToYV12.subtitle("source"),repout.ConvertToYV12.subtitle("repaired out"),output.ConvertToYV12.subtitle("repaired pp out")) : nop bb = debug ? stackhorizontal(cropped.ConvertToYV12.BlankClip().subtitle("none"),repaired.ConvertToYV12.subtitle("repaired"),post.ConvertToYV12.subtitle("repaired pp")) : nop cc = debug ? stackhorizontal(logocolor.ConvertToYV12.subtitle("Logo Color"),logoalpha.ConvertToYV12.subtitle("Logo Alpha"),LogoInpaint.ConvertToYV12.subtitle("Logo Inpaint")) : nop dd = debug ? stackhorizontal(logo_mask.ConvertToYV12.subtitle("Logo Mask"),deblendmask.ConvertToYV12.subtitle("Deblend Mask"),PostMask.ConvertToYV12.subtitle("Post Mask")) : nop # Вставка восстановленного участка обратно в исходное видео output = RGB ? ( RGB24 ? output : output.converttoRGB32() ) : ( YUY2 ? fullclip.converttoYUY2() : fullclip.converttoYV12() ) final = clp.overlay(output,a, b) RETURN debug ? stackvertical(aa,bb,cc,dd) : final } function InpaintAssist ( clip clp, string "loc", string "alignment") { loc = default (loc, "") x = width (clp) y = height (clp) alignment = default (alignment, "top") align = (alignment == "top") ? 8 : (alignment == "center") ? 5 : (alignment == "bottom") ? 2 :8 framecount = framecount(clp) # I "Loc" parameter is not specified, split the clip in 9 parts et show crop value for each part # ============================================================================================== loc == "" ? Eval(""" white = blankclip(width=round(x/3),height=round(y/3),color=$FFFFFF,length=framecount) black = blankclip(width=round(x/3),height=round(y/3),color=$000000,length=framecount) l1 = stackhorizontal(white,black,white) l2 = stackhorizontal(black,white,black) background = stackvertical(l1,l2,l1).converttoRGB32.spline36resize(x,y) clp = clp.converttoRGB32 a1 = string(0) a2 = string(round((x*1/6))*2) a3 = string(round((x*1/3))*2) b1 = string(0) b2 = string(round((y*1/6))*2) b3 = string(round((y*1/3))*2) ca1 = string(-round((x*1/3))*2) ca2 = string(-round((x*1/6))*2) ca3 = string(0) d1 = string(-round((y*1/3))*2) d2 = string(-round((y*1/6))*2) d3 = string(0) c1 = clp.crop(0 , 0 , -round((x*1/3))*2, -round((y*1/3))*2) \ .subtitle("TL (" + a1 + "," + b1 + "," + ca1 + "," + d1+ ")",align=8) c2 = clp.crop(round((x*1/6))*2, 0 , -round((x*1/6))*2, -round((y*1/3))*2) \ .subtitle("TC (" + a2 + "," + b1 + "," + ca2 + "," + d1+ ")",align=8) c3 = clp.crop(round((x*1/3))*2, 0 , 0 , -round((y*1/3))*2) \ .subtitle("TR (" + a3 + "," + b1 + "," + ca3 + "," + d1+ ")",align=8) c4 = clp.crop(0 , round((y*1/6))*2 , -round((x*1/3))*2, -round((y*1/6))*2) \ .subtitle("ML (" + a1 + "," + b2 + "," + ca1 + "," + d2+ ")",align=8) c5 = clp.crop(round((x*1/6))*2, round((y*1/6))*2 , -round((x*1/6))*2, -round((y*1/6))*2) \ .subtitle("MC (" + a2 + "," + b2 + "," + ca2 + "," + d2+ ")",align=8) c6 = clp.crop(round((x*1/3))*2, round((y*1/6))*2 , 0 , -round((y*1/6))*2) \ .subtitle("MR (" + a3 + "," + b2 + "," + ca3 + "," + d2+ ")",align=8) c7 = clp.crop(0 , round((y*1/3))*2, -round((x*1/3))*2, 0) \ .subtitle("BL (" + a1 + "," + b3 + "," + ca1 + "," + d3+ ")",align=8) c8 = clp.crop(round((x*1/6))*2, round((y*1/3))*2, -round((x*1/6))*2, 0) \ .subtitle("BC (" + a2 + "," + b3 + "," + ca2 + "," + d3+ ")",align=8) c9 = clp.crop(round((x*1/3))*2, round((y*1/3))*2, 0 , 0) \ .subtitle("BR (" + a3 + "," + b3 + "," + ca3 + "," + d3+ ")",align=8) output = stackvertical(stackhorizontal(c1,c2,c3), stackhorizontal(c4,c5,c6), stackhorizontal(c7,c8,c9)) output = output.spline36resize(x,y) clip1 = background.layer(output.mask(blankclip(output,color=$DEDEDE))) """) : nop # If "Loc" is specified, hightlight the part choosen by user # ========================================================== (strlen(loc) == 2) ? Eval(""" a = (Rightstr(loc,1) == "L" || Rightstr(loc,1) == "1") ? 0 : (Rightstr(loc,1) == "C" || Rightstr(loc,1) == "2") ? round((x*1/6))*2 : round((x*1/3))*2 b = (leftstr(loc,1) == "T" || leftstr(loc,1) == "X") ? 0 : (leftstr(loc,1) == "M" || leftstr(loc,1) == "Y") ? round((y*1/6))*2 : round((y*1/3))*2 c = (Rightstr(loc,1) == "R" || Rightstr(loc,1) == "3") ? 0 : (Rightstr(loc,1) == "C" || Rightstr(loc,1) == "2") ? -round((x*1/6))*2 : -round((x*1/3))*2 d = (leftstr(loc,1) == "B" || leftstr(loc,1) == "Z") ? 0 : (leftstr(loc,1) == "M" || leftstr(loc,1) == "Y") ? -round((y*1/6))*2 : -round((y*1/3))*2 """) : (strlen(loc) != 0) ? eval(""" long = StrLen(loc) posvirg1 = findstr(loc, ",") posvirg2 = findstr(rightstr(loc,long-posvirg1), ",") posvirg2 = posvirg2+posvirg1 posvirg3 = findstr(rightstr(loc,long-posvirg2), ",") posvirg3 = posvirg3 + posvirg2 a = int(value(leftstr(loc,posvirg1-1))) b = int(value(leftstr(rightstr(loc,long-posvirg1),posvirg2-posvirg1-1))) c = int(value(leftstr(rightstr(loc,long-posvirg2),posvirg3-posvirg2-1))) d = int(value(rightstr(loc,long-posvirg3))) """) : nop (loc != "") ? eval(""" hightlight = blankclip(width=x-a+c,height=y-b+d,color=$96ff2d).converttoRGB32 clip2 = clp.converttoRGB32.layer(hightlight.Mask(blankclip(hightlight, color=$444444)),x=a,y=b) return clip2.subtitle("Crop value : " + string(a) +", " +string(b) +", " +string(c) +", " +string(d), align=align, size=20 ) """) : clip1 return last } |