2013-07-17 17 views
6

Używając jakiejś matematyki, stworzyłem następującą funkcję java, aby wprowadzić bitmapę, i wyciąć kwadrat wyśrodkowany, w którym kółko jest wykadrowane ponownie z czarną obwódką wokół niego . Reszta kwadratu powinna być przezroczysta. Co więcej, odległość między bokami jest przezroczysta, aby nie uszkodzić podglądu podczas wysyłania obrazu za pośrednictwem Posłańców.Kadrowanie obrazu obniża jakość, a obramowanie wygląda źle

Kod z mojej funkcji jest następująca:

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; 
    } 

Ta funkcja działa prawidłowo, ale są pewne problemy występujące, że nie był w stanie jeszcze rozwiązać.

  • Jakość obrazu jest znacznie spadła
  • Granica naprawdę nie jest okrągła, ale wydaje się być płaska na krawędziach obrazu (na niektórych urządzeniach ?!)

I” doceniamy każdą pomoc dotyczącą tych problemów. Muszę przyznać, że nie jestem najlepszy w matematyce i prawdopodobnie powinna istnieć lepsza formuła zakończenia granicy.

Odpowiedz

1

Myślę, że trzeba sprawdzić PorterDuffXferMode.

Znajdziesz tu informacje techniczne na temat łączenia trybów zdjęć HERE.

Istnieje dobry przykład tworzenia bitmapy z zaokrąglonymi krawędziami HERE. Trzeba tylko poprawić trochę kodu źródłowego i jesteś gotowy do pracy ...

Mam nadzieję, że to pomoże.

3

Twój kod źródłowy jest trudny do odczytania, ponieważ jest mieszanką języka niemieckiego i angielskiego w nazwach zmiennych. Ponadto nie mówisz, z której biblioteki obrazów korzystasz, więc nie wiemy dokładnie skąd pochodzą klasy Bitmap i kolor.

W każdym razie, jest bardzo oczywiste, że operujesz tylko na bitmapie. Bitmapa oznacza, że ​​cały obraz jest przechowywany w pamięci RAM piksel po pikselu. Nie ma stratnej kompresji. Nie widzę niczego w kodzie źródłowym, które może wpłynąć na jakość obrazu.

Jest bardzo prawdopodobne, że odpowiedź znajduje się w Kodeksie, który nie jest dla nas wyświetlany. Dodatkowo, to, co opisujesz (większość problemów) brzmi jak bardzo typowa kompresja JPEG o niskiej jakości. Jestem pewien, że gdzieś po wywołaniu funkcji, konwertujesz/zapisujesz obraz na JPEG. Spróbuj zrobić to w tej pozycji do BMP, TIFF lub PNG i zobacz, że błąd zniknie magicznie. Być może możesz też ustawić gdzieś poziom jakości JPEG, aby tego uniknąć.

Aby ułatwić innym (być może) również znaleźć dobrą odpowiedź, proszę pozwolić mi przetłumaczyć swój kod na angielski:

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; 
    } 
+1

+1 do tłumaczenia –

1

chodzi o jakość nie widzę niczego złego w swojej metodzie . Uruchomienie kodu za pomocą Java Swing nie powoduje utraty jakości. Jedynym problemem jest to, że obraz ma aliasów krawędzi.

Problem z aliasingiem będzie zanikać wraz ze wzrostem rozdzielczości ekranu i będzie bardziej zauważalny przy niższych rozdzielczościach. To może wyjaśniać, dlaczego widzisz to tylko w niektórych urządzeniach.Ten sam problem dotyczy twojej granicy, ale w tym przypadku byłby bardziej zauważalny, ponieważ kolor jest pojedynczy czarny.

Twój algorytm definiuje kwadratowy obszar oryginalnego obrazu. Aby znaleźć kwadrat, zaczyna się od centrum obrazu i rozwija się do obrazu width lub height obrazu, którykolwiek jest mniejszy. Mam na myśli ten obszar jako square.

aliasingu jest spowodowane przez kod, który ustawia kolory (używam pseudo-kod):

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 
} 

Kilka uwag o kodzie:

  • Przypadek 1 zależy od domyślnej piksela wartość oryginalnego obrazu, np. przezroczysta czerń. Działa, ale lepiej ustawić go jawnie
  • Przypadek 2 jest zbędny. Rób to w taki sam sposób, w jaki obsługujesz przypadek 1. Interesuje nas tylko to, co dzieje się wewnątrz kręgu.
  • Przypadek 3 (podczas rysowania obramowania) nie jest jasny, czego się spodziewa. Używanie alfa oryginalnego obrazu może naruszyć twój nowy wizerunek, jeśli zdarzy się, że oryginalna alfa zmienia się wzdłuż krawędzi koła. Jest to oczywiście błędne i zależnie od obrazu może potencjalnie być kolejną przyczyną twoich problemów.
  • Przypadek 4 jest w porządku.

Teraz w obwodzie kręgu za następujące przejścia kolorów nastąpić:

  • Jeśli granica nie jest używany: pełna przejrzystość -> pełny kolor obrazu (przypadek 2 i 4 w Pseudokod)
  • Jeśli granica jest używana: pełna przezroczystość -> pełna czerń -> pełny kolor obrazu (przypadki 2, 3 i 4)

Aby uzyskać lepszą jakość na krawędziach, należy wprowadzić Niektóre stany pośrednie, które sprawiają, że przejścia gładsza (nowe przejścia są pokazane w kursywą):

  • Granica nie jest używany: pełna przejrzystość ->częściową przezroczystość kolorem obrazu-> kolorowy obraz
  • Granicznej jest używana: pełna przezroczystość ->częściowa przezroczystość w kolorze czarnym-> pełna czerń ->częściowa przezroczystość koloru czarnego + kolor obrazu (np. blending)-> Kolorowy obraz

Mam nadzieję, że pomaga

Powiązane problemy