2012-09-03 47 views
1

我试图构建一个程序,可以从图像中删除单色边框。如何从图像中删除未知宽度的边框

边框始终为白色,但左侧和右侧的边框宽度可能不同于顶部和底部边框的宽度。所以我想要提取的图像集中在源图像中。

所以从下面的图片我想提取绿色的矩形。

enter image description here

此刻,我不知道如何开始解决这个问题。

UPDATE

所以最后calsign的代码段,它的一些改进,解决了我的问题。我意识到内部图像周围的边框可能不是完全单一的颜色,但可以略有不同。这导致一些图像留下一个小边界的行为。

我通过比较两种颜色的颜色距离和阈值来改善两个像素的颜色比较,从而解决了这个问题。当距离低于阈值时,颜色被平等地处理。

public Bitmap cropBorderFromBitmap(Bitmap bmp) { 
      //Convenience variables 
    int width = bmp.getWidth(); 
    int height = bmp.getHeight(); 

    int[] pixels = new int[height * width]; 

    //Load the pixel data into the pixels array 
    bmp.getPixels(pixels, 0, width, 0, 0, width, height); 

    int length = pixels.length; 

    int borderColor = pixels[0]; 

    //Locate the start of the border 
    int borderStart = 0; 
    for(int i = 0; i < length; i ++) { 

     // 1. Compare the color of two pixels whether they differ 
     // 2. Check whether the difference is significant  
     if(pixels[i] != borderColor && !sameColor(borderColor, pixels[i])) { 
      Log.i(TAG,"Current Color: " + pixels[i]);     
      borderStart = i; 
      break; 
     } 
    } 

    //Locate the end of the border 
    int borderEnd = 0; 
    for(int i = length - 1; i >= 0; i --) { 
     if(pixels[i] != borderColor && !sameColor(borderColor, pixels[i])) { 
      Log.i(TAG,"Current Color: " + pixels[i]); 
      borderEnd = length - i; 
      break; 
     } 
    } 

    //Calculate the margins 
    int leftMargin = borderStart % width; 
    int rightMargin = borderEnd % width; 
    int topMargin = borderStart/width; 
    int bottomMargin = borderEnd/width; 

    //Create the new, cropped version of the Bitmap 
    bmp = Bitmap.createBitmap(bmp, leftMargin, topMargin, width - leftMargin - rightMargin, height - topMargin - bottomMargin); 
    return bmp; 
} 

private boolean sameColor(int color1, int color2){ 
    // Split colors into RGB values 
    long r1 = (color1)&0xFF; 
    long g1 = (color1 >>8)&0xFF; 
    long b1 = (color1 >>16)&0xFF; 

    long r2 = (color2)&0xFF; 
    long g2 = (color2 >>8)&0xFF; 
    long b2 = (color2 >>16)&0xFF; 

    long dist = (r2 - r1) * (r2 - r1) + (g2 - g1) * (g2 - g1) + (b2 - b1) *(b2 - b1); 

    // Check vs. threshold 
    return dist < 200; 
} 
+1

是图像的黑线的一部分? –

+0

不,我只是添加了黑线,以显示图像的整个维度与其边界。 – Flo

+0

嘿!你能上传createBitmap的代码吗? –

回答

2

也许不是最好使用API​​来寻找解决方案,但是想到的是:直接修改图像的像素。

您可以通过getPixels()获得Bitmap的像素,然后使用createBitmap()创建一个新的裁剪的Bitmap。然后,这只是找到边界的尺寸的问题。

您可以通过访问位于0位置的像素找到边框的颜色,然后比较值(int)每个程序像素的值,直到你的范围边界(即不在于像素颜色)。有了一点数学,就可以完成。

下面是一些简单的代码说明了这一点:

private void cropBorderFromBitmap(Bitmap bmp) { 
    int[] pixels; 
    //Load the pixel data into the pixels array 
    bmp.getPixels(pixels, 0, width, 0, 0, width, height); 

    //Convenience variables 
    int width = bmp.getWidth(); 
    int height = bmp.getHeight(); 
    int length = pixels.length; 

    int borderColor = pixels[0]; 

    //Locate the start of the border 
    int borderStart; 
    for(int i = 0; i < length; i ++) { 
     if(pixels[i] != borderColor) { 
      borderStart = i; 
      break; 
     } 
    } 

    //Locate the end of the border 
    int borderEnd; 
    for(int i = length - 1; i >= 0; i --) { 
     if(pixels[i] != borderColor) { 
      borderEnd = length - i; 
      break; 
     } 
    } 

    //Calculate the margins 
    int leftMargin = borderStart % width; 
    int rightMargin = borderEnd % width; 
    int topMargin = borderStart/width; 
    int bottomMargin = borderEnd/width; 

    //Create the new, cropped version of the Bitmap 
    bmp = createBitmap(bmp, leftMargin, topMargin, width - leftMargin - rightMargin, height - topMargin - bottomMargin); 
} 

这是未经测试,缺少错误检测(例如,如果宽度是什么0?),但它应该作为一个证明OF-概念。

编辑:我只是意识到,我没有完成getPixels()方法。测试你的代码的奇迹......现在已经修复了。

+0

嘿,你的解决方案几乎完美!大! – Flo

+0

我意识到边框颜色在内部图像附近有点变化,并且不再是纯白色。这导致了问题,即边框未完全裁剪。所以我通过不仅比较颜色而且通过计算两种颜色之间的颜色距离来改进代码。然后我可以检查距离是否达到一定的阈值,这样我可以确保颜色真的发生了显着变化。 – Flo

+0

也许您可以使用您的阈值解决方案更新我的回复(或者我应该这样做?)。 – calsign

0

可以使用public int getPixel (int x, int y)函数返回的每一个像素的颜色
它应该很容易通过边境线运行,并验证颜色仍然是相同的

2

如果图片周围的图框是统一的,那么您只需调查图片中像素的变化。 但首先,你需要有一个BufferedImage对象来处理。这是一个允许您遍历图像位图的类(http://docs.oracle.com/javase/6/docs/api/java/awt/image/BufferedImage.html)。 如果有图像保存为一个文件,你需要调用这个方法:

BufferedImage bimage = ImageIO.read(new File(file)); 

现在,您可以获取从bimage位图阵列:

bimage.getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize) 

这样的:

int[] rgb = bimage.getRGB(0, 0, bimage.getWidth(), bimage.getHeight(), null, 0, bimage.getWidth()); 

ColorModel可能存在一些问题,因此请务必阅读有关如何从不同文件类型获取适当rgb的文档。

现在您已经拥有了rgb数组,您应该开始搜索框架从图片中间伸展多远。请记住,这是一个单维数组 - 所有行都按顺序依次写入 - 就像您将图片切成1像素高度并将它们粘在一起形成一条长条线一样。

这实际上对我们有利,因为我们在此表中遇到的第一个不同像素将作为一个很好的参考点。

所以现在我们只是做这样的事情:

int pixel1=0,pixel2=0, i=0; 
while(pixel1==pixel2 && i<bimage.getWidth()*bimage.getHeight()){ 
    pixel1=pixel2; 
    pixel2=rgb[i++]; 
} 

所以,现在,如果你的图像的帧是均匀的,顶部偏移是一样的底部偏移和左偏移量是一样的右偏移,那么变量i中的数字很可能是绿色矩形中的第一个像素。

为了知道它是哪一行和列,你需要下面的代码:

int row= i%bimage.getWidth(); 
int column= i - row*bimage.getWidth(); 

现在的问题是,你可能有嵌入在帧的图像,在它的左上角是与框架相同的颜色 - 例如,在白色框架中具有白色拐角的绿色矩形的图像。是这样吗?

+0

Thx伟大的答案。好的一点开始。关于最后的评论,可能会发生内部图像的任何一侧可能是白色的。我可能需要一个更强大的解决方案。也许这可能是很好的开始在多个位置进行检查,例如,在左侧的顶部,中间和底部。当左上角的第一个非白色像素的x坐标大于左侧的中间时,我知道内部图像的左上角可能是白色的,所以我取后者的x坐标检查为参考点。 – Flo

0

这是我的解决方案:

private Bitmap cropBorderFromBitmap(Bitmap bmp) { 

     final int borderWidth = 10; //preserved border width 
     final int borderColor = -1; //WHITE 

     int width = bmp.getWidth(); 
     int height = bmp.getHeight(); 

     int[] pixels = new int[width * height]; 
     bmp.getPixels(pixels, 0, width, 0, 0, width, height); 

     int minX = -1; 
     int minY = -1; 
     int maxX = -1; 
     int maxY = -1; 

     for(int y = 0; y < height; y++) { 
      for(int x = 0; x < width; x++) { 
       if(bmp.getPixel(x,y) != borderColor) { 
        minX = (minX == -1) ? x : Math.min(x, minX); 
        minY = (minY == -1) ? y : Math.min(y, minY); 

        maxX = (maxX == -1) ? x : Math.max(x, maxX); 
        maxY = (maxY == -1) ? y : Math.max(y, maxY); 
       } 
      } 
     } 

     minX = Math.max(0, minX - borderWidth); 
     maxX = Math.min(width, maxX + borderWidth); 
     minY = Math.max(0, minY - borderWidth); 
     maxY = Math.min(height, maxY + borderWidth); 

     //Create the new, cropped version of the Bitmap 
     return Bitmap.createBitmap(bmp, minX, minY, maxX - minX, maxY-minY); 
    }