VideoHelp Forum

Try DVDFab and download streaming video, copy, convert or make Blu-rays,DVDs! Download free trial !
+ Reply to Thread
Page 6 of 6
FirstFirst ... 4 5 6
Results 151 to 158 of 158
Thread
  1. Originally Posted by chris319 View Post
    Looking into opencv.
    I managed to avoid it, no opencv , no numpy, just everything in Vapoursynth using expressions and limiter,
    also it is set for more control
    rgb videos can be seen with illegal values as red, mask can be seen black&white, it is more customizable

    Code:
    '''
    Loads YUV clip, converts to rgb where RGB values are limited and clip is converted back to YUV.
    Using masks that reveal illegal RGB values, rgb clips can be visually compared.
    Percentage with illegal values for each rgb frame is in props and can be viewed on screen:
    clip.text.FrameProps().set_output()
    '''
    import vapoursynth as vs
    core = vs.core
    
    clip = core.lsmas.LibavSMASHSource(r'G:/video.mp4')
    
    #MIN and MAX set always as 8bit values, even if using higher bits for RGB
    clip_MIN = 16
    clip_MAX = 235
    
    illegal_MIN = 5
    illegal_MAX = 246
    
    #format could be vs.RGB24 (8bit), vs.RGB30 (10bit), vs.RGB48 (16bit), vs.RGBS (floating point)
    RGB_RESIZE = 'Point'
    RGB_RESIZE_ARGS = dict(matrix_in_s = '709', format = vs.RGB24, range_in_s = 'full')
    
    #allow blur with settings, it blurs only mask/illegal area,
    #but this has not such an impact, just restricting a tiny bit clip_MIN or clip_MAX is much more significant
    CONVOLUTION = False
    CONV_MATRIX = dict( matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1], saturate=True, mode='s' )
    
    YUV_RESIZE  = 'Bicubic'
    YUV_RESIZE_ARGS = dict(matrix_s = '709', format = vs.YUV420P8, range_s = 'full')
    
    PROP_NAME  = f'Percent_of_values_outside_of_range_{illegal_MIN}_to_{illegal_MAX}'
    
    
    
    
    #------------------------ END OF USER INPUT ---------------------------------
    
    
    _RGB_RESIZE = getattr(core.resize, RGB_RESIZE)
    _YUV_RESIZE = getattr(core.resize, YUV_RESIZE)
    
    '''original YUV to RGB'''
    rgb_clip = _RGB_RESIZE(clip, **RGB_RESIZE_ARGS)
    
    if rgb_clip.format.sample_type == vs.INTEGER:
        '''255 for 8bit, 1023 for 10bit etc'''
        SIZE=2**rgb_clip.format.bits_per_sample-1
        clip_min=clip_MIN*(SIZE+1)/256
        clip_max=clip_MAX*(SIZE+1)/256
        illegal_min=illegal_MIN*(SIZE+1)/256
        illegal_max=illegal_MAX*(SIZE+1)/256
    else:
        '''float values for RGBS'''
        SIZE=1
        clip_min=clip_MIN/255.0
        clip_max=clip_MAX/255.0
        illegal_min=illegal_MIN/255.0
        illegal_max=illegal_MAX/255.0
    
    RED_CLIP = core.std.BlankClip(rgb_clip, color = (SIZE,0,0))
    
    def copy_prop(n,f):
       f_out = f[0].copy()
       f_out.props[PROP_NAME] = '{:.1f}'.format(f[1].props['PlaneStatsAverage']*100)
       return f_out
    
    def get_mask(rgb):
        '''
        mask has white pixel if R,G or B value is outside of limits,
        value = SIZE if (x<min or y<min or z<min or x>max or y>max or z>max) else 0
        '''
        mask = core.std.Expr(
                              clips = [core.std.ShufflePlanes(rgb, planes=i,  colorfamily=vs.GRAY)  for i in range(0,3)],
                              expr  = [ f'x {illegal_min} < y {illegal_min} < or {SIZE} 0 ?\
                                                            z {illegal_min} < or {SIZE} 0 ?\
                                                            x {illegal_max} > or {SIZE} 0 ?\
                                                            y {illegal_max} > or {SIZE} 0 ?\
                                                            z {illegal_max} > or {SIZE} 0 ?'
                                      ]
                             )
        mask = mask.std.SetFrameProp(prop=PROP_NAME, delete=True)\
                   .std.SetFrameProp(prop='_Matrix', delete=True)\
                   .std.PlaneStats(prop='PlaneStats')
    
        '''copying PlaneStatsAverage into rgb clip as a new PROP_NAME'''
        rgb = core.std.ModifyFrame(rgb, [rgb, mask], copy_prop)
        return rgb, mask
    
    
    '''making a mask to show illegal values before limiter is applied'''
    rgb_clip, mask = get_mask(rgb_clip)
    
    if CONVOLUTION:
        blurred  = core.std.Convolution(rgb_clip, **CONV_MATRIX)
        rgb_clip = core.std.MaskedMerge(rgb_clip, blurred, mask) 
    
    '''limiting RGB'''
    clipped_rgb = core.std.Limiter(rgb_clip, clip_min, clip_max, planes=[0, 1, 2])
    '''making a mask to show illegal values (should be all black, no illegal values now)'''
    clipped_rgb, mask_clipped = get_mask(clipped_rgb)
    
    '''RGB back to final YUV for delivery '''
    clipped_yuv  = _YUV_RESIZE(clipped_rgb, **YUV_RESIZE_ARGS)
    '''deleting prop in YUV clip'''
    clipped_yuv = core.std.SetFrameProp(clipped_yuv, prop=PROP_NAME, delete=True)
    
    '''changing that YUV back to RGB to mock studio monitor'''
    rgb_monitor    = _RGB_RESIZE(clipped_yuv, **RGB_RESIZE_ARGS)
    '''making a mask to show illegal values'''
    rgb_monitor, mask_monitor = get_mask(rgb_monitor)
    
    
    '''pasting masks as RED into RGB'''
    rgb_clip =    core.std.MaskedMerge(rgb_clip,    RED_CLIP, mask)
    rgb_monitor = core.std.MaskedMerge(rgb_monitor, RED_CLIP, mask_monitor)
    
    clip.set_output()
    rgb_clip.    text.FrameProps().set_output(1)
    mask.        text.FrameProps().set_output(2)
    clipped_rgb. text.FrameProps().set_output(3)
    mask_clipped.text.FrameProps().set_output(4)
    clipped_yuv.set_output(5)                                   #this one is for encoding
    rgb_monitor.text.FrameProps().set_output(6)
    mask_monitor.text.FrameProps().set_output(7)
    Looking at it, blurring (if testing) should be done on that rgb_clipped rather than that first converted RGB, not sure. But blur is not helping that much, as it appears. Just bringing clip_MIN one up or clip_MAX one down can have significant impact.
    Last edited by _Al_; 23rd Feb 2020 at 17:26.
    Quote Quote  
  2. red shows illegal values before and after
    video is from here I think, it was that sneaker lighthouse video https://mega.nz/#!osdxQbCR!vim8f5gAD5nf0w0jf-vEAA3mGySmEOoZQOH_GE3Z2uw
    frame 220, clip_MAX and clip_MIN is 5 and 246, also illegal_MIN and MAX have same values, videos are rgb_clip and rgb_monitor
    Image Attached Thumbnails Click image for larger version

Name:	clip_02_[1920, 1080, 0, 0]_frame_0000220.png
Views:	6
Size:	2.49 MB
ID:	52097  

    Click image for larger version

Name:	clip_07_[1920, 1080, 0, 0]_frame_0000220.png
Views:	6
Size:	2.44 MB
ID:	52098  

    Last edited by _Al_; 23rd Feb 2020 at 04:05.
    Quote Quote  
  3. click three times on image, they will fill your screen on 1920x1080 monitor
    just changing clip_MIN to 10 and clip_MAX=240 it gives this:
    Last edited by _Al_; 22nd Feb 2020 at 20:44.
    Quote Quote  
  4. image:
    Image Attached Thumbnails Click image for larger version

Name:	clip_07_[1920, 1080, 0, 0]_frame_0000220.png
Views:	4
Size:	2.44 MB
ID:	52100  

    Quote Quote  
  5. Originally Posted by chris319 View Post
    Despite extensive testing, I had my full- and limited-range YUV-to-RGB code reversed. It doesn't help that the white bar on RP 219 bars is 235 because that's exactly what I was getting while the underlying problem was being masked. I had to make a special test signal called a window signal, simply a box at 255-255-255 next to a box at 0-0-0 against a gray background. Now I could see if the whites were coming up to 255, which the SMPTE bars weren't revealing. Using a window signal is a good example of ancient technology helping to solve a modern problem.
    Yes definitely make use of other patterns and tests.

    For levels tests, another common test is using a full ramp for Y=0 to Y=255 for 8bit. Using that with a Y' waveform can detect all sorts of problems

    Bars typically have "blacker than black" area in the pluge area (Y<16), but not all have "whiter than white" (Y>235) areas. Most custom ones have both for this very reason e.g. the vapoursynth bars



    I'm still having trouble getting the lutrgb values right. On actual picture content, ringing artifacts seem to bother the lutrgb functions. I hate to apply unsharp and low-pass filter it because the picture is a tiny bit soft to begin with.

    LutRGB works in RGB . If you measure the direct RGB output, it should be working ok. If not, there is a bug.

    (When you convert to YUV it's no longer RGB, and you're going to expect some issues. And when subsample YUV444 to 422 or 420, even more problems and deviations are expected)



    To find the bug, sometimes you have to look in the mirror.
    Happens to everybody
    Quote Quote  
  6. those illegal values might be just single red, blue or green ,where overall color is from middle of range, but just one single RGB color jumps out to illegal values, like here for example in that grass, where green color jumps out:
    here are cropped versions of above frames:
    first : rgb_clip (before limiting, just YUV to RGB)
    second: rgb_monitor (YUV to RGB, limited and then encoded to YUV, then observed again in RGB)
    Image Attached Thumbnails Click image for larger version

Name:	cropped_clip_02_[240, 134, 1016, 918]_frame_0000220.png
Views:	5
Size:	771.7 KB
ID:	52101  

    Click image for larger version

Name:	cropped_clip_07_[240, 134, 1016, 918]_frame_0000220.png
Views:	4
Size:	811.2 KB
ID:	52102  

    Last edited by _Al_; 23rd Feb 2020 at 04:05.
    Quote Quote  
  7. I thought that those illegal values were green , because of grass, but they are actually blue, counter intuitive

    so below are even more to detail pixels, settings used:
    clip_MIN = 10
    clip_MAX = 240
    illegal_MIN = 5
    illegal_MAX = 246

    RGB_RESIZE = 'Point'
    RGB_RESIZE_ARGS = dict(matrix_in_s = '709', format = vs.RGB24, range_in_s = 'full')

    YUV_RESIZE = 'Bicubic'
    YUV_RESIZE_ARGS = dict(matrix_s = '709', format = vs.YUV420P8, range_s = 'full')
    Last edited by _Al_; 23rd Feb 2020 at 04:05.
    Quote Quote  
  8. 1. So here it is all in order, first RGB_clipped with legal values, so all values are legal:
    RGB_clipped: P Frame:220 Pixel: 1010,963 RGB24 r:81 g:90 b:10 preview: r:81 g:90 b:10
    RGB_clipped: P Frame:220 Pixel: 1010,964 RGB24 r:70 g:86 b:10 preview: r:70 g:86 b:10
    RGB_clipped: P Frame:220 Pixel: 1010,965 RGB24 r:73 g:89 b:10 preview: r:73 g:89 b:10
    RGB_clipped: P Frame:220 Pixel: 1010,966 RGB24 r:72 g:95 b:10 preview: r:72 g:95 b:10
    RGB_clipped: P Frame:220 Pixel: 1010,967 RGB24 r:76 g:99 b:10 preview: r:76 g:99 b:10
    RGB_clipped: P Frame:220 Pixel: 1010,968 RGB24 r:80 g:101 b:10 preview: r:80 g:101 b:10

    2. rgb_monitor with mask

    3. rgb_monitor without mask:
    RGB_monitor: P Frame:220 Pixel: 1010,963 RGB24 r:82 g:90 b:2 preview: r:82 g:90 b:2
    RGB_monitor: P Frame:220 Pixel: 1010,964 RGB24 r:71 g:87 b:1 preview: r:71 g:87 b:1
    RGB_monitor: P Frame:220 Pixel: 1010,965 RGB24 r:74 g:90 b:4 preview: r:74 g:90 b:4
    RGB_monitor: P Frame:220 Pixel: 1010,966 RGB24 r:73 g:95 b:10 preview: r:73 g:95 b:10
    RGB_monitor: P Frame:220 Pixel: 1010,967 RGB24 r:77 g:99 b:14 preview: r:77 g:99 b:14
    RGB_monitor: P Frame:220 Pixel: 1010,968 RGB24 r:79 g:102 b:8 preview: r:79 g:102 b:8

    Note: Do not crop script into this ridiculously small resolution (and then try to blow up elsewhere on screen to see pixels). Maybe it is just me, it freezes a PC if trying to crop somewhere beyond 50x30, regular crops are just fine. Something in that script above gives a trouble. In normal script it does not matter.
    Image Attached Thumbnails Click image for larger version

Name:	1.rgb_clipped_04_all_values_legal[30, 16, 1004, 960]_frame_0000220.png
Views:	3
Size:	11.6 KB
ID:	52108  

    Click image for larger version

Name:	2.rgb_monitor_mask_07_[30, 16, 1004, 960]_frame_0000220.png
Views:	3
Size:	11.6 KB
ID:	52109  

    Click image for larger version

Name:	3.rgb_monitor_07_[30, 16, 1004, 960]_frame_0000220.png
Views:	3
Size:	11.7 KB
ID:	52110  

    Last edited by _Al_; 23rd Feb 2020 at 17:39.
    Quote Quote  



Similar Threads