如何从图像中删除宽度未知的边框

时间:2012-09-03 20:34:41

标签: java android image-processing

我正在尝试构建一个可以从图像中删除单色边框的程序。

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

因此,从下图中我想提取绿色矩形。

enter image description here

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

更新

所以最后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;
}

4 个答案:

答案 0 :(得分: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,该怎么办?),但它应该作为概念验证。

编辑:我刚刚意识到我未能完成getPixels()方法。测试代码的奇迹......现在已修复。

答案 1 :(得分: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();

现在的问题是,您可能在框架中嵌入了一个图像,其左上角与框架颜色相同 - 例如,白色框架中带有白色角的绿色矩形图像。是这种情况吗?

答案 2 :(得分:0)

您可以使用 public int getPixel (int x, int y) 函数为每个像素返回其颜色
应该很容易穿过边框线并验证颜色是否仍然相同

答案 3 :(得分: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);
    }