1

画像から単色の境界線を削除できるプログラムを作成しようとしています。

境界線は常に白ですが、左右の境界線の幅が上下の境界線の幅と異なる場合があります。したがって、抽出したい画像はソース画像の中央に配置されます。

次の画像から、緑色の長方形を抽出します。

ここに画像の説明を入力してください

現時点では、この問題の解決を開始する方法がわかりません。

アップデート

最後に、calsignのコードスニペットとそのいくつかの改善により、私の問題が解決します。内側の画像の周囲の境界線は完全に単色ではないかもしれませんが、わずかに異なる可能性があることに気づきました。これにより、一部の画像では小さな境界線が残されたという動作が発生します。

この問題は、2つの色の色距離をしきい値と比較することにより、2つのピクセルの色の比較を改善することで解決しました。距離がしきい値を下回ると、色は同じように処理されます。

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

おそらく、解決策を見つけるためのAPIの最善の使用法ではありませんが、頭に浮かんだのは、画像のピクセルを直接変更することです。

Bitmapで'sピクセルを取得してから、でトリミングさgetPixels()れた新しいピクセルを作成できます。次に、境界線の寸法を見つけるだけです。BitmapcreateBitmap()

位置にあるピクセルにアクセスして境界線の色を見つけ、その値(an )を、境界線(その色ではないピクセル)に到達するまで、後続の各ピクセルの値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()。あなたのコードをテストすることの不思議...それは今修正されました。

于 2012-09-03T20:55:38.323 に答える
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ピクセルの高さの線にスライスし、それらを接着して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 に答える
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 に答える