2012-02-15 130 views
-1

我試圖在圖像中查找白色矩形。矩形大小是固定的。這是我想出作爲尚未:在圖像中查找白色矩形

BufferedImage bImage = bufferedImage; 
int height = bufferedImage.getHeight(); //~1100px 
int width = bufferedImage.getWidth(); //~1600px 
int neededWidth = width/2; 
int neededHeight = 150; 
int x = 0; 
int y = 0; 
boolean breaker = false; 
boolean found = false; 
int rgb = 0xFF00FF00; 
int fx, fy; 

fx = fy = 0; 
JavaLogger.log.info("width, height: " + w + ", " + h); 
while ((x != (width/2) || y != (height - neededHeight)) && found == false) { 
for (int i = y; i - y < neededHeight + 1; i++) { 
    for (int j = x; j - x < neededWidth + 1; j++) { //Vareetu buut, ka +1 vajadziigs 
     //JavaLogger.log.info("x,y: " + j + ", " + i); 
     long pixel = bImage.getRGB(j, i); 
     if (pixel != colorWhite && pixel != -1) { 
      //bImage.setRGB(j, i, rgb); 
      //JavaLogger.log.info("x,y: " + (j+x) + ", " + (i+y)); 
      breaker = true; 
      break; 

     } else { 
      //bImage.setRGB(j, i, 0xFFFFFF00); 
     } 
     //printPixelARGB(pixel); 
     if ((i - y == neededHeight-10) && j - x == neededWidth-10) { 
      JavaLogger.log.info("width, height: " + x + ", " + y + "," + j + ", " + i); 
      fx = j; 
      fy = i; 
      found = true; 
      breaker = true; 
      break; 
     } 
    } 
    if (breaker) { 
     breaker = false; 
     break; 
    } 

} 

if (x < (width/2)) { 
    x++; 
} else { 
    if (y < (height - neededHeight)) { 
     y++; 
     x = 0; 
    } else { 
     break; 
    } 
    } 
//JavaLogger.log.info("width, height: " + x + ", " + y); 
} 

if (found == true) { 

    for (int i = y; i < fy; i++) { 
     for (int j = x; j < fx; j++) { 
      bImage.setRGB(j, i, 0xFF00FF3F); 
     } 

    } 

} 
JavaLogger.log.info("width, height: " + w + ", " + h); 

該工程確定,如果我需要的矩形接近(0;0)開始時,但因爲它得到更遠,性能下降相當嚴重。我想知道,如果有什麼可以做的?

例如,該搜索了近8秒,這是相當多的。 One of searches 我在想,這可以更有效地完成。也許一些blob發現?閱讀它,但我不知道如何應用它。

而且,我是新來的Java和圖像處理,所以任何幫助表示讚賞。

+2

爲了更快提供更好的幫助,請發佈[SSCCE](http://sscce.org/)。無需發佈1,191px×1,684px的圖片!你沒有聽說過***作物嗎?!? – 2012-02-15 11:20:47

+0

這是一個SSCCE。代碼的每一部分都與問題相關。至於圖像 - 是的。我把整個圖像展示出我的問題的範圍。如果圖像被裁剪出來,那麼看起來底部不會花費很長時間。現在很明顯,它會。 – 2012-02-15 11:32:39

+1

*「這是一個SSCCE。」*儘可能大聲說出來,但這並不是真的。 *「代碼的每個部分都與問題相關。」*嗯......好。如何使代碼成爲'SC'的代碼部分?如果你感到困惑,它的問題不是代碼的長度。你有沒有*閱讀*鏈接? *「我把整個圖像顯示出我的問題的範圍。」*一個聰明的技巧,你可以用它來「吃你的蛋糕和吃它」(有一個小圖像下載/使用,以及一個大圖像測試與)是在後期嵌入一個小圖像,然後在運行時將其繪製成大圖像。 – 2012-02-15 11:52:50

回答

1

這是很粗糙的,但成功地找到圖像中所有白色像素,更多的檢查可以做,以確保它是你想要的大小,一切都在那裏,但基本是有。 PS:我沒有測試過你的圖片。 rthis.rc是圖片的大小和pthis.px是內部矩形大小

public static void main(String[] args) { 
    JFrame frame = new JFrame(); 
    final int r = 100; 
    final int p = 10; 

    NewJPanel pan = new NewJPanel(r, p, new A() { 
     @Override 
     public void doImage(BufferedImage i) { 
      int o = 0; 

      for (int j = 0; j < i.getWidth() - p; j++) { 
       for (int k = 0; k < i.getHeight() - p; k++) { 

        PixelGrabber pix2 = new PixelGrabber(
          i, j, k, p, p, false); 
        try { 
         pix2.grabPixels(); 
        } catch (InterruptedException ex) {} 

        int pixelColor = pix2.getColorModel() 
          .getRGB(pix2.getPixels()); 

        Color c = new Color(pixelColor); 
        if (c.equals(Color.WHITE)) { 
         System.out.println("Found at : x:" + j + ",y:" + k); 
        } 

       } 
      } 
     } 
    }); 

    frame.getContentPane().add(pan); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.setSize(500, 500); 
    frame.setLocationRelativeTo(null); 
    frame.setVisible(true); 
} 

private interface A { 
    void doImage(BufferedImage i); 
} 

private static class NewJPanel extends JPanel { 
    private static final long serialVersionUID = -5348356640373105209L; 

    private BufferedImage image = null; 
    private int px; 
    private int rc; 
    private A a; 

    public NewJPanel(int r, int p, A a) { 
     this.px = p; 
     this.rc = r; 
     this.a = a; 
    } 

    public BufferedImage getImage() { 
     return image; 
    } 

    @Override public void paint(Graphics g) { 
     super.paint(g); 

     image = new BufferedImage(this.rc, this.rc, 
       BufferedImage.TYPE_INT_ARGB); 
     java.awt.Graphics2D g2 = image.createGraphics(); 

     g2.setColor(Color.BLACK); 
     g2.fillRect(0, 0, this.rc, this.rc); 
     g2.setColor(Color.WHITE); 
     g2.fillRect(
       new Random().nextInt(this.rc - this.px), 
       new Random().nextInt(this.rc - this.px), 
       this.px, this.px); 

     g.drawImage(image, this.rc, this.rc, this); 
     this.a.doImage(this.image); 
    } 
} 
0

我不是專家,但我不認爲代碼的問題 - 你需要改變你的算法。我想通過在2D平面遞歸地尋找一個白色像素開始,像這樣:

findWhitePixel(廣場){ 看像素在「廣場」的中間 - 如果它是白色的回報,否則: findWhitePixel ('正方形'的右上角) findWhitePixel(左上角的'正方形') findWhitePixel(右下角的'正方形') findWhitePixel(正方形的左下角四分之一) }

找到白色像素後,嘗試向上,向下,向左和向右拖動以找到您的形狀邊框。如果這是給定的,只能有矩形 - 你完成了。如果可能有其他形狀(三角形,圓形等),則需要在此處進行驗證。

+0

你的算法會如何加快搜索過程?正如我所看到的,仍然需要不止一次地遍歷幾乎任何像素。 – 2012-02-15 12:04:05

+0

根據白色矩形的相對大小,您只會在擊中一個白色的像素之前超過幾個像素。 – Rami 2012-02-16 15:09:40

0

你所要求可以被稱爲「糜爛」的操作來解決。該侵蝕用該位置(左上角)中請求大小的矩形中最暗的所有像素替換每個像素。在這裏,最黑暗的意思是非白色取代白色。

侵蝕的輸出是與W-1列和H-1的行少的圖像。其中的任何白色像素對應於一個解決方案。

在矩形形狀的幸運情況下,侵蝕是可分離的操作。這意味着您可以首先使用水平線段形狀進行腐蝕,然後使用第一次侵蝕輸出中的垂直線段形狀。對於W x H的重調尺寸,這將W * H操作替換爲W + H,這是一項重大的節省。

在二進制圖像(非白色或白色)的也幸運的情況下,侵蝕由段能夠極其高效地進行:在每一行中獨立地,發現白色像素的所有連續運行,並打開W-1最右邊的非白色。對所有列執行相同的操作,縮短H-1像素的白色運行。

實施例:找到所有3x2的矩形:

####....#### 
##.....#..## 
#..######... 
.....###.... 

3X1侵蝕後:

####..#### 
##...##### 
#########. 
...#####.. 

1x2的侵蝕後:

####.##### 
########## 
#########. 

該算法需要每像素恆定時間(不考慮矩形大小)。正確實施,應該花幾個毫秒。