Android's algorithm for cropping the transparent area of the picture

In a recent project, we encountered such a requirement that the transparent area of ​​the picture needs to be cropped. After looking for a long time, I finally determined that I can only read the pixels of the Bitmap by myself to read the boundaries of the image to crop. Record the process below.
The original picture is as follows

PorterDuffXfermode

The first thing I thought was to use PorterDuffXfermode to process, because this method is actually very fast, but although this method can be used to process images, it cannot meet the needs of obtaining image boundaries.
code show as below:

    public static Bitmap cutStickerBitmap(String name, Context context, Bitmap bitmap) {
    
    
        Calendar calendar = Calendar.getInstance();
        Bitmap bit = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
        bit.eraseColor(Color.WHITE);
        Canvas canvas = new Canvas(bit);

        Paint paint = new Paint();
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));

        canvas.drawBitmap(bitmap, 0, 0, paint);
        Paint paintRect = new Paint();
        paintRect.setColor(Color.RED);
        paintRect.setAntiAlias(true);
        paintRect.setStyle(Paint.Style.STROKE);
        paintRect.setStrokeWidth(4);
        Rect rect = new Rect();
        //画一个框表示边界
        rect.set(0, 0, bitmap.getWidth(), bitmap.getHeight());
        canvas.drawRect(rect, paintRect);
        Log.i("xx", " 运行时间 cutStickerBitmap " + (Calendar.getInstance().getTimeInMillis() - calendar.getTimeInMillis()));
        return bit;
    }

The code processing time, we can see that the time is very fast, but unfortunately it does not meet the requirements:

the results of the processing are as follows:Insert picture description here

Write your own algorithm to read pixels

Regarding this algorithm, in fact, I have written two versions. If you write an algorithm yourself, you need to evaluate your own needs and results yourself. In the beginning, in order to prevent the graphics from being discontinuous, the idea I took was to get the borders from around the picture. The idea is shown in the figure:

This is indeed guaranteed to be 100% correct, but there is a problem with this, that is because the resolution of the image obtained is different each time, and sometimes it takes more than 10s to process each time, which is too much. slow.

Later, after careful observation, it was discovered that in fact, it does not need to be so strict, because all the graphs obtained are continuous, so the new algorithm starts processing from the middle.

Along the center line, first get the border to the right, and then get the border from the left along the center line. At the same time, in order to speed up, the method of reading two pixels at a time is adopted. If strict requirements are required, it can be changed to read one pixel at a time. The algorithm code is as follows.

    //处理贴纸
    public static Bitmap cutStickerBitmap(Bitmap bitmap) {
    
    
        Calendar calendar = Calendar.getInstance();
        int top = 0;
        int left = 0;
        int right = bitmap.getWidth() - 1;
        int bottom = 0;

        for (int w = bitmap.getWidth() / 2; w < bitmap.getWidth(); w += 2) {
    
    
            int h = 0;
            for (h = 0; h < bitmap.getHeight(); h+=2) {
    
    
                int color = bitmap.getPixel(w, h);
                if (color != 0) {
    
    
                    if (top == 0) {
    
    
                        top = h;
                    }
                    top = Math.min(top, h);
                    break;
                }
            }

            if (h >= bitmap.getHeight() - 1) {
    
    
                right = w;
                break;
            }
        }

        for (int w = bitmap.getWidth() / 2 - 1; w >= 0; w -= 2) {
    
    
            int h = 0;
            for (h = 0; h < bitmap.getHeight(); h+=2) {
    
    
                int color = bitmap.getPixel(w, h);
                if (color != 0) {
    
    
                    if (top == 0) {
    
    
                        top = h;
                    }
                    top = Math.min(top, h);
                    break;
                }
            }

            if (h >= bitmap.getHeight() - 1) {
    
    
                left = w;
                break;
            }
        }

        for (int w = left; w <= right; w++) {
    
    
            for (int h = bitmap.getHeight() - 1; h >= top; h--) {
    
    
                int color = bitmap.getPixel(w, h);
                if (color != 0) {
    
    
                    bottom = Math.max(bottom, h);
                    break;
                }
            }
        }

        //对边界值做一次判断,保证严谨
        int x = (int) Math.max(left  , 0f);
        int y = (int) Math.max(top  , 0f);
        int w = (int) Math.min(right - left  , bitmap.getWidth() - x);
        int h = (int) Math.min(bottom - top  , bitmap.getHeight() - y);
        if (x + w > bitmap.getWidth()) {
    
    
            x = 0;
            w = bitmap.getWidth();
        }

        if (y + h > bitmap.getHeight()) {
    
    
            y = 0;
            h = bitmap.getHeight();
        }
        Log.i("xx", " 运行时间 cutStickerBitmap " + (Calendar.getInstance().getTimeInMillis() - calendar.getTimeInMillis()));

        return Bitmap.createBitmap(bitmap, x, y, w, h);
    }

The code processing time is as follows:Insert picture description here

Guess you like

Origin blog.csdn.net/Ser_Bad/article/details/90607018