Home  >  Article  >  Web Front-end  >  javascript image processing—edge gradient calculation function_javascript skills

javascript image processing—edge gradient calculation function_javascript skills

WBOY
WBOYOriginal
2016-05-16 17:43:461484browse
Foreword

In the previous article , we explained the expansion and erosion functions in image processing. This article will do the edge gradient calculation function.

Edge of the image

How are the edges of images expressed mathematically?

How intensity changes in an edge

On the edges of the image, adjacent pixel values ​​should change significantly. In mathematics, derivatives are a way to express the speed of change. Large changes in gradient values ​​indicate significant changes in the content of the image.

To explain with a more vivid image, suppose we have a one-dimensional graph. The "jump" in the gray value in the image below indicates the existence of an edge:

 Intensity Plot for an edge

Using first-order differential derivation, we can more clearly see the existence of the edge "jump" (shown here as a high peak):

 First derivative of Intensity - Plot for an edge

From this we can conclude that edges can be found by locating pixels with gradient values ​​greater than those of the neighborhood.

Approximate gradient

For example, when the core is 3.

First calculate the approximate derivative in the x direction:

G_{x} = begin{bmatrix}-1 & 0 &  1 \-2 & 0 &  2 \-1 & 0 &  1end{bmatrix} * I

Then calculate the approximate derivative for the y direction:

G_{y} = begin{bmatrix}-1 & -2 & -1 </P> & 0 & 0 \ 1 &  2 &  1end{bmatrix} * I

Then calculate the gradient:

G = sqrt{ G_{x}^{2}   G_{y}^{2} }

Of course you can also write:

G = |G_{x}|   |G_{y}|

Function implementation
The code is as follows:


var Sobel = function(__src, __xorder, __yorder, __size, __borderType, __dst){
(__src && (__xorder ^ __yorder)) || error(arguments.callee, IS_UNDEFINED_OR_NULL/* {line} * /);
if(__src.type && __src.type === "CV_GRAY"){
var kernel1,
kernel2,
height = __src.row,
width = __src. col,
dst = __dst || new Mat(height, width, CV_16I, 1),
dstData = dst.data
size = __size || 3;
switch(size){
case 1:
size = 3;
case 3:
if(__xorder){
kernel = [-1, 0, 1,
-2, 0, 2,
-1, 0, 1
];
}else if(__yorder){
kernel = [-1, -2, -1,
, 0, 0,
, 2 , 1
];
}
break;
case 5:
if(__xorder){
kernel = [-1, -2, 0, 2, 1,
-4, -8, 0, 8, 4,
-6,-12, 0,12, 6,
-4, -8, 0, 8, 4,
-1, - 2, 0, 2, 1
];
}else if(__yorder){
kernel = [-1, -4, -6, -4, -1,
-2, - 8,-12, -8, -2,
, 0, 0, 0, 0,
, 8, 12, 8, 2,
, 4, 6, 4, 1
] ;
}
break;
default:
error(arguments.callee, UNSPPORT_SIZE/* {line} */);

}

GRAY216IC1Filter(__src , size, height, width, kernel, dstData, __borderType);

}else{
error(arguments.callee, UNSPPORT_DATA_TYPE/* {line} */);
}
return dst;
};


Only Sobel operators with kernel sizes of 3 and 5 are provided here. The main reason is that the calculation of kernels of 7 or above is relatively slow.
Output a single-channel 16-bit signed integer matrix. The code is as follows:

function GRAY216IC1Filter(__src, size, height, width, kernel, dstData, __borderType){
var start = size >> 1;

var withBorderMat = copyMakeBorder(__src, start, start, 0, 0, __borderType);

var mData = withBorderMat.data,
mWidth = withBorderMat.col;

var i, j, y, x, c;
var newValue, nowX, offsetY, offsetI;

for(i = height; i--;){
offsetI = i * width;
for(j = width; j- -;){
newValue = 0;
for(y = size; y--;){
offsetY = (y i) * mWidth;
for(x = size; x--; ){
nowX = x j;
newValue = (mData[offsetY nowX] * kernel[y * size x]);
}
}
dstData[j offsetI] = newValue;
}
}
}

Then give the kernel and matrix to this filter, and it’s OK.

The reason for making this filter independent is that it can be used for other similar calculation edge functions, such as Laplacian and Scharr operators.

Convert to unsigned 8-bit integer

Since the Sobel operator calculates a 16-bit signed integer and cannot be displayed as a picture, we need a function to convert it into an unsigned 8-bit integer matrix.

The convertScaleAbs function takes the absolute value of each element and puts it into the Int8Array array. Since numbers greater than 255 will be automatically converted to 255 during assignment, and numbers less than 0 will be automatically converted to 0, so We don't need to make a function to take care of this work.

Copy code The code is as follows:

function convertScaleAbs(__src, __dst){
__src || error(arguments.callee, IS_UNDEFINED_OR_NULL/* {line} */);
var height = __src.row,
width = __src.col,
channel = __src.channel,
sData = __src.data;

if(!__dst){
if(channel === 1)
dst = new Mat(height, width, CV_GRAY);
else if(channel === 4)
dst = new Mat(height, width, CV_RGBA);
else
dst = new Mat(height, width, CV_8I, channel);
}else{
dst = __dst;
}

var dData = dst.data;

var i, j, c;

for(i = height; i--; ){
for(j = width * channel; j--;){
dData[i * width * channel j] = Math.abs(sData[i * width * channel j]);
}
}

return dst;
}
Merge values ​​proportionally

We also need a function to superimpose the x-direction gradient calculation value and the y-direction gradient calculation value.

Copy code The code is as follows:

var addWeighted = function(__src1, __alpha, __src2, __beta , __gamma, __dst){
(__src1 && __src2) || error(arguments.callee, IS_UNDEFINED_OR_NULL/* {line} */);
var height = __src1.row,
width = __src1.col ,
alpha = __alpha || 0,
beta = __beta || 0,
channel = __src1.channel,
gamma = __gamma || 0;
if(height !== __src2 .row || width !== __src2.col || channel !== __src2.channel){
error(arguments.callee, "Src2 must be the same size and channel number as src1!"/* {line} */);
return null;
}

if(!__dst){
if(__src1.type.match(/CV_d /))
dst = new Mat( height, width, __src1.depth(), channel);
else
dst = new Mat(height, width, __src1.depth());
}else{
dst = __dst;
}

var dData = dst.data,
s1Data = __src1.data,
s2Data = __src2.data;

var i;

for (i = height * width * channel; i--;)
dData[i] = __alpha * s1Data[i] __beta * s2Data[i] gamma;

return dst;
};

This function is very simple. It actually just adds the corresponding elements of two matrices in a fixed ratio. Rendering

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn