1

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

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

所以从下图中我想提取绿色矩形。

在此处输入图像描述

目前我不知道如何开始解决这个问题。

更新

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

4 回答 4

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();

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

于 2012-09-03T21:13:51.530 回答
2

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

您可以获取 aBitmap的像素,getPixels()然后创建一个新的、裁剪BitmapcreateBitmap(). 然后,只需找到边界的尺寸即可。

您可以通过访问位于 position 的像素找到边框的颜色,0然后将该值 (an 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()方法。测试你的代码的奇迹......它现在已经修复了。

于 2012-09-03T20:55:38.323 回答
0

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

于 2012-09-03T20:54:25.880 回答
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);
    }
于 2016-11-10T07:30:24.207 回答