图像处理之基于泛红算法的二值图像内部区域填充

简介: 图像处理之基于泛红算法的二值图像内部区域填充

图像处理之基于泛红算法的二值图像内部区域填充


一:基本原理


在二值图像处理中有个常用的操作叫做Hole Fill意思是填充所有封闭区域的内部,这种算法在二值图像基础上的对象识别与提取有很大作用。基于泛红填充算法实现二值图像内部区域填充是一直快速填充算法。




因为泛红填充通常需要指定从一个点开始,填满整个封闭区域,对一张二值图像来说,我们最好的办法是把背景当成一个封闭区域,从上向下从左到右查到第一个背景像素点,基于扫描线算法实现全部填充成一个非0,255之外的一个像素值,我这里是127。填充完成之后再一次从左到右,从上向下检查每个像素值如果是127的则为背景像素,否则全部设为前景像素。这样就完成二值图像每个封闭区域内部填充。




二:算法实现步骤


1.      读取二值图像


2.      基于扫描线算法对背景像素区域进行泛红填充,填充值为127


3.      循环每个像素对值为127的设为背景像素,其它值设为前景像素


4.      返回填充之后的二值图像像素数据


三:代码实现

package com.gloomyfish.basic.imageprocess;
 
public class FloodFillAlgorithm extends AbstractByteProcessor {
  private int foreground;
  private int background;
  private byte[] data;
  private int width;
  private int height;
 
  // stack data structure
  private int maxStackSize = 500; // will be increased as needed
  private int[] xstack = new int[maxStackSize];
  private int[] ystack = new int[maxStackSize];
  private int stackSize;
 
  public FloodFillAlgorithm(byte[] data) {
    this.data = data;
    this.foreground = 0;
    this.background = 255 - this.foreground;
  }
 
  public int getColor(int x, int y) {
    int index = y * width + x;
    return data[index] & 0xff;
  }
 
  public void setColor(int x, int y, int newColor) {
    int index = y * width + x;
    data[index] = (byte) newColor;
  }
 
  public void floodFillScanLineWithStack(int x, int y, int newColor, int oldColor) {
    if (oldColor == newColor) {
      System.out.println("do nothing !!!, filled area!!");
      return;
    }
    emptyStack();
 
    int y1;
    boolean spanLeft, spanRight;
    push(x, y);
 
    while (true) {
      x = popx();
      if (x == -1)
        return;
      y = popy();
      y1 = y;
      while (y1 >= 0 && getColor(x, y1) == oldColor)
        y1--; // go to line top/bottom
      y1++; // start from line starting point pixel
      spanLeft = spanRight = false;
      while (y1 < height && getColor(x, y1) == oldColor) {
        setColor(x, y1, newColor);
        if (!spanLeft && x > 0 && getColor(x - 1, y1) == oldColor)// just
                                      // keep
                                      // left
                                      // line
                                      // once
                                      // in
                                      // the
                                      // stack
        {
          push(x - 1, y1);
          spanLeft = true;
        } else if (spanLeft && x > 0 && getColor(x - 1, y1) != oldColor) {
          spanLeft = false;
        }
        if (!spanRight && x < width - 1 && getColor(x + 1, y1) == oldColor) // just
                                          // keep
                                          // right
                                          // line
                                          // once
                                          // in
                                          // the
                                          // stack
        {
          push(x + 1, y1);
          spanRight = true;
        } else if (spanRight && x < width - 1 && getColor(x + 1, y1) != oldColor) {
          spanRight = false;
        }
        y1++;
      }
    }
 
  }
 
  private void emptyStack() {
    while (popx() != -1) {
      popy();
    }
    stackSize = 0;
  }
 
  final void push(int x, int y) {
    stackSize++;
    if (stackSize == maxStackSize) {
      int[] newXStack = new int[maxStackSize * 2];
      int[] newYStack = new int[maxStackSize * 2];
      System.arraycopy(xstack, 0, newXStack, 0, maxStackSize);
      System.arraycopy(ystack, 0, newYStack, 0, maxStackSize);
      xstack = newXStack;
      ystack = newYStack;
      maxStackSize *= 2;
    }
    xstack[stackSize - 1] = x;
    ystack[stackSize - 1] = y;
  }
 
  final int popx() {
    if (stackSize == 0)
      return -1;
    else
      return xstack[stackSize - 1];
  }
 
  final int popy() {
    int value = ystack[stackSize - 1];
    stackSize--;
    return value;
  }
 
  @Override
  public void process(int width, int height) {
    this.width = width;
    this.height = height;
 
    for (int y = 0; y < height; y++) {
      if (getColor(0, y) == background)
        floodFillScanLineWithStack(0, y, 127, 255);
      if (getColor(width - 1, y) == background)
        floodFillScanLineWithStack(width - 1, y, 127, 255);
    }
    for (int x = 0; x < width; x++) {
      if (getColor(x, 0) == background)
        floodFillScanLineWithStack(x, 0, 127, 255);
      if (getColor(x, height - 1) == background)
        floodFillScanLineWithStack(x, height - 1, 127, 255);
    }
    
    int p = 0;
    for (int i = 0; i < data.length; i++) {
      p = data[i]&0xff;
      if (p == 127)
        data[i] = (byte)255;
      else
        data[i] = (byte)0;
    }
  }
 
}

四:运行结果

使用代码,要先读取二值图像数据到data字节数组

FloodFillAlgorithm ffa = new FloodFillAlgorithm(data);
    ffa.process(width, height);
相关文章
|
19天前
|
算法 计算机视觉
图像处理之积分图应用四(基于局部均值的图像二值化算法)
图像处理之积分图应用四(基于局部均值的图像二值化算法)
25 0
|
16天前
|
机器学习/深度学习 算法 测试技术
如何应对缺失值带来的分布变化?探索填充缺失值的最佳插补算法
该文探讨了缺失值插补的不同方法,比较了它们恢复数据真实分布的效果。文章指出,处理插补尤其在小样本或复杂数据时是个挑战,需要选择能适应数据分布变化的方法。文中介绍了完全随机缺失(MCAR)、随机缺失(MAR)和非随机缺失(MNAR)三种机制,并以一个简单的例子展示了数据分布变化。文章通过比较均值插补、回归插补和高斯插补,强调了高斯插补在重现数据分布方面更优。评估插补方法时,不应仅依赖于RMSE,而应关注分布预测,使用如能量距离这样的指标。此外,即使在随机缺失情况下,数据分布也可能因模式变化而变化,需要考虑适应这些变化的插补方法。
28 2
|
2天前
|
算法 计算机视觉
基于Chan-Vese算法的图像边缘提取matlab仿真
**算法预览展示了4幅图像,从边缘检测到最终分割,体现了在matlab2022a中应用的Chan-Vese水平集迭代过程。核心代码段用于更新水平集并显示迭代效果,最后生成分割结果及误差曲线。Chan-Vese模型(2001)是图像分割的经典方法,通过最小化能量函数自动检测平滑区域和清晰边界的图像分割,适用于复杂环境,广泛应用于医学影像和机器视觉。**
|
8天前
|
机器学习/深度学习 人工智能 算法
【CVPR2024】面向StableDiffusion的编辑算法FreePromptEditing,提升图像编辑效果
近日,阿里云人工智能平台PAI与华南理工大学贾奎教授团队合作在深度学习顶级会议 CVPR2024 上发表 FPE(Free-Prompt-Editing) 算法,这是一种面向StableDiffusion的图像编辑算法。在这篇论文中,StableDiffusion可用于实现图像编辑的本质被挖掘,解释证明了基于StableDiffusion编辑的算法本质,并基于此设计了新的图像编辑算法,大幅度提升了图像编辑的效率。
|
9天前
|
机器学习/深度学习 人工智能 自然语言处理
【CVPR2024】阿里云人工智能平台PAI图像编辑算法论文入选CVPR2024
近期,阿里云人工智能平台PAI发表的图像编辑算法论文在CVPR-2024上正式亮相发表。论文成果是阿里云与华南理工大学贾奎教授领衔的团队共同研发。此次入选标志着阿里云人工智能平台PAI自主研发的图像编辑算法达到了先进水平,赢得了国际学术界的认可。在阿里云人工智能平台PAI算法团队和华南理工大学的老师学生们一同的坚持和热情下,将阿里云在图像生成与编辑领域的先进理念得以通过学术论文和会议的形式,向业界传递和展现。
|
15天前
|
存储 编解码 算法
C#.NET逃逸时间算法生成分形图像的毕业设计完成!晒晒功能
该文介绍了一个使用C#.NET Visual Studio 2008开发的程序,包含错误修复的Julia、Mandelbrot和优化过的Newton三种算法,生成色彩丰富的分形图像。作者改进了原始算法的效率,将内层循环的画点操作移至外部,提升性能。程序提供五种图形模式,支持放大缩小及颜色更新,并允许用户自定义画布大小以调整精度。还具备保存为高质JPG的功能。附有四张示例图片展示生成的分形效果。
|
17天前
|
存储 算法 数据挖掘
python5种算法模拟螺旋、分层填充、递归、迭代、分治实现螺旋矩阵ll【力扣题59】
python5种算法模拟螺旋、分层填充、递归、迭代、分治实现螺旋矩阵ll【力扣题59】
|
17天前
|
存储 机器学习/深度学习 算法
python 五种算法转置后翻转、层次旋转、递归分块、一次性旋转、环状替换 实现旋转图像【力扣题48】
python 五种算法转置后翻转、层次旋转、递归分块、一次性旋转、环状替换 实现旋转图像【力扣题48】
|
5天前
|
机器学习/深度学习 算法 数据挖掘
机器学习之聚类——MeanShift算法和图像矢量量化
机器学习之聚类——MeanShift算法和图像矢量量化
8 0
|
13天前
|
编解码 算法 PyTorch
超好用!图像去雾算法C2PNet介绍与使用指南
超好用!图像去雾算法C2PNet介绍与使用指南