JavaScript实现区域生长算法

这篇博客介绍了如何使用JavaScript实现区域生长算法,该算法应用于图像处理。首先通过canvas获取图像数据,然后基于人工选择的种子点进行生长。生长规则是判断当前点与种子点灰度差值百分比是否小于给定阈值,满足条件则加入生长区域。最终将生长结果绘制到canvas上。示例代码展示了从一维数组生成二维数组、区域生长函数等关键步骤,并在实际图像上应用了区域生长算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

区域生长算法的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
      // 复制一份图像数据,格式为[r1, g1, b1, a1, r2, g2, b2, a2...]
      let copy_data = [...imgData]
      // 提取得到二维矩阵
      let imgMatrix = twoDimArrayFrom(copy_data, height, width, 4)
      // 进行区域生长
      let {seed_number, mask} = regionGrow(imgMatrix, [118, 54], 0.05)
      // 基于得到的mask修改imgData中的数据,并绘制图像
      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>
原始图片

图片大小236*236

浏览器显示结果

结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值