安卓位图去除白边

4
我对Android中的位图有一个问题:我有一张带有白色边距[大小未知]的位图。是否可以创建一个新的位图,将所有白色边距去除(矩形形状)?
Bitmap bmp = Bitmap.createBitmap(width, bmpheigth, Config.ARGB_8888);
    Canvas canvas = new Canvas(bmp);
    canvas.setBitmap(bmp);
    canvas.drawColor(Color.WHITE);
// draw here things!

假设我们不知道物品的位置在哪里。

有什么好方法可以解决这个问题吗?谢谢!

4个回答

6

感谢@Maxim Efimov和@StackOverflowException

以防有人需要这种问题的代码片段:

此方法返回一个裁剪掉边距的较小位图。首先将像素传递给int数组,然后使用该数组比使用Bitmap.getPixel方法更快。

只需调用指定源位图和背景颜色的方法即可。

Bitmap bmp2 = removeMargins(bmp, Color.WHITE);


private static Bitmap removeMargins2(Bitmap bmp, int color) {
    // TODO Auto-generated method stub


    long dtMili = System.currentTimeMillis();
    int MTop = 0, MBot = 0, MLeft = 0, MRight = 0;
    boolean found1 = false, found2 = false;

    int[] bmpIn = new int[bmp.getWidth() * bmp.getHeight()];
    int[][] bmpInt = new int[bmp.getWidth()][bmp.getHeight()];

    bmp.getPixels(bmpIn, 0, bmp.getWidth(), 0, 0, bmp.getWidth(),
            bmp.getHeight());

    for (int ii = 0, contX = 0, contY = 0; ii < bmpIn.length; ii++) {
        bmpInt[contX][contY] = bmpIn[ii];
        contX++;
        if (contX >= bmp.getWidth()) {
            contX = 0;
            contY++;
            if (contY >= bmp.getHeight()) {
                break;
            }
        }
    }

    for (int hP = 0; hP < bmpInt[0].length && !found2; hP++) {
        // looking for MTop
        for (int wP = 0; wP < bmpInt.length && !found2; wP++) {
            if (bmpInt[wP][hP] != color) {
                Log.e("MTop 2", "Pixel found @" + hP);
                MTop = hP;
                found2 = true;
                break;
            }
        }
    }
    found2 = false;

    for (int hP = bmpInt[0].length - 1; hP >= 0 && !found2; hP--) {
        // looking for MBot
        for (int wP = 0; wP < bmpInt.length && !found2; wP++) {
            if (bmpInt[wP][hP] != color) {
                Log.e("MBot 2", "Pixel found @" + hP);
                MBot = bmp.getHeight() - hP;
                found2 = true;
                break;
            }
        }
    }
    found2 = false;

    for (int wP = 0; wP < bmpInt.length && !found2; wP++) {
        // looking for MLeft
        for (int hP = 0; hP < bmpInt[0].length && !found2; hP++) {
            if (bmpInt[wP][hP] != color) {
                Log.e("MLeft 2", "Pixel found @" + wP);
                MLeft = wP;
                found2 = true;
                break;
            }
        }
    }
    found2 = false;

    for (int wP = bmpInt.length - 1; wP >= 0 && !found2; wP--) {
        // looking for MRight
        for (int hP = 0; hP < bmpInt[0].length && !found2; hP++) {
            if (bmpInt[wP][hP] != color) {
                Log.e("MRight 2", "Pixel found @" + wP);
                MRight = bmp.getWidth() - wP;
                found2 = true;
                break;
            }
        }

    }
    found2 = false;

    int sizeY = bmp.getHeight() - MBot - MTop, sizeX = bmp.getWidth()
            - MRight - MLeft;

    Bitmap bmp2 = Bitmap.createBitmap(bmp, MLeft, MTop, sizeX, sizeY);
    dtMili = (System.currentTimeMillis() - dtMili);
    Log.e("Margin   2",
            "Time needed " + dtMili + "mSec\nh:" + bmp.getWidth() + "w:"
                    + bmp.getHeight() + "\narray x:" + bmpInt.length + "y:"
                    + bmpInt[0].length);
    return bmp2;
}

1
我认为你裁剪了多余的1个像素,因为你只在下一次迭代中退出外循环。我认为你应该测试例如 wP > -1 && !found2 - njzk2
1
这个程序的性能如何?看起来批量获取所有像素可能会大大加快它的速度... - tilpner
我在一台设备上使用它,对于一个500x700的位图,我需要180毫秒,但这是一颗1.2 GHz的处理器。您有更快的解决方案吗?您能提供一小段代码吗? - user1616685
仿真器需要1800毫秒的时间,所以加快这个过程会很好。 - user1616685

2
使用Bitmap.createBitmap(source, x, y, width, height),因此您可以知道白边大小并执行所需操作。

实际上我不知道边距的大小(例如使用未知数量字母[user input]的canvas.drawText),我正在寻找一种检测和删除边距的方法。->创建新位图。 - user1616685
@user1616685,这是一个有点复杂但可用的过程 - 获取带边距的位图,然后只需在每个边上迭代其边界像素,直到找到非白色像素 - 这就是边距结束的地方。以这种方式操作可以获得所有边距,然后您就能够使用我上面描述的方法。 - Maxim Efimov
循环遍历位图像素?http://developer.android.com/reference/android/graphics/Bitmap.html#getPixels%28int[],%20int,%20int,%20int,%20int,%20int,%20int%29 我会尝试并在此处进行评论。 - user1616685
@user1616685 是的,或者只需使用http://developer.android.com/reference/android/graphics/Bitmap.html#getPixel(int, int),因为它不需要额外的缓冲区。 - Maxim Efimov

2

我的解决方案:

private Bitmap trim(Bitmap bitmap, int trimColor){
        int minX = Integer.MAX_VALUE;
        int maxX = 0;
        int minY = Integer.MAX_VALUE;
        int maxY = 0;

        for(int x = 0; x < bitmap.getWidth(); x++){
            for(int y = 0; y < bitmap.getHeight(); y++){
                if(bitmap.getPixel(x, y) != trimColor){
                    if(x < minX){
                        minX = x;
                    }
                    if(x > maxX){
                        maxX = x;
                    }
                    if(y < minY){
                        minY = y;
                    }
                    if(y > maxY){
                        maxY = y;
                    }
                }
            }
        }
        return Bitmap.createBitmap(bitmap, minX, minY, maxX - minX + 1, maxY - minY + 1);
    }

执行1280 x 576像素位图需要2965毫秒的时间,在小米红米3S上速度不太快。如果可能的话,在裁剪之前缩小图像:

private Bitmap scaleDown(Bitmap bitmap, float maxImageSize, boolean filter) {
        float ratio = Math.min(maxImageSize / bitmap.getWidth(), maxImageSize / bitmap.getHeight());
        int width = Math.round(ratio * bitmap.getWidth());
        int height = Math.round(ratio * bitmap.getHeight());

        return Bitmap.createScaledBitmap(bitmap, width, height, filter);
    }

0
来晚了,但这个变种略微更快,也许更容易阅读:
    public static Bitmap imageWithMargin(Bitmap bitmap, int color, int maxMargin) {
    int maxTop = 0, maxBottom = 0, maxLeft = 0, maxRight = 0;
    int width = bitmap.getWidth();
    int height = bitmap.getHeight();
    int[] bitmapArray = new int[width * height];
    bitmap.getPixels(bitmapArray, 0, width, 0, 0, width, height);

    // Find first non-color pixel from top of bitmap
    searchTopMargin:
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            if (bitmapArray[width * y + x] != color) {
                maxTop = y > maxMargin ? y - maxMargin : 0;
                break searchTopMargin;
            }
        }
    }

    // Find first non-color pixel from bottom of bitmap
    searchBottomMargin:
    for (int y = height - 1; y >= 0; y--) {
        for (int x = width - 1; x >= 0; x--) {
            if (bitmapArray[width * y + x] != color) {
                maxBottom = y < height - maxMargin ? y + maxMargin : height;
                break searchBottomMargin;
            }
        }
    }

    // Find first non-color pixel from left of bitmap
    searchLeftMargin:
    for (int x = 0; x < width; x++) {
        for (int y = 0; y < height; y++) {
            if (bitmapArray[width * y + x] != color) {
                maxLeft = x > maxMargin ? x - maxMargin : 0;
                break searchLeftMargin;
            }
        }
    }

    // Find first non-color pixel from right of bitmap
    searchRightMargin:
    for (int x = width - 1; x >= 0; x--) {
        for (int y = height - 1; y >= 0; y--) {
            if (bitmapArray[width * y + x] != color) {
                maxRight = x < width - maxMargin ? x + maxMargin : width;
                break searchRightMargin;
            }
        }
    }

    return Bitmap.createBitmap(bitmap, maxLeft, maxTop, maxRight - maxLeft, maxBottom - maxTop);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接