绘制填充多维数组

时间:2015-05-03 17:21:36

标签: java arrays algorithm multidimensional-array

我的目标是"油漆填充"人们可能会在许多图像编辑程序中看到的功能。也就是说,给定一个屏幕(由二维颜色数组表示),一个点和一个新颜色,填充周围区域,直到颜色从原始颜色变化。

我已经为2D数组实现了它,这里是代码:

public static void paint (int [][] screen,int OldColor,int NewColor,int y,int x)
    {   
        if(y>screen.length-1||y<0||x>screen[0].length||x<0||screen[y][x]!=OldColor)
          return;
        screen[y][x]=NewColor;
        paint(screen,OldColor,NewColor,y-1,x);
        paint(screen, OldColor, NewColor, y+1, x);
        paint(screen, OldColor, NewColor, y, x-1);
        paint(screen, OldColor, NewColor, y, x+1);
    }

但我想为3D等多维数组实现它,可以通过添加:

来解决
paint(screen, OldColor, NewColor, y, x,z-1);
paint(screen, OldColor, NewColor, y, x,z+1);

但是想象一下阵列是100 D ......我怎么能解决这个问题?

3 个答案:

答案 0 :(得分:2)

感谢@ Spektre关于积分结构的建议,我设法编写了一个简单的N维洪水填充。

我使用char矩阵来简化编码,而不是图像。将其更改为int作为颜色值以及其他矩阵的数据类型中的一些更改,将为您执行100D:)

在这个简单的程序中,我尝试用“B”填充所有“A”,并填充所有连接的char值,类似于蚂蚁巢。您可以使用其他图层跟踪A之间的连接以查看填充路径。

在第二张图片中(Im1,添加有意添加了B,然后在其上方添加了一个无法从填充点访问的A),它也可以正常工作。

package test;

import java.awt.Point;
import java.util.LinkedList;
import java.util.Queue;

/**
 *
 * @author Pasban
 */
public class NDFloodFill {

    public int N1 = 8; // width
    public int N2 = 6; // height
    public int N = 3; // number of layers
    public ImageData[] images = new ImageData[N];

    public static void main(String[] args) {
        NDFloodFill ndf = new NDFloodFill();

        //print original data
        //ndf.print();
        ndf.fill(0, 0, 0, 'A', 'B');
        ndf.print();
    }

    public NDFloodFill() {
        String im0 = ""
                + "AA...A..\n"
                + ".....A..\n"
                + "....AA..\n"
                + "........\n"
                + "........\n"
                + "...AA.AA";

        String im1 = ""
                + ".A..A...\n"
                + "....B...\n"
                + "..AAA...\n"
                + "........\n"
                + "...AA.A.\n"
                + "..AA..A.";

        String im2 = ""
                + ".A......\n"
                + ".AA.....\n"
                + "..A.....\n"
                + "..A.....\n"
                + "..A.AAA.\n"
                + "..A.....";

        images[0] = new ImageData(im0, 0);
        images[1] = new ImageData(im1, 1);
        images[2] = new ImageData(im2, 2);
    }

    private void print() {
        for (int i = 0; i < N; i++) {
            System.out.println(images[i].getImage());
        }
    }

    private void fill(int x, int y, int index, char original, char fill) {
        Queue<PixFill> broadCast = new LinkedList<>();
        broadCast.add(new PixFill(new Point(x, y), index));
        for (int i = 0; i < N; i++) {
            images[i].reset();
        }
        while (!broadCast.isEmpty()) {
            PixFill pf = broadCast.remove();
            Queue<PixFill> newPoints = images[pf.index].fillArea(pf.xy, original, fill);
            if (newPoints != null) {
                broadCast.addAll(newPoints);
            }
        }
    }

    public class PixFill {

        Point xy;
        int index;

        public PixFill(Point xy, int index) {
            this.xy = xy;
            this.index = index;
        }

        @Override
        public String toString() {
            return this.xy.x + " : " + this.xy.y + " / " + this.index;
        }
    }

    public class ImageData {

        char[][] pix = new char[N1][N2];
        boolean[][] done = new boolean[N1][N2];
        int index;

        public ImageData(String image, int index) {
            int k = 0;
            this.index = index;
            for (int y = 0; y < N2; y++) { // row
                for (int x = 0; x < N1; x++) { // column
                    pix[x][y] = image.charAt(k++);
                }
                k++; // ignoring the \n char
            }
        }

        public void reset() {
            for (int y = 0; y < N2; y++) {
                for (int x = 0; x < N1; x++) {
                    done[x][y] = false;
                }
            }
        }

        public String getImage() {
            String ret = "";
            for (int y = 0; y < N2; y++) { // row
                String line = "";
                for (int x = 0; x < N1; x++) { // column
                    line += pix[x][y];
                }
                ret += line + "\n";
            }
            return ret;
        }

        public Queue<PixFill> fillArea(Point p, char original, char fill) {
            if (!(p.x >= 0 && p.y >= 0 && p.x < N1 && p.y < N2) || !(pix[p.x][p.y] == original)) {
                return null;
            }

            // create queue for efficiency
            Queue<Point> list = new LinkedList<>();
            list.add(p);

            // create broadcasting to spread filled points to othwer layers
            Queue<PixFill> broadCast = new LinkedList<>();
            while (!list.isEmpty()) {
                p = list.remove();
                if ((p.x >= 0 && p.y >= 0 && p.x < N1 && p.y < N2) && (pix[p.x][p.y] == original) && (!done[p.x][p.y])) {
                    //fill
                    pix[p.x][p.y] = fill;
                    done[p.x][p.y] = true;
                    //look for neighbors

                    list.add(new Point(p.x - 1, p.y));
                    list.add(new Point(p.x + 1, p.y));
                    list.add(new Point(p.x, p.y - 1));
                    list.add(new Point(p.x, p.y + 1));
                    // there will not be a duplicate pixFill as we always add the filled points that are not filled yet,
                    // so duplicate fill will never happen, so do pixFill :)

                    // add one for upper layer
                    if (index < N - 1) {
                        broadCast.add(new PixFill(p, index + 1));
                    }

                    // add one for lower layer
                    if (index > 0) {
                        broadCast.add(new PixFill(p, index - 1));
                    }

                    //layers out of range <0, N> can be filtered
                }
            }

            return broadCast;
        }
    }
}

答案 1 :(得分:1)

  1. 避免递归函数!请使用队列来填充图像
  2. 您要在哪个图片上开始填充?
  3. 检查第i张图像上的图像颜色,并将该点添加到列表中。
  4. 稍后检查您是否可以从存储的点向上或向下移动到(i + 1) th 或(i-1) th 图像并重复此过程从那里。
  5. 这是一个原创的想法,但你可能需要的就是这个。

    另外,您需要为每个级别设置一个数组,以检查是否已为该图像填充了该像素。所以你将摆脱无限循环:)

    使用队列检查此洪水填充: Flood Fill Optimization: Attempting to Using a Queue

答案 2 :(得分:0)

Salivan对他的建议是正确的,但他没有理解你所问的真正问题。 对于任意维度,您需要将点结构从pnt.x,pnt.y,pnt.z等符号更改为pnt[0],pnt[1],pnt[2],然后几乎没有办法处理此问题:

  1. 用零填充的固定限制大小

    • 所以处理所有像10 D(如果10 D是使用的最大维度)
    • 并用零填充未使用的轴
    • 这是一个缓慢的丑陋,痛苦地要求记忆和限制最大维度
  2. 使用嵌套for循环(用于初始化等)

    • 看这里rasterize and fill a hypersphere
    • 许多多维操作需要嵌套循环
    • 这个有任意深度
    • 您可以将其视为多位数的增量函数
    • 其中每个数字代表空间中的轴
  3. 在N-D中使用普通for循环生成邻居

    // point variables
    int p[N],q[N];
    // here you have actual point p and want to find its neighbors
    for (int i=0;i<N;i++)
     {
     for (int j=0;i<N;i++) q[j]=p[j]; // copy point
     q[i]--;
     // add q to flood fill
     q[i]+=2;
     // add q to flood fill
     }