home home Staff Contact
Forensic Protection - Services Forensic Protection - Rates Forensic Protection - FP_System Forensic Protection - Process
RgbAmplifier

PROBLEM: Increasing a video's gamma or histogram profile can brighten a seemingly black nighttime surveillance video. However, with only 256 shades of YUV illumination, the results can fail to be forensically useful.

SOLUTION:
Amplify subtle color changes to detect movement (weapon, people in the shadows, etc...), amplify signage (logos, license plates, etc...), and other forensic needs. Besides the obvious use with low quality surveillance video, the exaggerated color shifts allow the detection of seemingly imperceptible temperature changes. For example, machinery heating up (and thus red incremented by one value in RGB space). Here it amplifies the otherwise nearly invisible shadows of two birds (b/w and loops several times), even though this was a very low quality and noisy original. It did the same thing for suspects hiding in the bushes for one of my active cases.

BACKGROUND:
Forensic video analysts often encounter videos with washed out details. A few years back I invented an AVIsynth script that exaggerated subtle changes in pixels as they deviated from the average value of that same pixel across adjacent frames. The filter was painfully slow and suffered from out-of-memory issues. New tools provided a slight speed increase but the memory and speed issues were too constraining, until the script was recently optimized into a plugin.

Because RGB color space retains maximum details, adjacent pixels may have imperceptible color differences. If either pixel is part of a moving object, amplifying the difference will make the variance easily viewable. By restricting the affected color range, the user can target a specific need. The revised script allows the user to define the level of amplification, the temporal range for averaging, and the color range affected.

APPLICATION:
Filters that remove poison or salt-pepper noise may be more effective, and less likely to remove valid details, after RgbAmplifier filter processing. Once amplified, VELA testing can be applied to highlight the previously faint details that are now dominant events (e.g. a knife in a persons hand during a night time fight).

VIDEO PREPARATION:
Videos in RGB color space require a separate byte for each of the red (R), green (G) and blue (B) color values for every pixel. Videos in YUV (4.2.0) color space retain a luminosity (Y) byte value for every pixel, but retain only one red (U) and blue (V) color value for each 2 by 2 group of pixels. Since each byte is an integer value ranging 0 to 255, YUV color space requires only one third of the bytes compared to RGB with minimal perceptual loss in quality. This reduced file size supports faster video transmissions (TV, internet, CCTV, etc..), but is unsuitable for RGB amplification.

Because RGB color space can retain more data, conversion from YUV to RGB will result in skipped RGB values, and a slight loss in clarity due to the rounding errors from conversion. Processes that increase resolution using temporal Gaussian motion compensated de-interlacing or sub-pixel fusion can be used to recover missing details and clarity. The resulting video can then be resized back to its original resolution to retain some of the additional RGB values.

HOW IT WORKS:
Given a clip, this script examines every pixel of every frame and independently multiplies the difference of its specific R, G and B values from the average R, G and B values of that same pixel location spanning a defined radius of adjacent frames. If the new values are above or below the allowable RGB values (0 and 255), they are capped at those limits. The revised RGB values replace the original values, and the amplified clip is returned. If the Multiplier is set to a value of zero, the plugin acts as a temporal frame averager (works great with license plates).

The filter allows the user to define the color range to be affected. Any color outside that range will not be touched. If no color limits are specified, the resulting scene may look over saturated including any poison noise.

This tool will:
 Convert seemingly imperceptible color changes into obvious color changes
 Highlight seemingly imperceptible movements of high contrast pixels
 Sharpen the details of moving objects in low activity videos (e.g. surveillance videos)
 Cause distortion or ghosting/transparency effect to moving objects (an unavoidable side effect)

This plugin requires RGB24 or RGB32 color space, and is intended for forensic analysis of videos created from fixed position cameras. Usage on non-stationary cameras may produce unpredictable or content destructive results. The faster the object is traveling and/or the greater the filter's radius setting, the greater the risk of negatively impacting the visual accuracy of the moving object.

=====
USAGE:
RgbAmplifier(clip clip,int "Radius"=2,float "Multiplier"=2.0,int "Rmin"=0,int "GMin"=0,int "Bmin"=0, \
int "RMax"=255,int "GMax"=255,int "BMax"=255,bool "Precise"=false)

=====
PARAMETERS:

Radius: integer from 1 to 99 (default 2). Defines the radius of how many frames are to be averaged (2 * radius -1). For example, a radius of 7 will instruct the filter to average 13 frames (2 * 7 -1). A value of 1 effectively disables the function (useful if adjusting the values within AVSpmod).

Multiplier: float from >=0.0 to <=10 (default 2.0). Defines the multiplier for the difference between a pixel’s color value (for each of R, G and B values) and its average value (as defined by the Radius). For example, the default value of 2.0 will replace every R, G and B value of every pixel with a value twice as far from the average R, G or B value of that pixel.

Rmin: integer from 0 to 255 (default 0). Cannot be greater than Rmax. The filter will not alter any pixel whose Red color value is below this threshold value.

Gmin: integer from 0 to 255 (default 0). Cannot be greater than Gmax. The filter will not alter any pixel whose Green color value is below this threshold value.

Bmin: integer from 0 to 255 (default 0). Cannot be greater than Bmax. The filter will not alter any pixel whose Blue color value is below this threshold value.

Rmax: integer from 0 to 255 (default 255). Cannot be less than Rmin. The filter will not alter any pixel whose Red color value is above this threshold value.

Gmax: integer from 0 to 255 (default 255). Cannot be less than Gmin. The filter will not alter any pixel whose Ged color value is above this threshold value.

Bmax: integer from 0 to 255 (default 255). Cannot be less than Bmin. The filter will not alter any pixel whose Blue color value is above this threshold value.

Precise: Boolean (default false). If "false" integer math is used for speed. If "true" double precision Floating point is used for accuracy. This is a plug-in setting only.

=====
EXAMPLES:

RgbAmplifier ()
Double pixel color deviations from the average of the current, preceding and postceding frame’s pixel value

RgbAmplifier (Radius=5, Multiplier=0.0)
Temporal averaging using the current frame and the first four (Radius - 1) preceding and postceding frame’s pixel values

RgbAmplifier (Radius=5, Multiplier=3, Rmin=0, GMin=169, Bmin=234, RMax=5, GMax=179, BMax=244)
Triple pixel color deviations from the average of the current frame and the first four preceding and postceding frame’s pixel values, but only for pixels with a color within 2% of pure Cyan (“00AEEF”)

If you would like a free hands-on training workshop, recommend me and this topic to the educational committee of any national group that you belong to. Upcoming training dates are listed in my CV.

=====
OPTIMIZED SCRIPT:

Function RgbAmplifier (clip clip, int "Radius", float "Multiplier",int "Rmin",int "GMin",int "Bmin",int "RMax",int "GMax",int "BMax") {
 myName="RgbAmplifier: "
 Radius=Default(Radius,2) Multiplier=Float(Default(Multiplier,2.0))
 RMin=Default(RMin,0) GMin=Default(GMin,0) BMin=Default(BMin,0)
 RMax=Default(RMax,255) GMax=Default(GMax,255) BMax=Default(BMax,255)
 Assert(Radius>=1 && Radius <= 99,"RgbAmplifier: Radius range 1->99 ("+String(Radius)+")")
 Assert(Multiplier>=0.0 && Multiplier<=10.0,"RgbAmplifier: 0.0 <= Multiplier <= 10.0 ("+String(Multiplier)+")")
 Assert(RMin<=255&&RMin>=0,myName+"RMin range 0 -> 255 ("+String(RMin)+")")
 Assert(GMin<=255&&GMin>=0,myName+"GMin range 0 -> 255 ("+String(GMin)+")")
 Assert(BMin<=255&&BMin>=0,myName+"BMin range 0 -> 255 ("+String(BMin)+")")
 Assert(RMax<=255&&RMax>=RMin,myName+"RMax range RMin -> 255 ("+String(RMax)+")")
 Assert(GMax<=255&&GMax>=GMin,myName+"GMax range GMin -> 255 ("+String(GMax)+")")
 Assert(BMax<=255&&BMax>=BMin,myName+"BMax range BMin -> 255 ("+String(BMax)+")")
 GScript("""
  WW=clip.Width() HH=clip.Height() FC=clip.Framecount()
  clipfinal=0
  for(i=0,FC-1) {
   clip2=clip.trim(i,-1)
   rangemin = Max(i-(Radius-1),0)
   rangemax = Min(i+(Radius-1),FC-1)
   diameter = rangemax - rangemin + 1
   for(y=0,HH-1) {
    for(x=0,WW-1) {
     red=0 green=0 blue=0
     redavg=0 greenavg=0 blueavg=0
     for(j=rangemin,rangemax){
      col = clip.RT_RGB32AsInt(n=j, x=x, y=y)
      b=RT_BitAND(col,$FF) col=RT_BitLSR(col,8)
      g=RT_BitAND(col,$FF) col=RT_BitLSR(col,8)
      r=RT_BitAND(col,$FF)
      redavg = redavg + r
      greenavg = greenavg + g
      blueavg = blueavg + b
      if(j==i) {
       red = r
       green = g
       blue = b
      }
     }
     if(r>=RMin&&r<=RMax && g>=GMin&&g<=GMax && b>=BMin&&b<=BMax) {
      redavg = Float(redavg) / diameter
      newred = Round(redavg + (Multiplier * ( red - redavg)))
      newred = Max(Min(newred,255),0)
      greenavg = Float(greenavg) / diameter
      newgreen = Round(greenavg + (Multiplier * ( green - greenavg)))
      newgreen = Max(Min(newgreen,255),0)
      blueavg = Float(blueavg) / diameter
      newblue = Round(blueavg + (Multiplier * ( blue - blueavg)))
      newblue = Max(Min(newblue,255),0)
      clip2=clip2.Layer(clip2.BlankClip(pixel_type="RGB32", color=(newred*256+newgreen)*256+newblue)
      \ .crop(0,0,1,1), x=x, y=y, level=257)
     }
    }
   }
   clipfinal=(clipfinal.IsClip()) ? clipfinal++clip2 : clip2
  }
  return clipfinal
 """)
}

The above work is the original creation and intellectual property of Doug Carner, president of Forensic Protection, Inc. with special thanks to Gavino and StainlessS for optimizing my script into a plug-in.

Side note: Original introduced in 2010 as "Paranormal filtering" to debunk supernatural videos, it (and I) was publicly ridiculed for its name, ignoring its potential value to the forensic community. It has been renamed "RgbAmplifier" to encourage scientific collaboration and a more civil discussion.

Update: In 2012, realizing the power of this technology, MIT began work on their version, "Eulerian Video Magnification".

Copyright © Forensic Protection
QuickLinks | Main page | Case study | Media | FAQs | Contact us