2014-07-15 16 views
5

Tôi dường như đã nhấn một bức tường trong dự án gần đây nhất của tôi liên quan đến việc tạo sóng/gợn trên một hình ảnh. Tôi làm một cái làm việc với các màu cơ bản trên một mạng lưới hoạt động hoàn hảo; heck, tôi thậm chí còn thêm sắc thái cho các màu sắc tùy thuộc vào chiều cao của sóng.Phát sóng bằng thuật toán "Hugo Elias"! Java

Tuy nhiên, mục tiêu tổng thể của tôi là làm cho hiệu ứng này hoạt động trên một hình ảnh như bạn sẽ thấy here. Tôi đã theo một thuật toán mà mọi người đang gọi phương pháp Hugo Elias (mặc dù idk nếu anh ta thực sự đã đưa ra thiết kế). Hướng dẫn của ông có thể được tìm thấy here!

Khi làm theo hướng dẫn đó, tôi đã tìm thấy mã giả của mình đầy thách thức để theo dõi. Ý tôi là khái niệm cho hầu hết các phần có ý nghĩa cho đến khi tôi nhấn phần bản đồ chiều cao trên một hình ảnh. Vấn đề là x và y offsets ném một ArrayIndexOutOfBoundsException do anh ta thêm bù đắp cho x hoặc y tương ứng. Nếu sóng quá lớn (tức là trong trường hợp của tôi 512), nó sẽ phát ra lỗi; tuy nhiên, nếu nó quá nhỏ, bạn không thể nhìn thấy nó.

Bất kỳ ý tưởng hoặc bản sửa lỗi nào để triển khai thuật toán của tôi đã cố gắng sẽ làm cho ngày của tôi. Cảm ơn bạn!

Vì vậy, tôi thực sự không thể tạo ra một phiên bản biên dịch có thể nhỏ và hiển thị vấn đề, nhưng tôi sẽ đưa ra ba phương pháp tôi đang sử dụng trong thuật toán. Cũng nên nhớ rằng buffer1 và buffer2 là các bản đồ chiều cao cho sóng (hiện tại và trước đó) và imgArray là một bufferedImage được biểu diễn bởi một int [img.getWidth() * img.getHeight()] đầy đủ các giá trị ARGB.

Anyways đây bạn đi:

public class WaveRippleAlgorithmOnImage extends JPanel implements Runnable, MouseListener, MouseMotionListener 
{ 
    private int[] buffer1; 
    private int[] buffer2; 

    private int[] imgArray; 
    private int[] movedImgArray; 

    private static double dampening = 0.96; 
    private BufferedImage img; 

    public WaveRippleAlgorithmOnImage(BufferedImage img) 
    { 
     this.img = img; 

     imgArray = new int[img.getHeight()*img.getWidth()]; 
     movedImgArray = new int[img.getHeight()*img.getWidth()]; 

     imgArray = img.getRGB(0, 0, 
       img.getWidth(), img.getHeight(), 
       null, 0, img.getWidth()); 

     //OLD CODE 
     /*for(int y = 0; y < img.getHeight(); y++) 
     { 
      for(int x = 0; x < img.getWidth(); x++) 
      { 
       imgArray[y][x] = temp[0 + (y-0)*img.getWidth() + (x-0)]; 
      } 
     }*/ 

     buffer1 = new int[img.getHeight()*img.getWidth()]; 
     buffer2 = new int[img.getHeight()*img.getWidth()]; 

     buffer1[buffer1.length/2] = (img.getWidth() <= img.getHeight() ? img.getWidth()/3 : img.getHeight()/3); 
     //buffer1[25][25] = 10; 

     back = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB); 

     this.addMouseListener(this); 
     this.addMouseMotionListener(this); 

    } 

    //<editor-fold defaultstate="collapsed" desc="Used Methods"> 
    @Override 
    public void run() 
    { 
     while(true) 
     { 
      this.update(); 
      this.repaint(); 
      this.swap(); 
     } 
    } 

    //Called from Thread to update movedImgArray prior to being drawn. 
    private void update() 
    { 
     //This is my attempt of trying to convert his code to java. 
     for (int i=img.getWidth(); i < imgArray.length - 1; i++) 
     { 
      if(i % img.getWidth() == 0 || i >= imgArray.length - img.getWidth()) 
       continue; 

      buffer2[i] = (
         ((buffer1[i-1]+ 
          buffer1[i+1]+ 
          buffer1[i-img.getWidth()]+ 
          buffer1[i+img.getWidth()]) >> 1)) - buffer2[i]; 

      buffer2[i] -= (buffer2[i] >> 5); 
     } 

     //Still my version of his code, because of the int[] instead of int[][]. 
     for (int y = 1; y < img.getHeight() - 2; y++) 
     { 
      for(int x = 1; x < img.getWidth() - 2; x++) 
      { 
       int xOffset = buffer1[((y)*img.getWidth()) + (x-1)] - buffer1[((y)*img.getWidth()) + (x+1)]; 
       int yOffset = buffer1[((y-1)*img.getWidth()) + (x)] - buffer1[((y+1)*img.getWidth()) + (x)]; 

       int shading = xOffset; 

       //Here is where the error occurs (after a click or wave started), because yOffset becomes -512; which in turn gets 
       //multiplied by y... Not good... -_- 
       movedImgArray[(y*img.getWidth()) + x] = imgArray[((y+yOffset)*img.getWidth()) + (x+xOffset)] + shading; 
      } 
     } 

     //This is my OLD code that kidna worked... 
     //I threw in here to show you how I was doing it before I switched to images. 
     /* 
     for(int y = 1; y < img.getHeight() - 1; y++) 
     { 
      for(int x = 1; x < img.getWidth() - 1; x++) 
      { 
       //buffer2[y][x] = ((buffer1[y][x-1] + 
       //buffer1[y][x+1] + 
       //buffer1[y+1][x] + 
       //buffer1[y-1][x])/4) - buffer2[y][x]; 
       buffer2[y][x] = ((buffer1[y][x-1] + 
         buffer1[y][x+1] + 
         buffer1[y+1][x] + 
         buffer1[y-1][x] + 
         buffer1[y + 1][x-1] + 
         buffer1[y + 1][x+1] + 
         buffer1[y - 1][x - 1] + 
         buffer1[y - 1][x + 1])/4) - buffer2[y][x]; 

       buffer2[y][x] = (int)(buffer2[y][x] * dampening); 
      } 
     }*/ 
    } 

    //Swaps buffers 
    private void swap() 
    { 
     int[] temp; 

     temp = buffer2; 
     buffer2 = buffer1; 
     buffer1 = temp; 
    } 

    //This creates a wave upon clicking. It also is where that 512 is coming from. 
    //512 was about right in my OLD code shown above, but helps to cause the Exeception now. 
    @Override 
    public void mouseClicked(MouseEvent e) 
    { 
     if(e.getX() > 0 && e.getY() > 0 && e.getX() < img.getWidth() && e.getY() < img.getHeight()) 
      buffer2[((e.getY())*img.getWidth()) + (e.getX())] = 512; 
    } 

    private BufferedImage back; 
    @Override 
    public void paintComponent(Graphics g) 
    { 
     super.paintComponent(g); 

     back.setRGB(0, 0, img.getWidth(), img.getHeight(), movedImgArray, 0, img.getWidth()); 
     g.drawImage(back, 0, 0, null); 
    } 
} 

Vì vậy, bất cứ đề nghị hoặc ý tưởng sẽ được đánh giá rất nhiều. Cảm ơn một lần nữa!

P.S. Dưới đây là hai hình ảnh của mã cũ hoạt động.

enter image description here enter image description here

+1

bạn có muốn thu hẹp mã và đặt câu hỏi không? –

+0

Như tôi đã nói, tôi thực sự đã cố gắng thu hẹp nó càng nhiều càng tốt để phù hợp với hướng dẫn SSCCE, nhưng thực sự tôi chỉ muốn hiểu rõ hơn về cách thực hiện phần hình ảnh của thuật toán của anh ấy. Tôi chỉ đặt các phương pháp mà tôi cảm thấy là quan trọng để sửa chữa nó. ^ _^ –

+0

+1 Đáng buồn thay, bài viết tuyệt vời này không còn nữa, ước gì tôi đã lưu nó ra khỏi dòng, nhưng tôi thì không. Chính nhờ thuật toán này mà tôi đã nhận ra và thực hiện thuật toán mờ ngây ngây của mình (nghĩ nhanh hơn Gaussian), sau đó tiếp tục khám phá "blur box 3-pass tách" - một cách tiếp cận Gaussian nhanh hơn nhiều. – Nolo

Trả lời

2

Nhìn vào giả ban đầu của tôi, tôi giả sử Array Out Of Bounds lỗi đang xảy ra khi bạn cố gắng tìm kiếm các kết cấu dựa trên bù đắp. Vấn đề xảy ra bởi vì khúc xạ trong nước cho phép chúng ta nhìn thấy bên ngoài của kết cấu.

for every pixel (x,y) in the buffer 

    Xoffset = buffer(x-1, y) - buffer(x+1, y) 
    Yoffset = buffer(x, y-1) - buffer(x, y+1) 

    Shading = Xoffset 

    t = texture(x+Xoffset, y+Yoffset) // Array out of bounds? 

    p = t + Shading 

    plot pixel at (x,y) with colour p 

end loop 

Cách khắc phục điều này chỉ đơn giản là để kẹp tọa độ kết cấu hoặc để chúng quấn. Ngoài ra, nếu bạn thấy rằng lượng khúc xạ là quá nhiều, bạn có thể giảm nó bằng cách dịch chuyển bit các giá trị Xoffset và Yoffset một chút.

int clamp(int x, int min, int max) 
{ 
    if (x < min) return min; 
    if (x > max) return max; 
    return x; 
} 

int wrap(int x, int min, int max) 
{ 
    while (x<min) 
     x += (1+max-min); 

    while (x>max) 
     x -= (1+max-min); 

    return x; 
} 


for every pixel (x,y) in the buffer 

    Xoffset = buffer(x-1, y) - buffer(x+1, y) 
    Yoffset = buffer(x, y-1) - buffer(x, y+1) 

    Shading = Xoffset 

    Xoffset >>= 1        // Halve the amount of refraction 
    Yoffset >>= 1        // if you want. 

    Xcoordinate = clamp(x+Xoffset, 0, Xmax) // Use clamp() or wrap() here 
    Ycoordinate = clamp(y+Yoffset, 0, Ymax) // 
    t = texture(Xcoordinate, Ycoordinate) 

    p = t + Shading 

    plot pixel at (x,y) with colour p 

end loop