-
Notifications
You must be signed in to change notification settings - Fork 812
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[FEAT] Add dilate and erode operations to Tensor #1136
base: main
Are you sure you want to change the base?
[FEAT] Add dilate and erode operations to Tensor #1136
Conversation
// Only include values where the kernel has a value | ||
// of 1. | ||
// Rather than multiply against this value, we use | ||
// the if check to reduce the size of the array. | ||
const kernelValue = kernel[kernelRowOffset + paddingSize.height][kernelColOffset + paddingSize.width]; | ||
if (kernelValue === 1) { | ||
kernelValues.push(data[neighborIndex] * kernelValue); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Originally I was not using the if statement, and utilising the fact that a kernel contains either 0
or 1
, however that meant that kernelValues
array would be bigger than it needs to be.
Also, erode
wouldn't work properly because 0
is always the minimum value.
function validateKernel(kernelSize) { | ||
let kernel; | ||
if (typeof kernelSize === 'object' && 'width' in kernelSize && 'height' in kernelSize) { | ||
// This is a Size object, so no conversion required. | ||
kernel = kernelSize; | ||
} else if (typeof kernelSize === 'number' && Number.isInteger(kernelSize)) { | ||
// A single whole number is assumed as the width and height. | ||
kernel = { width: kernelSize, height: kernelSize }; | ||
} else if (Array.isArray(kernelSize) && kernelSize.length === 2 && kernelSize.every(Number.isInteger)) { | ||
// An array of two values is assumed as width then height. | ||
kernel = { width: kernelSize[0], height: kernelSize[1] }; | ||
} else { | ||
throw new Error("Invalid kernel size."); | ||
} | ||
|
||
if (kernel.width % 2 === 0 || kernel.height % 2 === 0) { | ||
throw new Error("Kernel size must be odd"); | ||
} | ||
|
||
return kernel; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The purpose of this function is to help users with passing in kernel values.
To get a 3x3 kernel to the erode
function we can do this:
tensor.erode(3)
tensor.erode([3, 3])
tensor.erode({ width: 3, height: 3 })
Most likely we want a symmetrical kernel, and it's easier to just pass in a single number.
This PR is inspired by the functionality of OpenCV.
With this, we can create a kernel that is operated over each element of the
data
array and performs some calculation.For this PR, we only have
dilate
anderode
.I decided to set these functions to
async
, despite that making the chaining a bit clunkier, since these functions are often used together.Explanation
kernel
This is an array of 0s and 1s that will be applied to each element of the
data
array, 1 by 1.There are multiple shapes supported in this PR, they are:
RECT
,CROSS
,ELLIPSE
.Consider a 5x5 kernel for each shape:
RECT
:CROSS
:ELLIPSE
:The element we are checking will be in the centre, and then it will apply this kernel to all those values around it.
Any value of 1 will be included and 0 will be discarded.
dilate
Once we have a list of values for that element, we will apply a
Math.max
to return the biggest value of these.Consider this Tensor.
If we were to apply
CROSS
with a kernel size of 3x3, then the first iteration would return the values of[1, 2, 6]
. This is because the top and left side of the kernel are off the edge.When the loop gets to the value of
13
, the extracted values would be[8, 12, 13, 14, 18]
.Finally, the value in each instance will be replaced with the maximum value.
Again, in the case of the first element, that would be
6
and for the centre element, that would be replaced with18
.erode
This works in the exact same way as
dilate
, however it will apply theMath.min
to the elements instead.