View Full Version : repair bad deinterlacing
hrgiger6
29th June 2014, 05:19
every so often I come across an encode that has been deinterlaced with the wrong field order into a progressive file. I have heard that the fields can be recovered and the file repaired, can someone do this? what plugins and script would do the job here? (if it can be done at all.) before I started using avisynth I would have said it was impossible to fix, but now I am not so sure.
http://oi60.tinypic.com/30vfbj8.jpg
here is the whole 4 min. file recorded from a south american tv broadcast in 83, and unfortunately this is by far the best source of this available anywhere. should be a quick dl just click the very top link where it says "Download: bad deinterlacing.rar."
http://speedy.sh/NNf5B/bad-deinterlacing.rar
Evil_Burrito
29th June 2014, 08:19
If you want to take the time it is definitely possible to improve the video, but in my opinion I don't think it is possible to completely "fix" it. Because your source has problems on top of problems. For many of the problems you could use mvtools2. Read the documentation (thoroughly if it is your first time) and at the end there are some examples scripts that could be of help.
Like
To recreate bad frames by interpolation with MFlowInter:
super = MSuper()
backward_vectors = MAnalyse(super, isb = true, delta=2)
forward_vectors = MAnalyse(super, isb = false, delta=2)
inter = MFlowInter(super, backward_vectors, forward_vectors, time=50, ml=70)
# Assume bad frames are 50 and 60
trim(0,49) ++ inter.trim(49,-1) \
++ trim(51,59) ++ inter.trim(59,-1) ++ trim(61,0)
I did some quick work so you can see some possible results. The pictures are attached (note these were done at 3 am and I am tired).
Evil_Burrito
29th June 2014, 21:46
I wanted to point out that the worst issue (in my opinion) is the poor vhs capturing. It has lots of scenes that are completely missing frames/fields (plus jitter and vcr lines). Which are not necessarily due to bad deinterlacing. Yes, it looks similar to interlace artifacts (combing), but I don't think they are, because the lines are too thick. Although anything is possible, it could have been badly de-interlaced by hardware before it was even captured. I can't know unless I had more details about the source and the methods used.
You should check out these links to learn more from people who are more experienced than me.
http://forum.videohelp.com/threads/334613-Filters-for-restoring-old-VHS
http://www.digitalfaq.com/forum/video-restore/2251-tbc-time-base.html
ChiDragon
30th June 2014, 02:01
Which are not necessarily due to bad deinterlacing. Yes, it looks similar to interlace artifacts (combing), but I don't think they are, because the lines are too thick.
Artifacts like this are caused by taking an interlaced source and resizing down with a scaler that expects progressive input.
johnmeyer
30th June 2014, 04:08
I think ChiDragon is correct about the cause. I was certain that Didée posted a script, back around 2009-2010, that was able to make an improvement on this sort of video, but after 30 minutes of searching, I can no longer find the post. If he is lurking, maybe he can reinvent his solution.
I thought I had archived it in my local script repository, but I can't find it here either. That's a bummer, because clients sometimes send me video that looks like this, and I am expected to fix it.
2Bdecided
2nd July 2014, 14:14
Are you thinking of this?
http://forum.doom9.org/showthread.php?t=162599
Maybe not, because that was resized telecine, and the solution Didée posted was half a joke.
I don't remember a "proper" fix for this kind of thing, and I've been looking for a long time!
Even the kind of improvement that you assume might be possible hasn't been achieved yet AFAICT.
Cheers,
David.
Evil_Burrito
2nd July 2014, 17:37
Thanks ChiDragon for the knowledge. You think it was resized while interlaced? I will keep it in my brain backup vault if by unlucky chance I see video like this again.
hrgiger6, have you made any progress? Or did you just want the forum to do all the work for you :rolleyes:
johnmeyer
2nd July 2014, 18:43
Are you thinking of this?
http://forum.doom9.org/showthread.php?t=162599
Maybe not, because that was resized telecine, and the solution Didée posted was half a joke.That was actually a response to a thread I started, and Didée's code was no joke: it worked perfectly. Also, the problems I was facing in that thread were not from improper re-sizing.
The thread I was thinking of -- and which I think may have been removed for some reason -- concerned exactly the problem shown in the OP's picture, and which happens when you re-size interlaced video without first de-interlacing. I remember the thread well because I posted a "solution" that I had used when helping a collector restore the entire 57-episode Johnny Cash show. My idea did make the video look better, but when I posted my code, Didée and other pointed out that it was the wrong fix because I didn't correctly identify the problem.
I then remember -- perhaps incorrectly -- that Didée posted some code that did a much better job of undoing the mess.
But since I can't find the post, my ancient memory cells are probably playing tricks on me.
johnmeyer
2nd July 2014, 19:11
Ah ... when I wrote "Johnny Cash" in the last post, I realized I could use that to find the old post. I found it right away, and I now realize why it was so hard to find: it is in the middle of the huge QTGMC thread.
Here is a link to the point in that long thread where Sadie posted a clip (the link is now dead) that showed problems similar to what is shown in the single frame in the OP's post:
Bad Interlace Resizing (http://forum.doom9.org/showthread.php?p=1492396#post1492396)
Several posts later, Didée provides a great example, using AVISynth code, of how that video got corrupted. Many posts after that, I posted my "solution" to help fix the problem:
Suggested "fix" (http://forum.doom9.org/showthread.php?p=1492613#post1492613)
In the next post following mine, Didée immediately corrects my wrong thinking as to what caused the problem, but then states:
Your solution is good - since it's close to impossible to (sufficiently) revert the interlace-damage, keeping just one field & discarding the other is the next best thing you can only do. But the problem analysis definitely needed to be corrected.
So, I guess the OP could try the code I posted in that old thread. It might help a little. It did help with the video I was dealing with, but as others pointed out in that old thread, the video will never look great, and a lot of resolution will be lost.
BTW, if you keep reading the thread, you'll see the remains of an unfortunate exchange between Didée and me. It resulted from a misunderstanding when we were both posting at the exact same moment, and one of us went back and edited a post after the other had already read the original version. We ended up responding to things that were no longer there. When we realize what had happened, we kissed and made up ...
I have complete and total respect for Didée.
hrgiger6
3rd July 2014, 09:12
hrgiger6, have you made any progress? Or did you just want the forum to do all the work for you :rolleyes:
sorry, I am absolutely still working on it and I will post some results in a minute.
thanks EB for taking the time to help me on this, and everyone else here as well.
hrgiger6
3rd July 2014, 12:20
well, I can't seem to see any difference using any of the scripts suggested. can anyone else?
the only way I see that this could be sort of repaired is to be able to define each field by its actual lines of resolution (e.g. 1-10, 21-30... for upper 11-20, 31-40... for lower), separate the fields and then interpolate the missing lines for each field back in creating progressive frames, resize, and re-interlace properly.
can this be done?
johnmeyer
3rd July 2014, 19:16
I had a few minutes this morning and looked carefully at the clip, field-by-field, rather than frame-by-frame. It is very useful to look at the fields during the momentary flashes caused by the dramatic stage lighting. What happens is that you end up with portions of the previous field, as seen here:
https://i.imgur.com/OG3jc7P.jpg
The dark stripes are from the previous even field, before the flash happened.
Looking at this, it might be possible to take each even field and split it spatially into horizontal stripes. Then you could combine half the stripes from the current even field, and the complementary half of the stripes from the previous even field, and you might then have something that looks better. You'd then do the same thing with the odd fields, and then re-weave to get them back together as a frame.
I think something like this may have already been done. My starting point would be to use some of StanlessS' code.
johnmeyer
3rd July 2014, 19:41
P.S. I think your best bet is to try to get a better copy of that 1983 Kiss "Creatures of the Night" concert in Rio. There are dozens of versions on YouTube and elsewhere, none of which seem to have this problem. You could just watch those and be done with it.
Also, unless you are absolutely in love with that particular concert, you can find dozens and dozens of clips from the rest of that tour, and create your own concert. Based on a quick, casual, perusal of clips, they used the same stage set and costumes throughout.
hrgiger6
4th July 2014, 07:22
I had a few minutes this morning and looked carefully at the clip, field-by-field, rather than frame-by-frame. It is very useful to look at the fields during the momentary flashes caused by the dramatic stage lighting. What happens is that you end up with portions of the previous field, as seen here:
http://i177.photobucket.com/albums/w208/johnmeyer/Flash_zps4975c91f.jpg
The dark stripes are from the previous even field, before the flash happened.
Looking at this, it might be possible to take each even field and split it spatially into horizontal stripes. Then you could combine half the stripes from the current even field, and the complementary half of the stripes from the previous even field, and you might then have something that looks better. You'd then do the same thing with the odd fields, and then re-weave to get them back together as a frame.
I think something like this may have already been done. My starting point would be to use some of StanlessS' code.
right, exactly. I did this already with PS and is what I alluded to previously when I said could we define each field as being lines 1-10,21-30,41-50 etc. as being the upper field for example. if we could get this divided into fields properly, surely we could use some sort of smart deinterlacing on steroids that would treat the huge bars jutting out similar to the 'combing' on typical interlaced footage.
P.S. I think your best bet is to try to get a better copy of that 1983 Kiss "Creatures of the Night" concert in Rio. There are dozens of versions on YouTube and elsewhere, none of which seem to have this problem. You could just watch those and be done with it.
Also, unless you are absolutely in love with that particular concert, you can find dozens and dozens of clips from the rest of that tour, and create your own concert. Based on a quick, casual, perusal of clips, they used the same stage set and costumes throughout.
I have several very nice copies like the ones you speak of, but they are incomplete and definitely do not include the song in this clip 'God of Thunder.' there are at least 2 seemingly complete concerts on youtube but if you look at this clip http://www.youtube.com/watch?v=OMW8tGzeEA8@ 41:15 you can see why I am interested in this short clip, despite its major flaws. I have not been able to find a better quality copy of the complete concert, only the same edited show that everyone else has, in multiple versions.
only other source of footage from full concert
http://oi61.tinypic.com/35hleu1.jpg
the clip I posted above with the discussed problems
http://oi60.tinypic.com/nmxe35.jpg
I have tons of Kiss shows so that's not the problem, this is exceedingly rare footage in almost unspeakable quality except for those spots that cause all the trouble. if I can find a decent tranfer of that complete show, I'll just rotoscope those bars away using the other footage in the trouble spots of the affected frames. I don't think I will find the rare footage in a usable quality and the youtube quality is too poor to even consider.
if somehow avisynth could treat those huge bars in motion scenes as just huge interlacing artifacts maybe it could blend them somewhat? but I guess it can't do that because there are no fields that correspond to the bars anymore. I guess I can just redo each frame that has the bars by hand in PS, I was hoping to avoid that though.
btw this concert really is that special, featuring Vinnie Vincent on lead guitar and 3rd to the last concert with make-up (before re-uniting in the 90's) in front of 137,000 fans.
johnmeyer
4th July 2014, 19:09
OK, I wrote some "proof of concept" code. It is so crude that I hesitate to post it. However, it shows the basic three steps of the idea:
1. Create a clip for each even band, and a clip for each odd band.
2. When creating the odd bands, use a motion estimated clip that is halfway between the current band and the previous band.
3. Reassemble the odd and even clips.
Here is a clip of comparing the original (the top part of the stackhorizontal image) with the clip that results from what I describe above:
https://i.imgur.com/F447B95.jpg
If you look at the portion of the two clips pointed to by the red arrows, the mic stand is now straight.
My approach is proof of concept only. Besides being a brute force approach (there must be a more compact, elegant way to code this), there are two major issues that must be solved:
1. The edges of the horizontal bands do not mesh smoothly. I either need to do a better job figuring out the exact scan line to use for each band, or I need to figure out how to recombine them with a little blur on the edges. That is beyond what I could figure out to do in the short time I spent on this.
2. The original clip should probably be used at scene changes, because this code actually introduces bands at each scene change, rather than removing them.
Here is the code (please keep your giggling to yourself):
source = AVISource("E:\fs.avi").KillAudio()
prev = selectevery(source,1,-1)
super=MSuper(prev,pel=2)
vfe=manalyse(super,truemotion=true,isb=false,delta=1)
vbe=manalyse(super,truemotion=true,isb=true,delta=1)
prev_est = mflowinter(prev,super,vbe,vfe,time=50)
clip1 = crop(source,0,0,480,9)
clip2 = crop(prev_est,0,9,480,18)
clip3 = crop(source,0,27,480,18)
clip4 = crop(prev_est,0,45,480,18)
clip5 = crop(source,0,63,480,18)
clip6 = crop(prev_est,0,81,480,18)
clip7 = crop(source,0,99,480,18)
clip8 = crop(prev_est,0,117,480,18)
clip9 = crop(source,0,135,480,18)
clip10 = crop(prev_est,0,153,480,18)
clip11 = crop(source,0,171,480,18)
clip12 = crop(prev_est,0,189,480,18)
clip13 = crop(source,0,207,480,18)
clip14 = crop(prev_est,0,225,480,18)
clip15 = crop(source,0,243,480,18)
clip16 = crop(prev_est,0,261,480,18)
clip17 = crop(source,0,279,480,18)
clip18 = crop(prev_est,0,297,480,18)
clip19 = crop(source,0,315,480,18)
clip20 = crop(prev_est,0,333,480,18)
test = BlankClip(length=FrameCount(source), width=480, height=360, fps=29.97, color=$000000).converttoyuy2()
test1 = overlay(test ,clip1,0,0)
test1 = overlay(test1,clip2,0,9)
test1 = overlay(test1,clip3,0,27)
test1 = overlay(test1,clip4,0,45)
test1 = overlay(test1,clip5,0,63)
test1 = overlay(test1,clip6,0,81)
test1 = overlay(test1,clip7,0,99)
test1 = overlay(test1,clip8,0,117)
test1 = overlay(test1,clip9,0,135)
test1 = overlay(test1,clip10,0,153)
test1 = overlay(test1,clip11,0,171)
test1 = overlay(test1,clip12,0,189)
test1 = overlay(test1,clip13,0,207)
test1 = overlay(test1,clip14,0,225)
test1 = overlay(test1,clip15,0,243)
test1 = overlay(test1,clip16,0,261)
test1 = overlay(test1,clip17,0,279)
test1 = overlay(test1,clip18,0,297)
test1 = overlay(test1,clip19,0,315)
test1 = overlay(test1,clip20,0,333)
stackvertical(source,test1)
#return test1
Hopefully someone else (or the OP) can figure out how to solve these two problems. With a little help, I think this approach can solve the problems with this particular clip.
hrgiger6
5th July 2014, 04:16
WOW now we are really getting somewhere. last night I divided the video into fields using a mask I made in PS with bars 18 pxls tall to just black the other field out or turn it red for delogo (abysmal.) I just had no idea how to proceed. what you have done looks like possibly we could put another mask over the fine stripes and use a delogo (I haven't done anything like that with avisynth myself) or something to interpolate those fine glitches. of course you or someone else will have a better idea but it is definitely doable.
I really appreciate your hard work on this.
as one of the other posters said, this really is a problem that shows up fairly frequently, if we can figure out how to deal with this it will be a major accomplishment.
hrgiger6
5th July 2014, 08:05
I ran your script and it works amazingly well except in very fast motion areas. I made a repair mask for delogo which has 3 px red lines centered every 18 px. it was able to somewhat interpolate those areas with the very visible horizontal lines giving an improved appearance. however I am certain that avisynth would do a far better job but I am unfamiliar as to what script/plugins would be best to use.
test comparison of original file, your script and script w/ delogo applied
http://oi57.tinypic.com/2nh2hwg.jpg
johnmeyer
5th July 2014, 22:03
Hmmm ... yes, my approach breaks down with vertical motion. Works very well with horizontal motion (as you show in the first of the two frames of the singer).
I don't know if there is a solution ...
StainlessS
5th July 2014, 22:25
Be aware if anyone tries AMSS0815's AvsInpaint via Reuf Toc's InPaintFunc.avs, it will be broken now under v2.6, due to a bug fix in
Levels(RGB), where Reuf Toc relied on the bug to create some kind of mask.
http://forum.doom9.org/showthread.php?p=1479855#post1479855
johnmeyer
5th July 2014, 23:00
OK, this is an idea for how to make an improvement on my original attempt.
I think the idea of using motion estimation is still useful, but my original code (in my earlier post) applies the motion estimation to the entire clip. This doesn't work when there is vertical motion because the bands are affected differently when they move up or down into the area previously occupied by bands from another part of the image.
Therefore, a possible better solution would be to first create two clips using the "macro fields" that were created by the improper resizing. Macro fields?? OK, to define my made-up term, "macro fields" refers to the alternating 18-line horizontal blocks of pixels. The idea would be to do something similar to a "separatefields", but do this instead on each group of 18 horizontal lines. Then, assemble the odd horizontal groups of 18 lines into one "field" and the even blocks into a second "field." The motion estimation would then be applied to just the odd fields. Finally, the odd and even "fields" would be "weaved" back together, but in 18-line chunks.
This is similar to:
separatefields()
even = selecteven()
odd = selectodd()
super=MSuper(even,pel=2)
vfe=manalyse(super,truemotion=true,isb=false,delta=1)
vbe=manalyse(super,truemotion=true,isb=true,delta=1)
neweven = mflowinter(even,super,vbe,vfe,time=50)
interleave(neweven,odd)
weave()
except that the separate, select, interleave, and weave statements would work on groups of 18 lines instead of one line at a time.
I think -- but am not sure -- that doing it this way would let the motion estimation work its magic in both the x and y directions without being confused by the moving, hard discontinuities every 18 pixels.
I'm not quite sure how to code this ...
colours
6th July 2014, 06:42
johnmeyer: You could use SeparateRows/WeaveRows to perform "macrofield" separation.
source
SeparateRows(36)
WeaveRows(18)
#clip is now separated into macrofields; insert macrofield filtering here
SeparateRows(18)
WeaveRows(36)
#clip is restored
(This doesn't sound very useful, but I haven't been following the rest of the thread too closely.)
hrgiger6
6th July 2014, 06:47
John now that is what I have been talking about. how to somehow define the 'macro fields' so they could be deinterlaced like normal fields. you are actually doing it though, figuring out how. I guess this technique (script) will eventually be called "Macro-deinterlacer."
johnmeyer
6th July 2014, 20:24
SeparateRows() doesn't appear to let you specify contiguous rows. Thus, SeparateRows(36) only takes one row at a time, creating the first frame from rows 0, 35, 71, ... and the next frame from 1, 36, 72 ..., etc. The function I would need to create would create the first frame from rows 0, 1, 2, 3, 4, ... 17, and the next frame from the next 18 rows, etc.
It seems like someone must have coded this at some point. I'll keep poking around.
Gavino
6th July 2014, 21:47
But if you follow SeparateRows(36) by WeaveRows(18) - as in colours' script above - you will get what you want.
johnmeyer
6th July 2014, 21:50
The following code gets a step closer to a solution. It is a brute-force implementation of what I described above. The motion estimation now produces the correct result regardless of whether the motion is horizontal or vertical. This is the result, using frame 424, the same frame the OP used in his earlier post:
https://i.imgur.com/E1EEGGH.jpg
Once again, the two remaining items that need to be solved are to use the original frame at scene changes (this is trivial to do); and figure out how to blend the alternating rows in order to get rid of the horizontal lines. Part of this problem may be caused by incorrect coding on my part, but I think it is simply caused by the original problem (the incorrect re-sizing of interlaced video), and therefore some smoothing or bluring along these horizontal lines may be needed.
There may also be some motion estimation parameters in MVTools2 that could be tuned in order to get better results. I played around a little with search= and blksize=, but didn't look at any of the other settings.
Here is the code:
# Create two half-height clips from groups of 18 rows of pixels.
# Shift one of these clips in time (using motion estimation) halfway between previous frame and current frame.
# Reassemble the two half height clips.
# First clip uses 9 rows from top and bottome of original clip, plus rows of height=18 in between.
#
# John H. Meyer - July 6, 2014
#
source = AVISource("E:\fs.avi").KillAudio()
clip1 = crop(source,0,0,480,9)
clip2 = crop(source,0,9,480,18)
clip3 = crop(source,0,27,480,18)
clip4 = crop(source,0,45,480,18)
clip5 = crop(source,0,63,480,18)
clip6 = crop(source,0,81,480,18)
clip7 = crop(source,0,99,480,18)
clip8 = crop(source,0,117,480,18)
clip9 = crop(source,0,135,480,18)
clip10 = crop(source,0,153,480,18)
clip11 = crop(source,0,171,480,18)
clip12 = crop(source,0,189,480,18)
clip13 = crop(source,0,207,480,18)
clip14 = crop(source,0,225,480,18)
clip15 = crop(source,0,243,480,18)
clip16 = crop(source,0,261,480,18)
clip17 = crop(source,0,279,480,18)
clip18 = crop(source,0,297,480,18)
clip19 = crop(source,0,315,480,18)
clip20 = crop(source,0,333,480,18)
clip21 = crop(source,0,351,480,9)
fram1 = BlankClip(length=FrameCount(source), width=480, height=180, fps=29.97, color=$000000).converttoyuy2()
fram1 = overlay(fram1,clip1,0,0)
fram1 = overlay(fram1,clip3,0,9)
fram1 = overlay(fram1,clip5,0,27)
fram1 = overlay(fram1,clip7,0,45)
fram1 = overlay(fram1,clip9,0,63)
fram1 = overlay(fram1,clip11,0,81)
fram1 = overlay(fram1,clip13,0,99)
fram1 = overlay(fram1,clip15,0,117)
fram1 = overlay(fram1,clip17,0,135)
fram1 = overlay(fram1,clip19,0,153)
fram1 = overlay(fram1,clip21,0,171)
fram2 = BlankClip(length=FrameCount(source), width=480, height=180, fps=29.97, color=$000000).converttoyuy2()
fram2 = overlay(fram2,clip2,0,0)
fram2 = overlay(fram2,clip4,0,18)
fram2 = overlay(fram2,clip6,0,36)
fram2 = overlay(fram2,clip8,0,54)
fram2 = overlay(fram2,clip10,0,72)
fram2 = overlay(fram2,clip12,0,90)
fram2 = overlay(fram2,clip14,0,108)
fram2 = overlay(fram2,clip16,0,126)
fram2 = overlay(fram2,clip18,0,144)
fram2 = overlay(fram2,clip20,0,162)
prev_fram2 = selectevery(fram2,1,-1)
super=MSuper(prev_fram2,pel=2)
vfe=manalyse(super,truemotion=true,isb=false,delta=1,blksize=4)
vbe=manalyse(super,truemotion=true,isb=true,delta=1,blksize=4)
fram2_est = mflowinter(prev_fram2,super,vbe,vfe,time=50)
new_clip = BlankClip(length=FrameCount(source), width=480, height=360, fps=29.97, color=$000000).converttoyuy2()
new_clip = overlay(new_clip,crop(fram1,0,0,480,18),0,0)
new_clip = overlay(new_clip,crop(fram2_est,0,0,480,18),0,9)
new_clip = overlay(new_clip,crop(fram1,0,9,480,18),0,27)
new_clip = overlay(new_clip,crop(fram2_est,0,18,480,18),0,45)
new_clip = overlay(new_clip,crop(fram1,0,27,480,18),0,63)
new_clip = overlay(new_clip,crop(fram2_est,0,36,480,18),0,81)
new_clip = overlay(new_clip,crop(fram1,0,45,480,18),0,99)
new_clip = overlay(new_clip,crop(fram2_est,0,54,480,18),0,117)
new_clip = overlay(new_clip,crop(fram1,0,63,480,18),0,135)
new_clip = overlay(new_clip,crop(fram2_est,0,72,480,18),0,153)
new_clip = overlay(new_clip,crop(fram1,0,81,480,18),0,171)
new_clip = overlay(new_clip,crop(fram2_est,0,90,480,18),0,189)
new_clip = overlay(new_clip,crop(fram1,0,99,480,18),0,207)
new_clip = overlay(new_clip,crop(fram2_est,0,108,480,18),0,225)
new_clip = overlay(new_clip,crop(fram1,0,117,480,18),0,243)
new_clip = overlay(new_clip,crop(fram2_est,0,126,480,18),0,261)
new_clip = overlay(new_clip,crop(fram1,0,135,480,18),0,279)
new_clip = overlay(new_clip,crop(fram2_est,0,144,480,18),0,297)
new_clip = overlay(new_clip,crop(fram1,0,153,480,18),0,315)
new_clip = overlay(new_clip,crop(fram2_est,0,162,480,18),0,333)
new_clip = overlay(new_clip,crop(fram1,0,171,480,9),0,351)
stackvertical(source,new_clip)
#return new_clip
johnmeyer
6th July 2014, 22:12
But if you follow SeparateRows(36) by WeaveRows(18) - as in colours' script above - you will get what you want.Hmm ... I think you're right. I could have used that to create the middle sections of my two clips (I still would need to create the first and last 9 rows separately).
johnmeyer
6th July 2014, 23:53
I made a few changes to the motion estimation and am getting much better results:
https://i.imgur.com/WuhVfRz.jpg
The horizontal lines are just as bad as before, but note that the alternating sections of his arm now line up quite nicely, without too many motion estimation errors.
If someone can help out by suggesting what is causing the horizontal lines, and can suggest how to get rid of them, I think I may be able to turn this into a function that can be used to fix video that has been screwed up by improper resizing of interlaced video. The result won't be perfect, but I think this may be good enough to make some people happy. :)
To get the result shown above, change the motion estimation code in my previous post to this:
prev_fram2 = selectevery(fram2,1,-1)
super=MSuper(prev_fram2,pel=2)
vfe=manalyse(super,truemotion=true,isb=false,delta=1,blksize=8,overlap=4,search=6)
vbe=manalyse(super,truemotion=true,isb=true,delta=1,blksize=8,overlap=4,search=6)
fram2_est = mflowinter(prev_fram2,super,vbe,vfe,time=50,blend=false,mL=100)
foxyshadis
7th July 2014, 01:09
The horizontal lines come from the borders of each band being blurred with the next band. Vinverse should help.
Also, since a low-resolution but less-trashed version of the concert exists, some interesting masking against each other to remove outliers might help. (Or it might be barking up an empty alley, I'm not sure.)
johnmeyer
7th July 2014, 01:42
I think there is something more going on than just having some residue from the original borders between the bands. I say this because if you look at the singer's chest in the last image I posted, you'll see some lines, even though there were no lines in the original because he wasn't moving much and therefore no resizing bands were introduced when this mess was first created.
I suspect that the problem is more subtle. Perhaps the original resizing didn't result in pixels being placed exactly on scan line boundaries. Therefore, there might be some sort of "1/2 pixel shift issue" that I can't quite get my head around.
If you look at the original image in my post above, and mentally shift the odd bands to the left, I don't think you'll see any line between the bands.
It is also possible that I made a mistake in my crop and overlay statements.
It would be really cool to get this working, because the topic of fixing badly resized interlaced video comes up fairly frequently, both here, and in other forums.
johnmeyer
7th July 2014, 20:00
I did a simple test: I captured a still frame from the original video (the same one I've been showing above) and put that into my photo editing program. I then moved the odd blocks to the left by just manually creating objects and then moving them. It quickly became obvious that the horizontal lines happen because the resizing created aliasing along the boundaries. Thus, it is not my code that is creating the lines.
Therefore, the solution will be to figure out how to feather the edges when doing the "overlay" at the end of my script when I assemble each frame back together.
StainlessS
7th July 2014, 20:14
Hi john. Mobile at moment.
Thanx for your reply on other thread, had I read the whole thing, i would not have needed ask question.
Have been following this thread, but you have ready done way better than i l, not sure that I can assist at all.
You already did way better than I would expect.
Good luck.
johnmeyer
7th July 2014, 21:31
Since the scene change logic is trivial to add, here's my current code which now uses the original frame at scene changes. This avoids introducing alternating bands at the scene changes.
I did try using delogo to get rid of the horizontal lines, but that didn't work well. What is needed is a similar blurring algorithm, but one that only gets applied to portions of the frame, based on a motion-estimated mask.
# Create two half-height clips from groups of 18 rows of pixels
# Shift one of these clips in time (using motion estimation) halfway between previous frame and current frame
# Then, reassemble the two half height clips.
# First clip uses 9 rows from top and bottome of original clip, plus rows of height=18 in between
#
# John H. Meyer - July 7, 2014
#
global blankthreshold=4
source = AVISource("E:\fs.avi").KillAudio()
global prev_source = selectevery(source, 1, -1)
clip1 = crop(source,0,0,480,9)
clip2 = crop(source,0,9,480,18)
clip3 = crop(source,0,27,480,18)
clip4 = crop(source,0,45,480,18)
clip5 = crop(source,0,63,480,18)
clip6 = crop(source,0,81,480,18)
clip7 = crop(source,0,99,480,18)
clip8 = crop(source,0,117,480,18)
clip9 = crop(source,0,135,480,18)
clip10 = crop(source,0,153,480,18)
clip11 = crop(source,0,171,480,18)
clip12 = crop(source,0,189,480,18)
clip13 = crop(source,0,207,480,18)
clip14 = crop(source,0,225,480,18)
clip15 = crop(source,0,243,480,18)
clip16 = crop(source,0,261,480,18)
clip17 = crop(source,0,279,480,18)
clip18 = crop(source,0,297,480,18)
clip19 = crop(source,0,315,480,18)
clip20 = crop(source,0,333,480,18)
clip21 = crop(source,0,351,480,9)
fram1 = BlankClip(length=FrameCount(source), width=480, height=180, fps=29.97, color=$000000).converttoyuy2()
fram1 = overlay(fram1,clip1,0,0)
fram1 = overlay(fram1,clip3,0,9)
fram1 = overlay(fram1,clip5,0,27)
fram1 = overlay(fram1,clip7,0,45)
fram1 = overlay(fram1,clip9,0,63)
fram1 = overlay(fram1,clip11,0,81)
fram1 = overlay(fram1,clip13,0,99)
fram1 = overlay(fram1,clip15,0,117)
fram1 = overlay(fram1,clip17,0,135)
fram1 = overlay(fram1,clip19,0,153)
fram1 = overlay(fram1,clip21,0,171)
fram2 = BlankClip(length=FrameCount(source), width=480, height=180, fps=29.97, color=$000000).converttoyuy2()
fram2 = overlay(fram2,clip2,0,0)
fram2 = overlay(fram2,clip4,0,18)
fram2 = overlay(fram2,clip6,0,36)
fram2 = overlay(fram2,clip8,0,54)
fram2 = overlay(fram2,clip10,0,72)
fram2 = overlay(fram2,clip12,0,90)
fram2 = overlay(fram2,clip14,0,108)
fram2 = overlay(fram2,clip16,0,126)
fram2 = overlay(fram2,clip18,0,144)
fram2 = overlay(fram2,clip20,0,162)
prev_fram2 = selectevery(fram2,1,-1)
super=MSuper(prev_fram2,pel=2)
vfe=manalyse(super,truemotion=true,isb=false,delta=1,blksize=8,overlap=4,search=6)
vbe=manalyse(super,truemotion=true,isb=true,delta=1,blksize=8,overlap=4,search=6)
fram2_est = mflowinter(prev_fram2,super,vbe,vfe,time=50,blend=false,mL=100)
new_clip = BlankClip(length=FrameCount(source), width=480, height=360, fps=29.97, color=$000000).converttoyuy2()
new_clip = overlay(new_clip,crop(fram1,0,0,480,18),0,0)
new_clip = overlay(new_clip,crop(fram2_est,0,0,480,18),0,9)
new_clip = overlay(new_clip,crop(fram1,0,9,480,18),0,27)
new_clip = overlay(new_clip,crop(fram2_est,0,18,480,18),0,45)
new_clip = overlay(new_clip,crop(fram1,0,27,480,18),0,63)
new_clip = overlay(new_clip,crop(fram2_est,0,36,480,18),0,81)
new_clip = overlay(new_clip,crop(fram1,0,45,480,18),0,99)
new_clip = overlay(new_clip,crop(fram2_est,0,54,480,18),0,117)
new_clip = overlay(new_clip,crop(fram1,0,63,480,18),0,135)
new_clip = overlay(new_clip,crop(fram2_est,0,72,480,18),0,153)
new_clip = overlay(new_clip,crop(fram1,0,81,480,18),0,171)
new_clip = overlay(new_clip,crop(fram2_est,0,90,480,18),0,189)
new_clip = overlay(new_clip,crop(fram1,0,99,480,18),0,207)
new_clip = overlay(new_clip,crop(fram2_est,0,108,480,18),0,225)
new_clip = overlay(new_clip,crop(fram1,0,117,480,18),0,243)
new_clip = overlay(new_clip,crop(fram2_est,0,126,480,18),0,261)
new_clip = overlay(new_clip,crop(fram1,0,135,480,18),0,279)
new_clip = overlay(new_clip,crop(fram2_est,0,144,480,18),0,297)
new_clip = overlay(new_clip,crop(fram1,0,153,480,18),0,315)
new_clip = overlay(new_clip,crop(fram2_est,0,162,480,18),0,333)
new_clip = overlay(new_clip,crop(fram1,0,171,480,9),0,351)
#Use original clip at scene changes
new_clip = ConditionalSelect (prev_source, "(YDifferenceToNext(prev_source.ConvertToYV12()) / YDifferenceFromPrevious(prev_source.ConvertToYV12())>blankthreshold)? 0 : 1" , source,new_clip,show=true)
stackhorizontal(source,new_clip)
#return new_clip
StainlessS
8th July 2014, 10:57
John, did you notice that fram1 seems to have light lines whereas fram2 has dark, sometimes other way around.
That dont tell me anything about origin, does it say anything to you. See frame 412 or 425
source = AVISource("BADYUY2.avi").KillAudio().ConvertToYUY2
global blankthreshold=4
global prev_source = selectevery(source, 1, -1)
clip1 = crop(source,0,0,480,9)
clip2 = crop(source,0,9,480,18)
clip3 = crop(source,0,27,480,18)
clip4 = crop(source,0,45,480,18)
clip5 = crop(source,0,63,480,18)
clip6 = crop(source,0,81,480,18)
clip7 = crop(source,0,99,480,18)
clip8 = crop(source,0,117,480,18)
clip9 = crop(source,0,135,480,18)
clip10 = crop(source,0,153,480,18)
clip11 = crop(source,0,171,480,18)
clip12 = crop(source,0,189,480,18)
clip13 = crop(source,0,207,480,18)
clip14 = crop(source,0,225,480,18)
clip15 = crop(source,0,243,480,18)
clip16 = crop(source,0,261,480,18)
clip17 = crop(source,0,279,480,18)
clip18 = crop(source,0,297,480,18)
clip19 = crop(source,0,315,480,18)
clip20 = crop(source,0,333,480,18)
clip21 = crop(source,0,351,480,9)
Fram1=StackVertical(clip1,clip3,clip5,clip7,clip9,clip11,clip13,clip15,clip17,clip19,clip21)
#return fram1.ConvertToRGB32()
Fram2=StackVertical(clip2,clip4,clip6,clip8,clip10,clip12,clip14,clip16,clip18,clip20)
return StackHorizontal(Fram1,fram2).ConvertToRGB32()
EDIT: And in at least one part of clip there were repeated 4 good frames and one bad.
johnmeyer
8th July 2014, 15:46
John, did you notice that fram1 seems to have light lines whereas fram2 has dark, sometimes other way around.
That dont tell me anything about origin, does it say anything to you?Well, it says that they were offset in time. This is not surprising because the source was interlaced and, of course, the odd and even fields are not only offset spatially, but temporally as well. I don't think there is any pattern as to which frames have lines and which don't.
I believe the lines happen depending on what is in the adjacent scan line when the resizing is done. The whole reason the problem happens is that the resizing operation must look at adjacent scan lines in order to know what pixel to create in each location in the new, smaller-sized video. Since the adjacent lines all come from a different moment in time (but only for interlaced video), bad things happen.
I need to go back to that post where Didée used "Blankclip" AVISynth code to demonstrate how resizing interlaced video, without first deinterlacing, causes the problem. Looking at the code may give me some additional ideas of how to reduce the problems.
One idea I had this morning would be to take my "fixed" video from the code above, and then use a mask to merge it back with the original video. The idea would be to only use the "fixed" version in those areas where there is motion. This would take advantage of the fact that on relatively static scenes, the original video looks fine.
If this works, I could then apply some sort of blur filter to the fixed video, with the blur only applied in the vertical direction. Thus, the static portions of each frame would be un-touched and un-blurred. This is pretty standard stuff, but I've never done any work with masktools, even though I've used scripts by other people that use it.
If I have time, I'll see what I can do.
StainlessS
8th July 2014, 19:27
Dont know if below might be useful, changed to use source clip (instead of Prev_source) in conditional scene change detector, same result.
Maybe of use if you can find some kind of nasty frame detector (IsCombed dont work).
Could also add eg Fixed clip to Select_Op args, if you can find some kind of detector to establish if fixed frame is good or not, and select based on that too.
GSCript("""
Function Select_Op(clip clp,int current_frame) { # Detect first frame after scene change
clp
nd= RT_YDifference(Last,n=current_frame - 1, delta= 1) # We detect relative to previous frame, ie for 1st frame after SC
pd=Max(RT_YDifference(Last,n=current_frame - 1, delta=-1), 0.00001)
Sop = (nd / pd > blankthreshold) ? 0 : 1
Sop # 0=scene change 1st frame : 1=not scene change
}
""")
BLUE = $29F06E # YUV BLUE
msk=New_Clip.Blankclip(length=1,color=000000)
stripe=New_Clip.BlankClip(height=2,color_yuv=BLUE)
GSCript("""
for(y=8,msk.height-2,18) {
msk=msk.overlay(stripe,0,y)
}
""")
Import("D:\avs\bank\s_exlogo.avs")
EXL_AMOUNT = 256 # Strength of S_Exlogo mixing, greater more opaque delogo (256 max)
Exl=New_Clip
GSCript("""
for(y=8,exl.height-2,18) {
exl=exl.S_Exlogo(0,y,-0,2,BlurMode=5,amount=EXL_AMOUNT)
}
""")
InPaint = New_Clip.ExinPaint(msk,color=BLUE)
#Fixed = New_Clip
#Fixed = InPaint
Fixed=Exl
# Use original clip at scene changes: Detect on Source clip rather than prev_source
ConditionalSelect (source, "Last.Select_Op(current_frame)" , source, Fixed,show=true)
#stackhorizontal(source,Last)
stackhorizontal(New_Clip,Last)
return Last
The ExinPaint thing I tried worked well in some cases but detrimental in others (mostly bad).
AVSInpaint produced some terrible colored streaks.
Both slow.
EDITED: Added S_Exlogo stuff, least destructive that I've tried.
Left fixed New_Clip, Right S_Exlogo'ed clip
https://s20.postimg.cc/c06cfxtvh/Kiss0_zps5bc96618.jpg (https://postimg.cc/image/7ea87l8c9/)
EDIT: Maybe even this
EXL_AMOUNT = 256 # Strength of S_Exlogo mixing, greater more opaque delogo (256 max)
EXL_AMOUNT2= 220
Exl=New_Clip
GSCript("""
for(y=8,exl.height-2,18) {
exl=exl.S_Exlogo(0,y,-0,2,BlurMode=5,amount=EXL_AMOUNT)
}
""")
Exl2=Exl
GSCript("""
for(y=7,exl2.height-4,18) {
exl2=exl2.S_Exlogo(0,y,-0,4,BlurMode=5,amount=EXL_AMOUNT2)
}
""")
Still does not seem too destructive and get rid of just a little more rubbish. (output exl2)
Left Exl, Right Exl2
https://s20.postimg.cc/pid8s860t/Kiss1_zps1ba549e9.jpg (https://postimg.cc/image/kjpqdp27t/)
johnmeyer
8th July 2014, 21:09
StainlessS,
I was tracking the mods to your post, and got to go through the evolution of your thinking. The last version works pretty darned well. The overall technique (my work, plus yours) still fails during the strobe lights (as do many other things ...), and also doesn't solve the problems during really rapid, purely vertical motion. However, I don't think it ever makes the video look worse -- a key requirement for any good function. Most of the video now looks almost as good during movement (which is where you see the problems introduced by the improper resizing) as it does during relatively static shots.
Here are a few before/after pics.
https://i.imgur.com/7DcoFCV.jpg
https://i.imgur.com/9FLtSBx.jpg
https://i.imgur.com/79qg9CD.jpg
and here is the frame that had the worst-looking artifact:
https://i.imgur.com/CZ3hIeS.jpg
I'll put the code in the next post. This code will combine my work with what StanlessS did.
johnmeyer
8th July 2014, 21:20
Here is the code used to create the static clips in my last post. This code combines the line removal code posted by StainlessS with the shifting code I previously posted.
I believe that this code now provides a viable "fix" for this specific instance of incorrectly resized interlaced video.
It is my belief that the height of the row blocks that must be shifted, which is 18 in this test clip, would probably be different for other clips. The number of rows will probably depend on the relationships between the original video and the resized version of that video. To make the following code into a function would require replacing all my "crop" and "overlay" calls with a function that could be called with a parameter specifying the height of each row, and the starting location of the first full row.
That is beyond what I have time to do.
# Create two half-height clips from groups of 18 rows of pixels
# Shift one of these clips in time (using motion estimation) halfway between previous frame and current frame
# Then, reassemble the two half height clips.
# First clip uses 9 rows from top and bottome of original clip, plus rows of height=18 in between
#
# John H. Meyer - July 8, 2014
# Line blur code from StanlessS
#
global scenethreshold=4
source = AVISource("E:\fs.avi").KillAudio()
global prev_source = selectevery(source, 1, -1)
clip1 = crop(source,0,0,480,9)
clip2 = crop(source,0,9,480,18)
clip3 = crop(source,0,27,480,18)
clip4 = crop(source,0,45,480,18)
clip5 = crop(source,0,63,480,18)
clip6 = crop(source,0,81,480,18)
clip7 = crop(source,0,99,480,18)
clip8 = crop(source,0,117,480,18)
clip9 = crop(source,0,135,480,18)
clip10 = crop(source,0,153,480,18)
clip11 = crop(source,0,171,480,18)
clip12 = crop(source,0,189,480,18)
clip13 = crop(source,0,207,480,18)
clip14 = crop(source,0,225,480,18)
clip15 = crop(source,0,243,480,18)
clip16 = crop(source,0,261,480,18)
clip17 = crop(source,0,279,480,18)
clip18 = crop(source,0,297,480,18)
clip19 = crop(source,0,315,480,18)
clip20 = crop(source,0,333,480,18)
clip21 = crop(source,0,351,480,9)
fram1 = BlankClip(length=FrameCount(source), width=480, height=180, fps=29.97, color=$000000).converttoyuy2()
fram1 = overlay(fram1,clip1,0,0)
fram1 = overlay(fram1,clip3,0,9)
fram1 = overlay(fram1,clip5,0,27)
fram1 = overlay(fram1,clip7,0,45)
fram1 = overlay(fram1,clip9,0,63)
fram1 = overlay(fram1,clip11,0,81)
fram1 = overlay(fram1,clip13,0,99)
fram1 = overlay(fram1,clip15,0,117)
fram1 = overlay(fram1,clip17,0,135)
fram1 = overlay(fram1,clip19,0,153)
fram1 = overlay(fram1,clip21,0,171)
fram2 = BlankClip(length=FrameCount(source), width=480, height=180, fps=29.97, color=$000000).converttoyuy2()
fram2 = overlay(fram2,clip2,0,0)
fram2 = overlay(fram2,clip4,0,18)
fram2 = overlay(fram2,clip6,0,36)
fram2 = overlay(fram2,clip8,0,54)
fram2 = overlay(fram2,clip10,0,72)
fram2 = overlay(fram2,clip12,0,90)
fram2 = overlay(fram2,clip14,0,108)
fram2 = overlay(fram2,clip16,0,126)
fram2 = overlay(fram2,clip18,0,144)
fram2 = overlay(fram2,clip20,0,162)
prev_fram2 = selectevery(fram2,1,-1)
super=MSuper(prev_fram2,pel=2)
vfe=manalyse(super,truemotion=true,isb=false,delta=1,blksize=8,overlap=4,search=6)
vbe=manalyse(super,truemotion=true,isb=true,delta=1,blksize=8,overlap=4,search=6)
fram2_est = mflowinter(prev_fram2,super,vbe,vfe,time=50,blend=false,mL=100)
new_clip = BlankClip(length=FrameCount(source), width=480, height=360, fps=29.97, color=$000000).converttoyuy2()
new_clip = overlay(new_clip,crop(fram1,0,0,480,18),0,0)
new_clip = overlay(new_clip,crop(fram2_est,0,0,480,18),0,9)
new_clip = overlay(new_clip,crop(fram1,0,9,480,18),0,27)
new_clip = overlay(new_clip,crop(fram2_est,0,18,480,18),0,45)
new_clip = overlay(new_clip,crop(fram1,0,27,480,18),0,63)
new_clip = overlay(new_clip,crop(fram2_est,0,36,480,18),0,81)
new_clip = overlay(new_clip,crop(fram1,0,45,480,18),0,99)
new_clip = overlay(new_clip,crop(fram2_est,0,54,480,18),0,117)
new_clip = overlay(new_clip,crop(fram1,0,63,480,18),0,135)
new_clip = overlay(new_clip,crop(fram2_est,0,72,480,18),0,153)
new_clip = overlay(new_clip,crop(fram1,0,81,480,18),0,171)
new_clip = overlay(new_clip,crop(fram2_est,0,90,480,18),0,189)
new_clip = overlay(new_clip,crop(fram1,0,99,480,18),0,207)
new_clip = overlay(new_clip,crop(fram2_est,0,108,480,18),0,225)
new_clip = overlay(new_clip,crop(fram1,0,117,480,18),0,243)
new_clip = overlay(new_clip,crop(fram2_est,0,126,480,18),0,261)
new_clip = overlay(new_clip,crop(fram1,0,135,480,18),0,279)
new_clip = overlay(new_clip,crop(fram2_est,0,144,480,18),0,297)
new_clip = overlay(new_clip,crop(fram1,0,153,480,18),0,315)
new_clip = overlay(new_clip,crop(fram2_est,0,162,480,18),0,333)
new_clip = overlay(new_clip,crop(fram1,0,171,480,9),0,351)
GSCript("""
Function Select_Op(clip clp,int current_frame) { # Detect first frame after scene change
clp
nd= RT_YDifference(Last,n=current_frame - 1, delta= 1) # We detect relative to previous frame, ie for 1st frame after SC
pd=Max(RT_YDifference(Last,n=current_frame - 1, delta=-1), 0.00001)
Sop = (nd / pd > scenethreshold) ? 0 : 1
Sop # 0=scene change 1st frame : 1=not scene change
}
""")
BLUE = $29F06E # YUV BLUE
msk=New_Clip.Blankclip(length=1,color=000000)
stripe=New_Clip.BlankClip(height=2,color_yuv=BLUE)
GSCript("""
for(y=8,msk.height-2,18) {
msk=msk.overlay(stripe,0,y)
}
""")
EXL_AMOUNT = 256 # Strength of S_Exlogo mixing, greater more opaque delogo (256 max)
Import("C:\Program Files\AviSynth 2.5\plugins\s_exlogo.avs")
Exl=New_Clip
GSCript("""
for(y=8,exl.height-2,18) {
exl=exl.S_Exlogo(0,y,-0,2,BlurMode=5,amount=EXL_AMOUNT)
}
""")
Fixed=Exl
# Use original clip at scene changes: Detect on Source clip rather than prev_source
ConditionalSelect (source, "Last.Select_Op(current_frame)" , source, Fixed,show=false)
stackhorizontal(source,Last)
return Last
StainlessS
8th July 2014, 21:47
Lovely work John, my part was nothing, just blurred a couple of lines.
Now what can we do about fixing that god awful noise (apart from Killaudio) ?
johnmeyer
8th July 2014, 23:09
Now what can we do about fixing that god awful noise (apart from Killaudio) ?Not a big fan of Kiss, eh? :)
I don't know why, but that reminds me of a famous quote from Maurice Ravel, the French composer who said of his famous composition, "Bolero:" "I have written one masterpiece, Bolero. Unfortunately it contains no music."
I guess the same could be said of other people's masterpieces.
StainlessS
9th July 2014, 01:19
I dont mind Kiss, not a exactly a fan though (could not leave out that comment, once it entered my head, hehe).
I'm not sure but I think Ravel actually wrote that piece for a bet, that he could write a 'number 1' with no musical value (and he won the bet).
Pub near me used to use that ditty to sound last orders, on the Crescendo, that was time (just like a ticking clock).
I'll see if I can knock up a function from what was done.
StainlessS
9th July 2014, 16:25
Hi, can you check this out John.
Fixed problem where we select on scene change, see code.
Also, of no particular worry but see "********** 18 should be 9 **********"
#Import("C:\Program Files\AviSynth 2.5\plugins\s_exlogo.avs")
#source = AVISource("E:\fs.avi").KillAudio()
Import("d:\avs\bank\s_exlogo.avs")
source = AVISource("BADYUY2.avi").KillAudio() # Yes, Kill that audio
# Create two half-height clips from groups of 18 rows of pixels
# Shift one of these clips in time (using motion estimation) halfway between previous frame and current frame
# Then, reassemble the two half height clips.
# First clip uses 9 rows from top and bottome of original clip, plus rows of height=18 in between
#
# John H. Meyer - July 8, 2014
# Line blur code from StanlessS
#
global scenethreshold=4
clip1 = crop(source,0,0,480,9)
clip2 = crop(source,0,9,480,18)
clip3 = crop(source,0,27,480,18)
clip4 = crop(source,0,45,480,18)
clip5 = crop(source,0,63,480,18)
clip6 = crop(source,0,81,480,18)
clip7 = crop(source,0,99,480,18)
clip8 = crop(source,0,117,480,18)
clip9 = crop(source,0,135,480,18)
clip10 = crop(source,0,153,480,18)
clip11 = crop(source,0,171,480,18)
clip12 = crop(source,0,189,480,18)
clip13 = crop(source,0,207,480,18)
clip14 = crop(source,0,225,480,18)
clip15 = crop(source,0,243,480,18)
clip16 = crop(source,0,261,480,18)
clip17 = crop(source,0,279,480,18)
clip18 = crop(source,0,297,480,18)
clip19 = crop(source,0,315,480,18)
clip20 = crop(source,0,333,480,18)
clip21 = crop(source,0,351,480,9)
fram1 = BlankClip(length=FrameCount(source), width=480, height=180, fps=29.97, color=$000000).converttoyuy2()
fram1 = overlay(fram1,clip1,0,0)
fram1 = overlay(fram1,clip3,0,9)
fram1 = overlay(fram1,clip5,0,27)
fram1 = overlay(fram1,clip7,0,45)
fram1 = overlay(fram1,clip9,0,63)
fram1 = overlay(fram1,clip11,0,81)
fram1 = overlay(fram1,clip13,0,99)
fram1 = overlay(fram1,clip15,0,117)
fram1 = overlay(fram1,clip17,0,135)
fram1 = overlay(fram1,clip19,0,153)
fram1 = overlay(fram1,clip21,0,171)
fram2 = BlankClip(length=FrameCount(source), width=480, height=180, fps=29.97, color=$000000).converttoyuy2()
fram2 = overlay(fram2,clip2,0,0)
fram2 = overlay(fram2,clip4,0,18)
fram2 = overlay(fram2,clip6,0,36)
fram2 = overlay(fram2,clip8,0,54)
fram2 = overlay(fram2,clip10,0,72)
fram2 = overlay(fram2,clip12,0,90)
fram2 = overlay(fram2,clip14,0,108)
fram2 = overlay(fram2,clip16,0,126)
fram2 = overlay(fram2,clip18,0,144)
fram2 = overlay(fram2,clip20,0,162)
prev_fram2 = selectevery(fram2,1,-1)
super=MSuper(prev_fram2,pel=2)
vfe=manalyse(super,truemotion=true,isb=false,delta=1,blksize=8,overlap=4,search=6)
vbe=manalyse(super,truemotion=true,isb=true,delta=1,blksize=8,overlap=4,search=6)
fram2_est = mflowinter(prev_fram2,super,vbe,vfe,time=50,blend=false,mL=100)
new_clip = BlankClip(length=FrameCount(source), width=480, height=360, fps=29.97, color=$000000).converttoyuy2()
new_clip = overlay(new_clip,crop(fram1,0,0,480,18),0,0) ********** 18 should be 9 **********
new_clip = overlay(new_clip,crop(fram2_est,0,0,480,18),0,9)
new_clip = overlay(new_clip,crop(fram1,0,9,480,18),0,27)
new_clip = overlay(new_clip,crop(fram2_est,0,18,480,18),0,45)
new_clip = overlay(new_clip,crop(fram1,0,27,480,18),0,63)
new_clip = overlay(new_clip,crop(fram2_est,0,36,480,18),0,81)
new_clip = overlay(new_clip,crop(fram1,0,45,480,18),0,99)
new_clip = overlay(new_clip,crop(fram2_est,0,54,480,18),0,117)
new_clip = overlay(new_clip,crop(fram1,0,63,480,18),0,135)
new_clip = overlay(new_clip,crop(fram2_est,0,72,480,18),0,153)
new_clip = overlay(new_clip,crop(fram1,0,81,480,18),0,171)
new_clip = overlay(new_clip,crop(fram2_est,0,90,480,18),0,189)
new_clip = overlay(new_clip,crop(fram1,0,99,480,18),0,207)
new_clip = overlay(new_clip,crop(fram2_est,0,108,480,18),0,225)
new_clip = overlay(new_clip,crop(fram1,0,117,480,18),0,243)
new_clip = overlay(new_clip,crop(fram2_est,0,126,480,18),0,261)
new_clip = overlay(new_clip,crop(fram1,0,135,480,18),0,279)
new_clip = overlay(new_clip,crop(fram2_est,0,144,480,18),0,297)
new_clip = overlay(new_clip,crop(fram1,0,153,480,18),0,315)
new_clip = overlay(new_clip,crop(fram2_est,0,162,480,18),0,333)
new_clip = overlay(new_clip,crop(fram1,0,171,480,9),0,351)
##################################
##################################
##################################
clp=source
RowStart= 9
RowStep = 18
RowStart= (RowStart % RowStep)
TOP_ROW_FIRST=False
GSCript("""
Function Select_Op(clip clp,int current_frame) { # Detect first frame after scene change
clp
nd= RT_YDifference(Last,n=current_frame - 1, delta= 1) # We detect relative to previous frame, ie for 1st frame after SC
pd=Max(RT_YDifference(Last,n=current_frame - 1, delta=-1), 0.00001)
Sc = (nd / pd > scenethreshold) ? 0 : 1
SC # 0=scene change 1st frame : 1=not scene change
}
BotRow = clp.Crop(0,(RowStart>0)?RowStart:RowStep,-0,RowStep)
for(y=((RowStart>0)?RowStart:RowStep)+RowStep*2,clp.Height-RowStart,RowStep*2) {
botRow = BotRow.StackVertical(clp.Crop(0,y,-0,Min(clp.Height-y,RowStep)))
}
if(TOP_ROW_FIRST) {
Offset_BotRow = BotRow
} Else {
Offset_BotRow = BotRow.DeleteFrame(BotRow.FrameCount-1).DuplicateFrame(0)
}
super_BotRow=MSuper(Offset_BotRow,pel=2)
vfe_BotRow=manalyse(super_BotRow,truemotion=true,isb=false,delta=1,blksize=8,overlap=4,search=6)
vbe_BotRow=manalyse(super_BotRow,truemotion=true,isb=true,delta=1,blksize=8,overlap=4,search=6)
est_BotRow=mflowinter(Offset_BotRow,super_BotRow,vbe_BotRow,vfe_BotRow,time=50,blend=false,mL=100)
newClip = clp
for(y=0,est_BotRow.Height-RowStep,RowStep) {
newClip=newClip.Overlay(est_BotRow.Crop(0,y,-0,Min(est_BotRow.Height-y,RowStep)),x=0,y=((RowStart>0)?RowStart:RowStep)+y*2)
}
################
EXL_AMOUNT = 256 # Strength of S_Exlogo mixing, greater more opaque delogo (256 max)
Exl_1=new_clip
for(y=RowStart,Exl_1.height-2,RowStep) {
Exl_1 = Exl_1.S_Exlogo(0,y,-0,2,BlurMode=5,amount=EXL_AMOUNT)
}
Exl_2=newClip
for(y=RowStart,Exl_2.height-2,RowStep) {
Exl_2 = Exl_2.S_Exlogo(0,y,-0,2,BlurMode=5,amount=EXL_AMOUNT)
}
""")
#Fixed_1 = new_clip
#Fixed_2 = newClip
Fixed_1 = Exl_1
Fixed_2 = Exl_2
# *** WE SWITCH ON SCENE CHANGE OF THE NEW CLIP, NOT SOURCE, SOURCE CLIP CAN SC SWITCH AT BAD FRAME ***
# *** See eg 3331(Bad) and 3958(Good)
Result_1 = Fixed_1.ConditionalSelect ("Last.Select_Op(current_frame)" ,source, Fixed_1, show=true)
Result_2 = Fixed_2.ConditionalSelect ("Last.Select_Op(current_frame)" ,clp , Fixed_2 , show=true)
Top=stackhorizontal(source,new_clip)
Bot=stackhorizontal(Result_1,Result_2)
StackVertical(TOP,BOT)
return Last
Can you give it all a once over please before I convert to Function, in particular the MC bit.
(Not feeling very chipper, not slept well for a couple of weeks and I ran out of coffee night before last. Got to nip out soon to see my dealer and get my caffeine hit).
EDIT: Only bottom right clip is result of my mods, other 3 from original code.
johnmeyer
9th July 2014, 16:55
OK, tried it out and it runs ... always a good sign.
The "18 should be 9" is a good catch on your part. Yes it should be 9, but as you can tell, it doesn't actually matter since the "extra 9 lines" get overwritten by the next block.
I deleted all of my code, which you still show in the above post, and also got rid of the comparisons to my code. Before I did this, I did look at the comparisons between yours and mine, and the frames looked the same. Removing my code and the comparisons makes it run much faster (obviously ...).
The one major issue I see, which is easily fixed, is that your scene detect code doesn't always use the original frame at scene changes. Maybe I screwed something up when I made the changes I just noted. However, at some scene changes, I am getting horizontal bars.
Your MC seems to be using identical settings to what I had in my original and therefore seems to be producing the identical results.
Here is the code I ended up testing. It should be the same as what you just posted, but with my code removed, and the comparisons to my code also removed.
Import("C:\Program Files\AviSynth 2.5\plugins\s_exlogo.avs")
source = AVISource("E:\fs.avi").KillAudio() # Yes, Kill that audio
# Create two half-height clips from groups of 18 rows of pixels
# Shift one of these clips in time (using motion estimation) halfway between previous frame and current frame
# Then, reassemble the two half height clips.
# First clip uses 9 rows from top and bottome of original clip, plus rows of height=18 in between
#
# John H. Meyer - July 8, 2014
# Completely re-written into a function by StanlessS July 9, 2014
#
global scenethreshold=4
clp=source
RowStart= 9
RowStep = 18
RowStart= (RowStart % RowStep)
TOP_ROW_FIRST=False
GSCript("""
Function Select_Op(clip clp,int current_frame) { # Detect first frame after scene change
clp
nd= RT_YDifference(Last,n=current_frame - 1, delta= 1) # We detect relative to previous frame, ie for 1st frame after SC
pd=Max(RT_YDifference(Last,n=current_frame - 1, delta=-1), 0.00001)
Sc = (nd / pd > scenethreshold) ? 0 : 1
SC # 0=scene change 1st frame : 1=not scene change
}
BotRow = clp.Crop(0,(RowStart>0)?RowStart:RowStep,-0,RowStep)
for(y=((RowStart>0)?RowStart:RowStep)+RowStep*2,clp.Height-RowStart,RowStep*2) {
botRow = BotRow.StackVertical(clp.Crop(0,y,-0,Min(clp.Height-y,RowStep)))
}
if(TOP_ROW_FIRST) {
Offset_BotRow = BotRow.DuplicateFrame(BotRow.FrameCount-1).DeleteFrame(0)
} Else {
Offset_BotRow = BotRow.DeleteFrame(BotRow.FrameCount-1).DuplicateFrame(0)
}
super_BotRow=MSuper(Offset_BotRow,pel=2)
vfe_BotRow=manalyse(super_BotRow,truemotion=true,isb=false,delta=1,blksize=8,overlap=4,search=6)
vbe_BotRow=manalyse(super_BotRow,truemotion=true,isb=true,delta=1,blksize=8,overlap=4,search=6)
est_BotRow=mflowinter(Offset_BotRow,super_BotRow,vbe_BotRow,vfe_BotRow,time=50,blend=false,mL=100)
newClip = clp
for(y=0,est_BotRow.Height-RowStep,RowStep) {
newClip=newClip.Overlay(est_BotRow.Crop(0,y,-0,Min(est_BotRow.Height-y,RowStep)),x=0,y=((RowStart>0)?RowStart:RowStep)+y*2)
}
################
EXL_AMOUNT = 256 # Strength of S_Exlogo mixing, greater more opaque delogo (256 max)
Exl_2=newClip
for(y=RowStart,Exl_2.height-2,RowStep) {
Exl_2 = Exl_2.S_Exlogo(0,y,-0,2,BlurMode=5,amount=EXL_AMOUNT)
}
""")
Fixed_1 = Exl_2
# *** WE SWITCH ON SCENE CHANGE OF THE NEW CLIP, NOT SOURCE, SOURCE CLIP CAN SC SWITCH AT BAD FRAME ***
# *** See eg 3331(Bad) and 3958(Good)
Result_1 = Fixed_1.ConditionalSelect ("Last.Select_Op(current_frame)" ,source, Fixed_1, show=true)
stackhorizontal(source,Result_1)
return Last
StainlessS
9th July 2014, 17:13
Oops, yes you are correct, me being too clever.
I guess I have to do comparisons on both clips to find out which is less screwed up.
Gonna go get some coffee and have another go.
Thanks.
EDIT: I fixed it for some frames switching on new clip, but screwed it up for others. EDIT: Saw you on-line and posted before I should have.
johnmeyer
9th July 2014, 17:18
Coffee ... good idea ... time for cup #2 (it's early here). I guess high tea is 4:00 p.m. (your time there now), but if I have tea or coffee that late in the day, I get to stay up all night watching old movies 'cause sleep ain't gonna happen.
StainlessS
9th July 2014, 17:25
No, I cant sleep without a good quart of strong coffee followed by a extra good skin full of beer.
(I once bought a jar of Nescafe [4oz I think, not the tiny one], in the morning, and at about 1:00am had to go out
to the 24hour place to get another one).
Yeh I've been drinking tea for two days, dont really like the stuff that much, just for emergencies.
If you take a peek at the 4 clip version, frame 3331 you will see that it does not uses source on bad scene change,
and on frame 3958, it does switch on good scene change.
Gone to shop.
johnmeyer
9th July 2014, 19:19
I hope the OP checks back in at some point. Hopefully he'll be able to use some of this stuff ...
StainlessS
10th July 2014, 01:32
I'm doing a Multi-Instance version, surprisingly it runs a little faster than the ConditionalSelect version.
I'll PM you with the script, and let you edit wording and such, And then post it here. (I hate docs).
I've Changed args from SceneChangeThreshold to dFact and dMin.
# dFact, default 4.0. (Greater than 1.0). For scene change condition to succeed: dFact*Diff(n-2 -> n-1)+dMin < Diff(n-1 -> n)
# dMin, default 0.5. (Greater than 0.1). dMin avoids silly numbers (very small) at static scenes detecting false scene changes.
Also, did you want me to add the 2nd s_Exlogo that I did in a previous edit.
1st instance will overlay 4 pixel width bad strip but at light AMOUNT setting (making pixels immendiately next to bad strip just a bit better)
2nd instance will overlay 2 pixel width bad strip, full AMOUNT (user adjusted for both)
EDIT: and the pixels adjacent to the two pixel strip are the ones made a little better by the 1st instance s_ExLogo, and used in fixing
the 2 pixel bad strip damage.
EDIT: @ post #35, only I did them wrong way around ie 2,4 instead of probably better 4,2.
johnmeyer
10th July 2014, 02:31
I played around with s_Exlogo and definitely liked slightly more aggressive settings, at least with this particular clip. The function is a little "weak" for this purpose, even with the setting cranked up to max (256), so the two-pass idea sounds good. I thought the second s_Exlogo in your previous code was to apply to "my" clip and the second was for "your" clip. I didn't realize that you were doing two passes. In this case, more is probably better. I also tried to play with the VBlur and Hblur settings because there is no need to blur anything in the horizontal direction, but those didn't seem to have any effect. I then read through all the s_Exlogo documentation (that you hate to write) and I think I can see why that would be so (because the lines extend across the entire frame).
StainlessS
10th July 2014, 03:42
256 for S_Exlogo Amount is maximum opaque Overlay (or maybe Layer, cant remember), would need to take sample from further
outside of bad strip to fix better but that would undoubtably produce more significant destruction.
The 2 pass S_Exlogo thing will allow you to do either, both maxed out at 256 strongest possible, with potential damage.
If I remember correctly, the horizontal bars are the ones affected by VBlur, but as only 2 pixels would not make a lot of difference, and as full width,
of course cannot do HBlur (If we could ie not quite full width, it would be way too destructive spreading image from the right/left extremes into
the center and completely unrelated image areas).
By the way, when I asked you to look at MC stuff, I meant the TopRowFirst thing (not all borked clips will be bottom field first origin),
I thnk its OK but I'm still more than a little knackered from lack of sleep, and was not sure that I've done it correctly, just wanted verification
as I dont have any test clip.
I could not really find a better way to decide on scene change, there are scene cuts on full frame, mid frame both top field scene change and bottom field
scene change, some seems progressive, some interlaced and the occasionl weird scene with 4 good (possibly progressive) and 1 bad frame.
I'll try to complete tonight, and send in PM, just post in thread when you are happy,
(If not happy then get back to me, or amend how you see fit, as far as I'm concerned, it's your script).
johnmeyer
10th July 2014, 06:03
I thought "MC" was Motion Compensation. When you send your new code I'll look at the TopRowFirst logic.
hrgiger6
10th July 2014, 10:48
guys this is starting to look really good! I had a bit of trouble getting S_Exogo going and then got an error with conditionalselect but I ironed that out. its amazing how even scenes that looked fine before, when you A/B them you see how much better they are after processing. I'll check out these newest scripts, I've just run them up to the last one on the second page so far.
I'll look around too and see if I can find some other video with this problem, it may be useful to see what results we get.
StainlessS
10th July 2014, 16:11
I thought "MC" was Motion Compensation. When you send your new code I'll look at the TopRowFirst logic.
Thanks but dont bother john, I had made a really stupid mistake, but fixed it now (could not remember how mflowinter thing worked).
I'm sending PM now, edit and post as you will.
On second thoughts, I'll just post here temporarily, in case OP hrgiger6 wants to have a quick look.
http://www.mediafire.com/download/0fzaxrobcgs4v7z/Macro_Deinterlace.zip
EDIT:
if(TOP_ROW_FIRST) {
Offset_BotRow = BotRow.DuplicateFrame(BotRow.FrameCount-1).DeleteFrame(0)
} Else {
Offset_BotRow = BotRow.DeleteFrame(BotRow.FrameCount-1).DuplicateFrame(0)
}
should have been {As currently implemented}(concerns original field order before clip was resized, and how MC is performed)
if(TopRowFirst) { Offset_BotRow = BotRow} # midway between current and next frames
Else { Offset_BotRow = BotRow.DeleteFrame(BotRow.FrameCount-1).DuplicateFrame(0) } # midway between Previous and current frames
EDIT: I've made no attempt to find best settings, I was more concerned with getting the script functional,
left something for hrgiger6 to do :)
EDIT: John, coords were a little bit off for the S_Exlogo stuff, fixed and re-upped, should be a bit better
(started at the top of the bottom row instead of bottom of the top row :( )
@hrgiger6, suggest as starting point with minimal destruction dFact=4.0 dMin=3.0 Amount=256 Amount2=150.
https://s20.postimg.cc/75h8vekxp/kiss3_zps9f3ef451.jpg (https://postimg.cc/image/lbwzqmvsp/)
Top Left Original : Top right Motion compensation EDIT: Estimation
Bottom left Amount=256 : Bottom right Amount=256 Amount2=150
johnmeyer
10th July 2014, 19:46
Downloaded the zip file in your last post. I get "invalid argument to function Macro_Deinterlace."
I'll work on it and see if I can figure it out.
[edit] You forgot to include "source" as the clip name in your function call.
StainlessS
10th July 2014, 19:56
Arh yes, but only in your version ie
#Import("C:\Program Files\AviSynth 2.5\plugins\s_exlogo.avs")
#source = AVISource("E:\fs.avi").KillAudio()
Import("d:\avs\bank\s_exlogo.avs")
AVISource("BADYUY2.avi").KillAudio() # Yes, Kill that audio # I used last
johnmeyer
10th July 2014, 20:11
My bad. I simply changed it to use my source and didn't notice that the clip was no longer named explicitly.
Everything works great.
I compared to my previous attempts, using one s_Exlogo pass, but using wider lines, etc., and your code produces equivalent line removal results, and probably fewer side-effects.
StainlessS
10th July 2014, 20:16
Im gonna get back to the scene detection thing, toodle pip :)
StainlessS
13th July 2014, 10:44
@JohnMeyer,
John, it's been bugging me that I did not check to see if it was better to use Primary or Secondary delogo first in order.
I've made a couple of changes and dont actually know which I prefer (after only a cursory look at frame 425).
I've made it optional by implementing Order arg, default Secondary delogo used first.
If you prefer it the other way around just change default and comments, below changes.
Function definition, add Order
Function Macro_Deinterlace(clip clp,int RowStart,int RowStep,Bool "TopRowFirst",Float "dFact",Float "dMin",Int "Amount",Int "Amount2",Bool "Order",Bool "Show") {
Comments
# Amount, Default 256, 0 -> 256. 0=Switched Off. Primary deLogo thin lines (height or diameter=2).
# Amount2, Default 0, 0 -> 256. 0=Switched Off. Mild greater diameter delogo (height or diameter=4).
# Order, Default False. Order of s_ExLogo delogo calls to repair thin lines left over after motion estimated repair.
# False=Mild delogo first (using Amount2, height or diameter=4) and then stronger Primary delogo (using Amount, height or diameter=2).
# True=Strong Primary delogo first (using Amount, height or diameter=2) and then milder delogo (using Amount2, height or diameter=4).
# The Primary delogo replaces any bad pixels in any thin lines left over after repair, it does this by taking single pixels from outside
# (above and below) the bad pixels, stacking them together, blur, and then replaces bad pixels. The bad pixels are replaced using
# Amount as the arg to Layer's 'Level' arg (ie opacity).
# The Secondary or mild delogo, uses a diameter or height of 4 pixels, samples singles pixels from 1 pixel outside of the diameter,
# stacking them together, blur and resize to height=4, and then replaces pixels within the diameter using Amount2 as the arg to Layer.
# With the Order arg, you can choose how thin lines repair is processed, it may in some cases produce better results when set False,
# and sometimes with Order set True. The script is Multi-Instance, so you can create two clips, one with Order=False, the other with
# Order=True, and stackHorizontal() to view results alongside each other.
Default Args
Order= Default(Order,False) # Secondary or mild delogo first.
Ordering
if(!Order && Amount2 > 0) { # Secondary Delogo, used before PRIMARY Delogo (More Mild Amount2 setting OR none)
for(y=RowStart,Fix.height-1,RowStep) {
Fix = Fix.S_Exlogo(0,y-2,-0,4,BlurMode=5,amount=Amount2)
}
}
if(Amount > 0) { # PRIMARY Delogo of thin lines (best use strong ie max Amount setting)
for(y=RowStart,Fix.height-1,RowStep) {
Fix = Fix.S_Exlogo(0,y-1,-0,2,BlurMode=5,amount=Amount)
}
}
if(Order && Amount2 > 0) { # Secondary Delogo, used after PRIMARY Delogo (More Mild Amount2 setting OR none)
for(y=RowStart,Fix.height-1,RowStep) {
Fix = Fix.S_Exlogo(0,y-2,-0,4,BlurMode=5,amount=Amount2)
}
}
I shall delete link to zip when I see that hrgiger6 (OP) has been online since link posted. (EDIT: Or you post an edited update).
johnmeyer
14th July 2014, 00:42
I did an A/B on frame 425, and could not see any important difference between doing the strong blend first vs. doing it second.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.