区域生长算法的js版本
1、主要内容
- 通过canvas进行图像的绘制
- 首先获取图像数据并用二维数组表示图像矩阵,其次基于人工选取的种子点进行生长,最后将生长所得的mask绘制在canvas上
- 区域生长实现原理:选取初始种子点,遍历种子点上下左右4邻域(也可以8邻域),基于生长准则(这里是根据领域灰度和种子点灰度差值百分比小于给定的阈值region_threshold)进行生长,如果满足准则那就将领域点加入种子列表中并将对应的mask置为1’
- 整体类似一个队列,种子列表后不断添加满足条件的点,种子列表前不断弹出遍历过的种子点,直到种子列表清空
2、定义处理数组的函数和区域生长算法
function twoDimArrayInit(height, width, value=0) {
let output = []
for(let i = 0; i < height; i++){
let temp = []
for(let j = 0; j < width; j++){
temp[j] = value
}
output[i] = temp
}
return output
}
function twoDimArrayFrom(array, height, width, step) {
if (array.length !== height * width * step) {
throw Error('请确认数组尺寸')
}
let output = []
for(let i = 0; i < height; i++){
let temp = []
for(let j = 0; j < width; j++){
temp[j] = array[(i * width + j) * step]
}
output[i] = temp
}
return output
}
function arrayAdd(a, b) {
if (a.length !== b.length) {
throw Error('数组长度不一致')
}
let output = []
for (let i = 0; i < a.length; i++) {
if (typeof a[i] !== 'number' || typeof b[i] !== 'number') {
throw Error('请输入一维数组')
} else {
output[i] = a[i] + b[i]
}
}
return output
}
function arraySet(array, index, value) {
array[index[0]][index[1]] = value
}
function arrayGet(array, index) {
return array[index[0]][index[1]]
}
function regionGrow(array, seed, threshold) {
let height = array.length
let width = array[0].length
let neighbors = [[-1, 0], [1, 0], [0, -1], [0, 1]]
let region_threshold = threshold
let seed_number = 0
let seed_list = [seed]
let mask = twoDimArrayInit(height, width)
while (seed_list.length > 0) {
let current_seed = seed_list.shift()
arraySet(mask, current_seed, 1)
for (let i = 0; i < 4; i++) {
let neighbor = arrayAdd(neighbors[i], current_seed)
if (neighbor[0] > 0 && neighbor[0] < height && neighbor[1] > 0 && neighbor[1] < width) {
let current_diff = Math.abs((arrayGet(array, neighbor) - arrayGet(array, current_seed)) / arrayGet(array, current_seed))
if (current_diff < region_threshold && arrayGet(mask, neighbor) !== 1) {
arraySet(mask, neighbor, 1)
seed_list.push(neighbor)
}
}
}
seed_number++
}
return {seed_number, mask}
}
3、完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<canvas id="myCanvas" width="600" height="600">
</canvas>
<script>
function twoDimArrayInit(height, width, value=0) {
let output = []
for(let i = 0; i < height; i++){
let temp = []
for(let j = 0; j < width; j++){
temp[j] = value
}
output[i] = temp
}
return output
}
function twoDimArrayFrom(array, height, width, step) {
if (array.length !== height * width * step) {
throw Error('请确认数组尺寸')
}
let output = []
for(let i = 0; i < height; i++){
let temp = []
for(let j = 0; j < width; j++){
temp[j] = array[(i * width + j) * step]
}
output[i] = temp
}
return output
}
function arrayAdd(a, b) {
if (a.length !== b.length) {
throw Error('数组长度不一致')
}
let output = []
for (let i = 0; i < a.length; i++) {
if (typeof a[i] !== 'number' || typeof b[i] !== 'number') {
throw Error('请输入一维数组')
} else {
output[i] = a[i] + b[i]
}
}
return output
}
function arraySet(array, index, value) {
array[index[0]][index[1]] = value
}
function arrayGet(array, index) {
return array[index[0]][index[1]]
}
function regionGrow(array, seed, threshold) {
let height = array.length
let width = array[0].length
let neighbors = [[-1, 0], [1, 0], [0, -1], [0, 1]]
let region_threshold = threshold
let seed_number = 0
let seed_list = [seed]
let mask = twoDimArrayInit(height, width)
while (seed_list.length > 0) {
let current_seed = seed_list.shift()
arraySet(mask, current_seed, 1)
for (let i = 0; i < 4; i++) {
let neighbor = arrayAdd(neighbors[i], current_seed)
if (neighbor[0] > 0 && neighbor[0] < height && neighbor[1] > 0 && neighbor[1] < width) {
let current_diff = Math.abs((arrayGet(array, neighbor) - arrayGet(array, current_seed)) / arrayGet(array, current_seed))
if (current_diff < region_threshold && arrayGet(mask, neighbor) !== 1) {
arraySet(mask, neighbor, 1)
seed_list.push(neighbor)
}
}
}
seed_number++
}
return {seed_number, mask}
}
let my_canvas = document.querySelector('#myCanvas')
let ctx = my_canvas.getContext('2d')
let img = new Image()
img.src = './test.png'
img.onload = function () {
let height = img.height
let width = img.width
ctx.drawImage(img, 0, 0)
let imgData_obj = ctx.getImageData(0, 0, width, height)
let imgData = imgData_obj.data
let copy_data = [...imgData]
let imgMatrix = twoDimArrayFrom(copy_data, height, width, 4)
let {seed_number, mask} = regionGrow(imgMatrix, [118, 54], 0.05)
for (let i = 0; i < 236; i++) {
for (let j = 0; j < 236; j++) {
imgData[(i * 236 + j) * 4] = mask[i][j] * 255;
imgData[(i * 236 + j) * 4 + 1] = mask[i][j] * 255;
imgData[(i * 236 + j) * 4 + 2] = mask[i][j] * 255;
}
}
ctx.putImageData(imgData_obj, 300, 0);
}
</script>
</body>
</html>
原始图片

浏览器显示结果
