Ecmascript 6

Variables

different between let and var

{
    var a=12;
    let b=22;
}
console.log(a);//12
console.log(b);// undefined

const

const x = 10
x = 12 // will result in an error!!

const a={};
a.m=12;
console.log(a);//{ m: 12 }
a={};//error

const arr=[1,2,3];
arr.push(4);//[1,2,3,4]
arr=[];//error

var and hoisting

Variable hoisting allows the use of a variable in a JavaScript program, even before it is declared. Such variables will be initialized to undefined by default. JavaScript runtime will scan for variable declarations and put them to the top of the function or script. Variables declared with var keyword get hoisted to the top.

//hoisted to top ; var i = undefined
for (var i = 1;i <= 5;i++){
   console.log(i);
}
console.log("after the loop i value is "+i);
//variable company is hoisted to top , var company = undefined
console.log(company); // using variable before declaring
var company = "TutorialsPoint"; // declare and initialized here
console.log(company);
   var balance = 5000
   console.log(typeof balance)//Number
   var balance = {message:"hello"}
   console.log(typeof balance)//Object

Operators

let a=null;
let b=a||12;//b=12

let a=null;
let b=a&&12;//b=null

?. and ?? operator

let m=undefined;
console.log(m?.hello)//undefined
let m=undefined??"mohammed";
console.log(m);//mohammed

Spread operator

<script>
   function addThreeNumbers(a,b,c){
      return a+b+c;
   }
   const arr = [10,20,30]
   console.log('sum is :',addThreeNumbers(...arr))
   console.log('sum is ',addThreeNumbers(...[1,2,3]))
</script>
   //copy array using spread operator
   let source_arr = [10,20,30]
   let dest_arr = [...source_arr]
   console.log(dest_arr)
	
   //concatenate two arrays
   let arr1 = [10,20,30]
   let arr2 =[40,50,60]
   let arr3 = [...arr1,...arr2]
   console.log(arr3)
<script>
   //copy object
   let student1 ={firstName:'Mohtashim',company:'TutorialsPoint'}
   let student2 ={...student1}
   console.log(student2)
   //concatenate objects
   let student3 = {lastName:'Mohammad'}
   let student4 = {...student1,...student3}
   console.log(student4)
</script>

Loops

in loop

let a={a:"hello",b:"world"}
for(let m in a){
    console.log(a[m]);
}

of loop

let a=[1,2,3,4];
for(let m of a){
    console.log(m);
}

label with break

outerloop: // This is the label name
for (var i = 0; i < 5; i++) {
   console.log("Outerloop: " + i);
   innerloop:
   for (var j = 0; j < 5; j++){
      if (j > 3 ) break ; // Quit the innermost loop
      if (i == 2) break innerloop; // Do the same thing
      if (i == 4) break outerloop; // Quit the outer loop
      console.log("Innerloop: " + j);
   }
}

Functions

constructor function

function A(val){
    this.b=val;
}

let a=new A(12);
console.log(a.b);//12
console.log(a instanceof A);//true
console.log(A.prototype===a.__proto__);//true
A.prototype.x=32;
console.log(a.x);//32
console.log(a.hasOwnProperty("x"));//false
a.x=321;
console.log(a.hasOwnProperty("x"));//true

Rest parameters

function fun1(...params) { 
   console.log(params.length); 
}  
fun1();  
fun1(5); 
fun1(5, 6, 7); 

Lambda functions

var msg = ()=> { 
   console.log("function invoked") 
} 
msg() 

var msg = x=> { 
   console.log(x) 
} 
msg(10)

Function Hoisting

Like variables, functions can also be hoisted. Unlike variables, function declarations when hoisted, hoists the function definition rather than just hoisting the function’s name.

hoist_function();  //call function
function hoist_function() { 
   console.log("foo"); 
} 
hoist_function(); // TypeError: hoist_function() is not a function  
var hoist_function() = function() { 
   console.log("bar"); 
};

Generator function

"use strict" 
function* rainbow() { 
   // the asterisk marks this as a generator 
   yield 'red'; 
   yield 'orange'; 
   yield 'yellow'; 
   yield 'green'; 
   yield 'blue'; 
   yield 'indigo'; 
   yield 'violet'; 
} 
for(let color of rainbow()) { 
   console.log(color); 
} 
function* ask() { 
   const name = yield "What is your name?"; 
   const sport = yield "What is your favorite sport?"; 
   return `${name}'s favorite sport is ${sport}`; 
}  
const it = ask(); 
console.log(it.next()); 
console.log(it.next('Ethan'));  
console.log(it.next('Cricket')); 

Objects

let A={};
let B=A;
let C={};
C[A]=12;
console.log(C[B]);
let k=12;
let A={k};
console.log(A["k"]);
var myCar = new Object(); 
myCar.make = "Ford"; //define an object 
myCar.model = "Mustang"; 
myCar.year = 1987;  

console.log(myCar["make"]) //access the object property 
console.log(myCar["model"]) 
console.log(myCar["year"])

let A={"v1":12};
let B=Object.create(A);
console.log(B.v1);//12
console.log(B===A);//false

delete property

// Creates a new object, myobj, with two properties, a and b. 
var myobj = new Object; 
myobj.a = 5; 
myobj.b = 12; 

// Removes the ‘a’ property 
delete myobj.a; 
console.log ("a" in myobj) // yields "false"

comparing

var val1 = {name: "Tom"}; 
var val2 = {name: "Tom"}; 
console.log(val1 == val2)  // return false 
console.log(val1 === val2)  // return false

object de-structing

<script>
let student = {
   rollno:20,
   name:'Prijin',
   cgpa:7.2
}

//destructuring to same property name
   let {name,cgpa} = student
   console.log(name)
   console.log(cgpa)

//destructuring to different name
   let {name:student_name,cgpa:student_cgpa}=student
   console.log(student_cgpa)
   console.log("student_name",student_name)
</script>
let customers= {
    c1:101,
    c2:102,
    c3:103
}

let {c1,...others} = customers
console.log(c1)//c1
console.log(others)//c2,c3

let emp = {
    id:101,
    address:{
        city:'Mumbai',
        pin:1234
    }
}
let {address} = emp;

console.log(address)
let {address:{city,pin}} = emp
console.log(city)//mumbai

define property

let B={a:1,b:2,c:3};
Object.defineProperty(B,"h",{ enumerable:true, value:4, configurable:true,writable:true});
for(let m in B){
    console.log(m);//a,b,c,h all of them they are enumerable
}
B.h={A:32};//can write on value because it writable
delete  B.h;//can delete because it configurable
console.log(B.h);

set and get

let B={a:1,b:2,c:3};

Object.defineProperty(B,"d",{ set(v) {console.log("hello");
    },get() {console.log("world");
    }});
B.d=345;//hello
let m=B.d;//world

let C={set name(v) {console.log("set ",v);
    },get name() {
    console.log("get");
    }};
C.name=43;//set   43

function constructor(){
    this.val=12;
}
let obj=new constructor();
obj.a=1;
obj.b=2;
console.log(Object.keys(obj));//[val,a,b]

?. and ?? operator

let m=undefined;
console.log(m?.hello)//undefined
let m=undefined??"mohammed";
console.log(m);//mohammed

Number

var num = new Number(10);
console.log(num.toString());
console.log(num.toString(2));//binary
console.log(num.toString(8));//octal

let val=41.2334
console.log(val.toFixed(1))//41.2
console.log(Number(" 12.453  "));//12.453

let val=Number("hello");
console.log(Number.isNaN(val));//true

let val=new Number(12);//instanceof Number
let val=12;//not instanceof Number

String

const str = "Please locate where 'locate' occurs!";
console.log(str.length);//36
console.log(str.indexOf("locate"));//7
console.log(str.toUpperCase());//PLEASE LOCATE WHERE 'LOCATE' OCCURS!
console.log(str.split(' '));//[ 'Please', 'locate', 'where', "'locate'", 'occurs!' ]
console.log(str.endsWith('!'));//true
console.log(str.substr(7))//locate where 'locate' occurs!

let str2="  I  Like  Frutes  ";
str2=str2.trim();
console.log(str2.replace(/(\s+)/i,','));//I,Like  Frutes
console.log(str2.search(/\w{0,2}\s/i));//0
console.log(str2.match(/(\w+\s*)/gi));//[ 'I  ', 'Like  ', 'Frutes' ]

var text1 = "Hello";
var text2 = "World";
var text3 = text1.concat(" ", text2);//Hello World

Array

let arr = ["orange", "mango", "banana", "sugar", "tea"];
let removed = arr.splice(2, 0, "water");//no remove only add
console.log(arr);//orange,mango,water,banana,sugar,tea

removed = arr.splice(3, 1);
console.log("After adding 1: " + arr );//orange,mango,water,sugar,tea
console.log("removed is: " + removed);//banana

var arr = ["orange", "mango", "banana", "sugar", "tea"]; 
console.log("arr.slice( 1, 2) : " + arr.slice( 1, 2) );//mango
console.log("arr.slice( 1, 3) : " + arr.slice( 1, 3) );//mango,banana
var arr = new Array("First","Second","Third"); 
var str = arr.join();console.log("str : " + str );  
var str = arr.join(", "); 
console.log("str : " + str );  

var str = arr.join(" + "); 
console.log("str : " + str );

/*
str : First,Second,Third 
str : First, Second, Third 
str : First + Second + Third 
*/
array.sort( compareFunction ); //or with no compare functions for numbers ands string array
push(element)//add to end 
unshift(element)//add to first
shift()//remove first
pop()//remove last 
function isBigEnough(element, index, array) { 
   return (element >= 10); 
} 
var retval = [2, 5, 8, 1, 4].some(isBigEnough); 
console.log("Returned value is : " + retval ); //false

var retval = [12, 5, 8, 1, 4].some(isBigEnough); 
console.log("Returned value is : " + retval );//true

var passed = [12, 5, 8, 130, 44].filter(isBigEnough); 
console.log("Test Value : " + passed );  //12,130,44

Map

let daysMap = new Map();
daysMap.set('1', 'Monday');
daysMap.set('2', 'Tuesday');
daysMap.set('3', 'Wednesday');
console.log(daysMap.size);

let andy = {ename:"Andrel"},
    varun = {ename:"Varun"},
    prijin = {ename:"Prijin"}
let empJobs = new Map([[andy,'Software Architect'],[varun,'Developer']]);
console.log(empJobs)//{{…} => "Software Architect", {…} => "Developer"}
'use strict' 
var roles = new Map([ 
   ['r1', 'User'], 
   ['r2', 'Guest'], 
   ['r3', 'Admin'], 
]);
for(let r of roles.entries()) 
console.log(`${r[0]}: ${r[1]}`);

let m=new Map([["ali",1],["mohammed",2]]);
for(let [k,v] of m.entries()){
    console.log(k,v);
}

Promise

   function add_positivenos_async(n1, n2) {
      let p = new Promise(function (resolve, reject) {
         if (n1 >= 0 && n2 >= 0) {
            //do some complex time consuming work
            resolve(n1 + n2)
         }
         else
            reject('NOT_Postive_Number_Passed') 
         })
         return p;
   }

   add_positivenos_async(10, 20)
      .then(successHandler) // if promise resolved
      .catch(errorHandler);// if promise rejected

   add_positivenos_async(-10, -20)
      .then(successHandler) // if promise resolved
      .catch(errorHandler);// if promise rejected

   function errorHandler(err) {
      console.log('Handling error', err)
   }
   function successHandler(result) {
      console.log('Handling success', result)
   }

   console.log('end')
function add_positivenos_async(n1, n2) {
    let p = new Promise(function (resolve, reject) {
        if (n1 >= 0 && n2 >= 0) {
            //do some complex time consuming work
            resolve(n1 + n2)
        }
        else
            reject('NOT_Postive_Number_Passed')
    })
    return p;
}

add_positivenos_async(10,20)
    .then(function(result){
        console.log("first result",result)
        return add_positivenos_async(result,result)
    }).then(function(result){
    console.log("second result",result)
    return add_positivenos_async(result,result)
}).then(function(result){
    console.log("third result",result)
})

console.log('end')

promise.all()
This method can be useful for aggregating the results of multiple promises.

   function add_positivenos_async(n1, n2) {
      let p = new Promise(function (resolve, reject) {
         if (n1 >= 0 && n2 >= 0) {
            //do some complex time consuming work
            resolve(n1 + n2)
         }
         else
            reject('NOT_Postive_Number_Passed')
      })

      return p;
   }
   //Promise.all(iterable)

Promise.all([add_positivenos_async(10,20),add_positivenos_async(30,40),add_positivenos_async(50,60)])
   .then(function(resolveValue){
      console.log(resolveValue[0])
      console.log(resolveValue[1])
      console.log(resolveValue[2])
      console.log('all add operations done')
   })
   .catch(function(err){
      console.log('Error',err)
   })
   console.log('end')

/*
end
30
70
110
all add operations done
*/

promise.race() This function takes an array of promises and returns the first promise that is settled.

   function add_positivenos_async(n1, n2) {
      let p = new Promise(function (resolve, reject) {
         if (n1 >= 0 && n2 >= 0) {
            //do some complex time consuming work
            resolve(n1 + n2)
         } else
            reject('NOT_Postive_Number_Passed')
      })

      return p;
   }

   //Promise.race(iterable)
   Promise.race([add_positivenos_async(10,20),add_positivenos_async(30,40)])
   .then(function(resolveValue){
      console.log('one of them is done')
      console.log(resolveValue)
   }).catch(function(err){
      console.log("Error",err)
   })

   console.log('end')

async

async function  fun(){
    return 100;
}

Promise.all([fun(),fun(),fun()]).then((res)=>{
    console.log(res);});

await


async function  fun(){
    return 100;
}

async  function  fun2(){
    let prom=Promise.all([fun(),fun(),fun()]);
    let res=await prom;
    return res;
}

fun2().then(res=>{console.log(res)});//[ 100, 100, 100 ]
async function f() {

  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve("done!"), 1000)
  });

  let result = await promise; // wait until the promise resolves (*)

  alert(result); // "done!"
}

f();

class

class A{
    m=12;
    constructor(val) {
        console.log(val);
        this.m=val;
    }
    set value(val){
        this.m=val;
    }

    get value() {
        return this.m;
    }
}

let a=new A(12);//12
a.value=22;
console.log(a.value);//22
class A{
    m=12;
    constructor(val) {
        console.log("A : ",val);
        this.m=val;
    }
    set value(val){
        this.m=val;
    }

    get value() {
        return this.m;
    }
}
class B extends A{
    constructor(val) {
        super(val);
        console.log("B : ",val)
    }
}
let b=new B(12);//A : 12 B : 12
class A{
    #m=12;//private field
}

get constructor from object

class A{
}

let a=new A();
console.log(a.constructor==A);//true

call super members

class A{
    constructor() {
    }
    fun(){
        console.log("A");
    }
}

class B extends A{
    constructor() {
        super();
    }
    fun(){
        super.fun();
        console.log("B");
    }

}

let b=new B();
b.fun();//A B

Color Space Transform And Geometry Transform

Color Space ,Transform, Threshold

Mat green=Mat(1,1,CV_8UC,Scalar(0,255,0)),hsv_green;
cv::cvtColor(green,hsv_green,cv::COLOR_BGR2HSV);
vec<uint8_t,3> value=hsv_green.at<vec<uint8_t,3>>(0,0);

Now you take [H-10, 100,100] and [H+10, 255, 255] as the lower bound and upper bound respectively. 

Object Color Tracking by inRange

    # Take each frame
    _, frame = cap.read()
    # Convert BGR to HSV
    hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
    # define range of blue color in HSV
    lower_blue = np.array([110,50,50])
    upper_blue = np.array([130,255,255])
    # Threshold the HSV image to get only blue colors
    mask = cv.inRange(hsv, lower_blue, upper_blue)
    # Bitwise-AND mask and original image
    res = cv.bitwise_and(frame,frame, mask= mask)

Transformations

OpenCV provides two transformation functions, warpAffine and warpPerspective, with which you can perform all kinds of transformations. warpAffine takes a 2×3 transformation matrix while warpPerspective takes a 3×3 transformation matrix as input.

resize Imgae
Scaling is just resizing of the image. OpenCV comes with a function resize() for this purpose. The size of the image can be specified manually, or you can specify the scaling factor. Different interpolation methods are used. Preferable interpolation methods are INTER_AREA for shrinking and INTER_CUBIC (slow) & INTER_LINEAR for zooming. By default, the interpolation method INTER_LINEAR is used for all resizing purposes. You can resize an input image with either of following methods:

resize(LoadedImage, LoadedImage, Size(100, 100));

Tanslate

warpAffine( src, warp_dst, warp_mat, warp_dst.size() );
translation.jpg

Rotation

Mat cv::getRotationMatrix2D	(	Point2f 	center,
double 	angle,
double 	scale 
)	
M = getRotationMatrix2D(((cols-1)/2.0,(rows-1)/2.0),90,1)
warpAffine(img,dest,M,(cols,rows))
rotation.jpg

Affine Transformation

In affine transformation, all parallel lines in the original image will still be parallel in the output image. To find the transformation matrix, we need three points from the input image and their corresponding locations in the output image. Then getAffineTransform will create a 2×3 matrix which is to be passed to warpAffine.


Mat cv::getAffineTransform	(	const Point2f 	src[],
const Point2f 	dst[] 
)	

Parameters
src	Coordinates of triangle vertices in the source image.
dst	Coordinates of the corresponding triangle vertices in the destination image.
affine.jpg

Perspective Transformation

For perspective transformation, you need a 3×3 transformation matrix. Straight lines will remain straight even after the transformation. To find this transformation matrix, you need 4 points on the input image and corresponding points on the output image. Among these 4 points, 3 of them should not be collinear. Then the transformation matrix can be found by the function getPerspectiveTransform. Then apply warpPerspective with this 3×3 transformation matrix.


Mat cv::getPerspectiveTransform	(	InputArray 	src,
InputArray 	dst,
int 	solveMethod = DECOMP_LU 
)	
pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])
pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])
Mat M = getPerspectiveTransform(pts1,pts2)
warpPerspective(img,dst,M,(300,300))
perspective.jpg

Gradient And Edge Detection With OpenCV

Edge Detection With Canny

1- RGB to Gray

2- Noise Removal (Gaussian Filter)

3- Edge Detection (Sobel Operator)

4-Edge Thinning ( Non Maximal Supression )

5- Connect Week Edges (Hysteresis Thresholding) (Double Threshold)

Mat src, src_gray;
Mat dst, detected_edges;
int lowThreshold = 0;
const int max_lowThreshold = 100;
const int ratio = 3;
const int kernel_size = 3;
const char* window_name = "Edge Map";
static void CannyThreshold(int, void*)
{
    blur( src_gray, detected_edges, Size(3,3) );
    Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );
    dst = Scalar::all(0);
    src.copyTo( dst, detected_edges);
    imshow( window_name, dst );
}

Gradient With Sobel , Scharr and Laplacian

OpenCV provides three types of gradient filters or High-pass filters Or Sharpening Filter Sobel, Scharr and Laplacian. We will see each one of them.

1. Sobel and Scharr Derivatives
Sobel operators is a joint Gausssian smoothing plus differentiation operation, so it is more resistant to noise. You can specify the direction of derivatives to be taken, vertical or horizontal (by the arguments, yorder and xorder respectively). You can also specify the size of kernel by the argument ksize. If ksize = -1, a 3×3 Scharr filter is used which gives better results than 3×3 Sobel filter. Please see the docs for kernels used

2- Laplacian
It calculates the Laplacian of the image given by the relation

img = cv.imread('dave.jpg',0)
laplacian = cv.Laplacian(img,cv.CV_64F)
sobelx = cv.Sobel(img,cv.CV_64F,1,0,ksize=5)
sobely = cv.Sobel(img,cv.CV_64F,0,1,ksize=5)
gradients.jpg

If you want to detect both edges, better option is to keep the output datatype to some higher forms, like cv.CV_16S, cv.CV_64F etc, take its absolute value and then convert back to cv.CV_8U. Below code demonstrates this procedure for a horizontal Sobel filter and difference in results.


# Output dtype = cv.CV_8U
sobelx8u = cv.Sobel(img,cv.CV_8U,1,0,ksize=5)
# Output dtype = cv.CV_64F. Then take its absolute and convert to cv.CV_8U
sobelx64f = cv.Sobel(img,cv.CV_64F,1,0,ksize=5)
abs_sobel64f = np.absolute(sobelx64f)
sobel_8u = np.uint8(abs_sobel64f)
double_edge.jpg

Blurring and Filtering images With OpenCV

2D Convolution ( Image Filtering )

As in one-dimensional signals, images also can be filtered with various low-pass filters (LPF), high-pass filters (HPF), etc. LPF helps in removing noise, blurring images, etc. HPF filters help in finding edges in images
OpenCV provides a function cv.filter2D() to convolve a kernel with an image.

Normalized Box Filter

To perform a smoothing operation we will apply a filter to our image. The most common type of filters are linear, in which an output pixel’s value .

g(i,j) = \sum_{k,l} f(i+k, j+l) h(k,l)
kernel = Mat::ones(5, 5, CV_8UC);/25
dst = filter2D(img,-1,kernel)
//or
blur = blur(img,dest,5)

// or you can use boxFilter
filter2D(InputArray src, OutputArray dst, int ddepth, InputArray kernel, Point anchor=Point(-1,-1), double delta=0, int borderType=BORDER_DEFAULT )

Median Filter

The median filter run through each element of the signal (in this case the image) and replace each pixel with the median of its neighboring pixels

median.jpg
medianBlur ( src, dst, i );//i is kernal size

Gaussian Filter

  • Probably the most useful filter (although not the fastest). Gaussian filtering is done by convolving each point in the input array with a Gaussian kernel and then summing them all to produce the output array.
  • Just to make the picture clearer, remember how a 1D Gaussian
../../../../_images/Smoothing_Tutorial_theory_gaussian_0.jpg
  • Assuming that an image is 1D, you can notice that the pixel located in the middle would have the biggest weight. The weight of its neighbors decreases as the spatial distance between them and the center pixel increases.
gaussian.jpg

Gaussian Filter Generation

G(x, y)=\frac{1}{2\pi \sigma ^{2}}e^{-\frac{x^{2}+y^{2}}{2\sigma ^{2}}}
void FilterCreation(double GKernel[][5]) 
{ 
    // intialising standard deviation to 1.0 
    double sigma = 1.0; 
    double r, s = 2.0 * sigma * sigma; 
  
    // sum is for normalization 
    double sum = 0.0; 
  
    // generating 5x5 kernel 
    for (int x = -2; x <= 2; x++) { 
        for (int y = -2; y <= 2; y++) { 
            r = sqrt(x * x + y * y); 
            GKernel[x + 2][y + 2] = (exp(-(r * r) / s)) / (M_PI * s); 
            sum += GKernel[x + 2][y + 2]; 
        } 
    } 
  
    // normalising the Kernel 
    for (int i = 0; i < 5; ++i) 
        for (int j = 0; j < 5; ++j) 
            GKernel[i][j] /= sum; 
} 
0.00296902    0.0133062    0.0219382    0.0133062    0.00296902    
0.0133062    0.0596343    0.0983203    0.0596343    0.0133062    
0.0219382    0.0983203    0.162103    0.0983203    0.0219382    
0.0133062    0.0596343    0.0983203    0.0596343    0.0133062    
0.00296902    0.0133062    0.0219382    0.0133062    0.00296902

Bilateral Filter

  • So far, we have explained some filters which main goal is to smooth an input image. However, sometimes the filters do not only dissolve the noise, but also smooth away the edges. To avoid this (at certain extent at least), we can use a bilateral filter.
  • In an analogous way as the Gaussian filter, the bilateral filter also considers the neighboring pixels with weights assigned to each of them. These weights have two components, the first of which is the same weighting used by the Gaussian filter. The second component takes into account the difference in intensity between the neighboring pixels and the evaluated one.
bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT )
Parameters:	
src – Source 8-bit or floating-point, 1-channel or 3-channel image.
dst – Destination image of the same size and type as src .
d – Diameter of each pixel neighborhood that is used during filtering. If it is non-positive, it is computed from sigmaSpace .
sigmaColor – Filter sigma in the color space. A larger value of the parameter means that farther colors within the pixel neighborhood (see sigmaSpace ) will be mixed together, resulting in larger areas of semi-equal color.
sigmaSpace – Filter sigma in the coordinate space. A larger value of the parameter means that farther pixels will influence each other as long as their colors are close enough (see sigmaColor ). When d>0 , it specifies the neighborhood size regardless of sigmaSpace . Otherwise, d is proportional to sigmaSpace .
bilateral.jpg