2017-08-16 47 views
0

我想將兩個圖像疊加在一起。背景和前景。前景被拼接在一起成爲一個更小的圖像網格(3x3)。我已經能夠使所有的白色像素變爲透明的解決方法,但是形狀的內部是白色的,我只希望形狀外部的像素透明。Java - 追蹤抽象形狀並使外部像素透明的輪廓

舉例來說,圖像網格在每個網格位置包含圓形或正方形。有沒有一種方法可以迭代每個像素,並創建兩個像素位置陣列 - 圖像之外的那些像素位置使它們透明,還有那些可以設置顏色的圖像內的像素位置?

import javax.imageio.ImageIO; 
import java.awt.*; 
import java.awt.image.BufferedImage; 
import java.io.File; 

// Stitches a grid of images together, scales a background image to fit and layers them. 
public class Layer { 

    public static void layerImages() { 

     // Grid layout of images to stitch. 
     int rows = 3; 
     int cols = 3; 
     int chunks = rows * cols; 
     int chunckWidth, chunkHeight; 

     // Image files to stitch 
     File[] imgFiles = new File[chunks]; 

     for(int i = 0; i < chunks; i++) { 
      imgFiles[i] = new File("ocarina_sprite" + (i + 1) + ".png"); 
     } 

     // Read images into array. 
     try { 
      BufferedImage[] buffImages = new BufferedImage[chunks]; 
      for (int i = 0; i < chunks; i++) { 
       buffImages[i] = ImageIO.read(imgFiles[i]); 
      } 

      chunckWidth = buffImages[0].getWidth(); 
      chunkHeight = buffImages[0].getHeight(); 

      BufferedImage finalImage = new BufferedImage(chunckWidth * cols, chunkHeight*rows, BufferedImage.TYPE_INT_ARGB); 

      // Calculate background width and height to cover stitched image. 
      int bwidth = 0; 
      int bheight = 0; 

      for(int i = 0; i < rows; i++) { 
       bwidth += buffImages[i].getWidth(); 
      } 
      for(int i = 0; i < cols; i++) { 
       bheight += buffImages[i].getHeight(); 
      } 

      // Background image 
      File dory = new File("dory.png"); 
      BufferedImage original = ImageIO.read(dory); 
      // Scale background image. 
      BufferedImage background = scale(original, bwidth, bheight); 

      // Prepare final image by drawing background first. 
      Graphics2D g = finalImage.createGraphics(); 
      g.drawImage(background, 0, 0, null); 

      // Prepare foreground image. 
      BufferedImage foreground = new BufferedImage(chunckWidth * cols, chunkHeight*rows, BufferedImage.TYPE_INT_ARGB); 

      // Stitch foreground images together 
      int num = 0; 
      for(int i = 0; i < rows; i++) { 
       for(int j = 0; j < rows; j++) { 
        foreground.createGraphics().drawImage(buffImages[num],chunckWidth * j, chunkHeight * i, null); 
        num++; 
       } 
      } 

      // Set white pixels to transparent. 
      for (int y = 0; y < foreground.getHeight(); ++y) { 
       for (int x = 0; x < foreground.getWidth(); ++x) { 
        int argb = foreground.getRGB(x, y); 
        if ((argb & 0xFFFFFF) > 0xFFFFEE) { 
         foreground.setRGB(x, y, 0x00FFFFFF); 
        } 
       } 
      } 

      // Draw foreground image to final image. 
      Graphics2D g3 = finalImage.createGraphics(); 
      g3.drawImage(foreground, 0, 0, null); 


      // Output final image 
      ImageIO.write(finalImage, "png", new File("finalImage.png")); 
     } 
     catch (Exception e) { 
      System.out.println(e); 
     } 
    } 

    // Scale image 
    public static BufferedImage scale(BufferedImage imageToScale, int dWidth, int dHeight) { 
     BufferedImage scaledImage = null; 
     if (imageToScale != null) { 
      scaledImage = new BufferedImage(dWidth, dHeight, imageToScale.getType()); 
      Graphics2D graphics2D = scaledImage.createGraphics(); 
      graphics2D.drawImage(imageToScale, 0, 0, dWidth, dHeight, null); 
      graphics2D.dispose(); 
     } 
     return scaledImage; 
    } 
} 
+1

我想你可以* floodfill *圖像之外的區域,設定邊界條件是,當你遇到一個非白色像素 – meowgoesthedog

+1

你爲什麼不能手動前處理在編輯器中前景圖像利用alpha通道? – khriskooper

+0

感謝您的評論。 Floodfill正是我所期待的,我寫了一個遞歸算法來使邊界周圍的像素透明。唯一的問題是,我得到一個計算器。有任何想法嗎?我在開始時進行檢查,以確保不會覆蓋同一個像素兩次,只是向北,南,東,西移動檢查邊界。 – user6688986

回答

0

在評論中提及此時,floodFill解決方案是什麼,我需要解決的問題,但超過一百萬+像素遞歸沒有發揮出來,所以我實現它floodfill使用隊列,而不是遞歸的森林火災算法。

public static void forestFire(int width, int height, int x, int y) { 
     // Check if already set 
     int argb = foreground.getRGB(x, y); 
     if (((argb >> 24) & 0xFF) == 0) { 
      return; 
     } 
     coords.add(new Point(x, y)); 

     // Set transparent pixel 
     foreground.setRGB(x, y, 0x00FFFFFF); 

     Point currentCoord = new Point(); 

     while(!coords.isEmpty()) { 
      currentCoord.setLocation(coords.poll()); 

      // Get current coordinates 
      x = (int)currentCoord.getX(); 
      y = (int)currentCoord.getY(); 

      // North 
      if(y != 0) { 
       int north = foreground.getRGB(x, y - 1); 
       // Check if transparent (already set) and check target colour (white) 
       if (((north >> 24) & 0xFF) > 0 && (north & 0xFFFFFF) > 0x111100) { 
        // Set transparent pixel 
        foreground.setRGB(x, y - 1, 0x00FFFFFF); 
        coords.add(new Point(x, y - 1)); 
       } 
      } 

      // East 
      if(x != width - 1) { 
       int east = foreground.getRGB(x + 1, y); 
       if (((east >> 24) & 0xFF) > 0 && (east & 0xFFFFFF) > 0x111100) { 
        foreground.setRGB(x + 1, y, 0x00FFFFFF); 
        coords.add(new Point(x + 1, y)); 
       } 
      } 

      // South 
      if(y != height - 1) { 
       int south = foreground.getRGB(x, y + 1); 
       if (((south >> 24) & 0xFF) > 0 && (south & 0xFFFFFF) > 0x111100) { 
        foreground.setRGB(x, y + 1, 0x00FFFFFF); 
        coords.add(new Point(x, y + 1)); 
       } 
      } 

      // West 
      if(x != 0) { 
       int west = foreground.getRGB(x - 1, y); 
       if (((west >> 24) & 0xFF) > 0 && (west & 0xFFFFFF) > 0x111100) { 
        foreground.setRGB(x - 1, y, 0x00FFFFFF); 
        coords.add(new Point(x - 1, y)); 
       } 
      } 
     }