6

いくつかの数学を使用して、次のJava関数を作成してビットマップを入力し、中央の正方形を切り取って、円が再び切り取られ、その周りに黒い境界線が表示されます。正方形の残りの部分は透明にする必要があります。さらに、メッセンジャー経由で画像を送信するときにプレビューを損なわないように、側面に透明な距離があります。

私の関数のコードは次のとおりです。

 public static Bitmap edit_image(Bitmap src,boolean makeborder) {
        int width = src.getWidth();
        int height = src.getHeight();
        int A, R, G, B;
        int pixel;

        int middlex = width/2;
        int middley = height/2;

        int seitenlaenge,startx,starty;
        if(width>height) 
        {
            seitenlaenge=height;
            starty=0;

            startx = middlex - (seitenlaenge/2);
        }
        else 
        {
            seitenlaenge=width; 
            startx=0;

            starty = middley - (seitenlaenge/2);
        }

        int kreisradius = seitenlaenge/2;
        int mittx = startx + kreisradius;
        int mitty = starty + kreisradius;
        int border=2;
        int seitenabstand=55;

        Bitmap bmOut = Bitmap.createBitmap(seitenlaenge+seitenabstand, seitenlaenge+seitenabstand, Bitmap.Config.ARGB_8888);
        bmOut.setHasAlpha(true);

        for(int x = 0; x < width; ++x) {
            for(int y = 0; y < height; ++y) {
                int distzumitte = (int) (Math.pow(mittx-x,2) + Math.pow(mitty-y,2)); // (Xm-Xp)^2 + (Ym-Yp)^2 = dist^2
                distzumitte = (int) Math.sqrt(distzumitte);

                pixel = src.getPixel(x, y);

                A = Color.alpha(pixel);
                R = (int)Color.red(pixel);
                G = (int)Color.green(pixel);
                B = (int)Color.blue(pixel);
                int color = Color.argb(A, R, G, B);

                int afterx=x-startx+(seitenabstand/2);
                int aftery=y-starty+(seitenabstand/2);

                if(x < startx || y < starty || afterx>=seitenlaenge+seitenabstand || aftery>=seitenlaenge+seitenabstand) //seitenrand
                {
                    continue;
                }
                else if(distzumitte > kreisradius)
                {
                    color=0x00FFFFFF;
                }
                else if(distzumitte > kreisradius-border && makeborder) //border
                {
                    color = Color.argb(A, 0, 0, 0);
                }
                bmOut.setPixel(afterx, aftery, color);
            }
        }

        return bmOut;
    }

この機能は正常に動作しますが、まだ解決できていない問題がいくつか発生しています。

  • 画質が大幅に落ちる
  • 境界線は実際には丸くはありませんが、画像の端が平らに見えます (一部のデバイスでは?!)。

その問題に関する助けをいただければ幸いです。私は数学が得意ではないことを認めなければなりません。境界線を引くためのより良い公式があるはずです。

4

3 に答える 3

3

変数名にドイツ語と英語が混在しているため、ソースコードは読みにくいです。さらに、どの画像ライブラリを使用しているかを述べていないため、クラス Bitmap と Color がどこから来たのか正確にはわかりません。

とにかく、ビットマップのみを操作していることは明らかです。ビットマップとは、イメージ全体がピクセル単位で RAM に格納されることを意味します。非可逆圧縮はありません。あなたのソースコードには、画像の品質に影響を与える可能性のあるものは何もありません.

答えは、あなたが私たちに示していないコードにある可能性が非常に高いです。さらに、あなたが説明したこと(両方の問題)は、非常に典型的な低品質のJPEG圧縮のように聞こえます。関数を呼び出した後のどこかで、画像をJPEGに変換/保存すると確信しています。BMP、TIFF、または PNG のその位置でそれを実行してみて、エラーが魔法のように消えることを確認してください。それを避けるために、JPEGの品質レベルをどこかに設定することもできます。

他の人 (おそらく) が良い答えを見つけやすくするために、あなたのコードを英語に翻訳させてください:

    public static Bitmap edit_image(Bitmap src,boolean makeborder) {
        int width = src.getWidth();
        int height = src.getHeight();
        int A, R, G, B;
        int pixel;

        int middlex = width/2;
        int middley = height/2;

        int sideLength,startx,starty;
        if(width>height) 
        {
            sideLength=height;
            starty=0;

            startx = middlex - (sideLength/2);
        }
        else 
        {
            sideLength=width; 
            startx=0;

            starty = middley - (sideLength/2);
        }

        int circleRadius = sideLength/2;
        int middleX = startx + circleRadius;
        int middleY = starty + circleRadius;
        int border=2;
        int sideDistance=55;

        Bitmap bmOut = Bitmap.createBitmap(sideLength+sideDistance, sideLength+sideDistance, Bitmap.Config.ARGB_8888);
        bmOut.setHasAlpha(true);

        for(int x = 0; x < width; ++x) {
            for(int y = 0; y < height; ++y) {
                int distanceToMiddle = (int) (Math.pow(middleX-x,2) + Math.pow(middleY-y,2)); // (Xm-Xp)^2 + (Ym-Yp)^2 = dist^2
                distanceToMiddle = (int) Math.sqrt(distanceToMiddle);

                pixel = src.getPixel(x, y);

                A = Color.alpha(pixel);
                R = (int)Color.red(pixel);
                G = (int)Color.green(pixel);
                B = (int)Color.blue(pixel);
                int color = Color.argb(A, R, G, B);

                int afterx=x-startx+(sideDistance/2);
                int aftery=y-starty+(sideDistance/2);

                if(x < startx || y < starty || afterx>=sideLength+sideDistance || aftery>=sideLength+sideDistance) //margin
                {
                    continue;
                }
                else if(distanceToMiddle > circleRadius)
                {
                    color=0x00FFFFFF;
                }
                else if(distanceToMiddle > circleRadius-border && makeborder) //border
                {
                    color = Color.argb(A, 0, 0, 0);
                }
                bmOut.setPixel(afterx, aftery, color);
            }
        }

        return bmOut;
    }
于 2013-07-26T04:24:10.487 に答える
1

品質に関しては、あなたの方法に問題はありません。Java Swing でコードを実行しても、品質は失われません。唯一の問題は、画像のエッジにエイリアシングがあることです。

エイリアシングの問題は、画面の解像度が上がるにつれて解消される傾向があり、解像度が低いほど顕著になります。これは、一部のデバイスでのみ表示される理由を説明している可能性があります.同じ問題が境界線にも当てはまりますが、その場合、色が単一の黒であるため、より顕著になります.

アルゴリズムは、元の画像の正方形の領域を定義します。正方形を見つけるには、画像の中心から開始し、画像のwidthまたは のheightいずれか小さい方に拡大します。この領域を と呼んでいsquareます。

エイリアシングは、色を設定するコードが原因です (私は疑似コードを使用しています)。

if ( outOfSquare() ) {
    continue;  // case 1: this works but you depend upon the new image' s default pixel value i.e. transparent black
} else if ( insideSquare() && ! insideCircle() ) {
    color = 0x00FFFFFF;  // case 2: transparent white. <- Redundant
} else if ( insideBorder() ) {  
    color = Color.argb(A, 0, 0, 0);  // case 3: Black color using the transparency of the original image. 
} else { // inside the inner circle 
    // case 4: leave image color
}

コードに関する注意事項:

  • ケース 1 は、元の画像のデフォルトのピクセル値、つまり透明な黒に依存します。動作しますが、明示的に設定することをお勧めします
  • ケース 2 は冗長です。ケース 1 を処理するのと同じ方法で処理します。円の内部で何が起こるかにのみ関心があります。
  • ケース 3 (境界線を描画する場合) は、期待される内容が明確ではありません。元の画像のアルファを使用すると、元のアルファが円のエッジに沿って変化した場合、新しい画像が台無しになる可能性があります。したがって、これは明らかに間違っており、画像によっては、問題の別の原因になる可能性があります。
  • ケース 4 は問題ありません。

円の周辺で、次の色の変化が起こります。

  • 境界線が使用されていない場合: 完全な透過性、->完全な画像の色 (疑似コードのケース 2 および 4)
  • 境界線が使用されている場合: 完全な透明性->完全な黒->完全な画像の色 (ケース 2、3、および 4)

エッジの品質を向上させるには、トランジションをよりスムーズにするいくつかの中間状態を導入する必要があります (新しいトランジションはイタリック体で表示されます)。

  • 境界線は使用されません: 完全な透明-> 部分的な透明度と画像の色の ->完全な画像の色
  • ボーダーが使用されます: 完全な透明-> 度 黒色の部分的な透明度 ->完全な黒色 黒色の-> 部分的な透明度 + 画像の色 (つまり、ブレンド) ->画像の完全な色

それが役立つことを願っています

于 2013-07-26T09:18:46.823 に答える