Wie beschneide ich ein Bild in Java?

75

Ich möchte ein Bild manuell mit der Maus zuschneiden.
Angenommen, das Bild enthält Text und ich möchte Text aus einem Bild auswählen. Zu diesem Zweck möchte ich diesen Bereich mit der Maus zuschneiden.

Hussain
quelle
Einige gute Ideen unten. Siehe auch java.sun.com/docs/books/tutorial/2d
trashgod
Hussain: Geben Sie einer dieser detaillierten Antworten den Scheck
IcedDante

Antworten:

153

Die Lösung, die ich zum Zuschneiden eines gepufferten Bildes am nützlichsten fand, verwendet getSubImage (x, y, w, h).

Meine Ernteroutine sah folgendermaßen aus:

  private BufferedImage cropImage(BufferedImage src, Rectangle rect) {
      BufferedImage dest = src.getSubimage(0, 0, rect.width, rect.height);
      return dest; 
   }
Codekopf
quelle
59
Warum nicht auch die x & y-Koordinaten einschließen? BufferedImage dest = src.getSubimage(rect.x, rect.y, rect.width, rect.height);
Sortierer
46

Es gibt zwei potenziell große Probleme mit der führenden Antwort auf diese Frage. Erstens, wie in den Dokumenten beschrieben:

public BufferedImage getSubimage (int x, int y, int w, int h)

Gibt ein Teilbild zurück, das durch einen angegebenen rechteckigen Bereich definiert ist. Das zurückgegebene BufferedImage verwendet dasselbe Datenarray wie das Originalbild.

Dies bedeutet im Wesentlichen, dass das Ergebnis von getSubimage als Zeiger fungiert, der auf einen Unterabschnitt des Originalbilds zeigt.

Warum ist das wichtig? Wenn Sie das Teilbild aus irgendeinem Grund bearbeiten möchten, werden die Änderungen auch am Originalbild vorgenommen. Dieses Problem trat beispielsweise auf, als ich das kleinere Bild in einem separaten Fenster zum Vergrößern des Originalbilds verwendete. (Art wie eine Lupe). Ich habe es möglich gemacht, die Farben zu invertieren, um bestimmte Details leichter zu sehen, aber der Bereich, der "gezoomt" wurde, wurde auch im Originalbild invertiert! Es gab also einen kleinen Abschnitt des Originalbildes, der die Farben invertiert hatte, während der Rest normal blieb. In vielen Fällen spielt dies keine Rolle. Wenn Sie jedoch das Bild bearbeiten oder nur eine Kopie des zugeschnittenen Abschnitts erstellen möchten, sollten Sie eine Methode in Betracht ziehen.

Das bringt uns zum zweiten Problem. Zum Glück ist es kein so großes Problem wie das erste. getSubImage verwendet dasselbe Datenarray wie das Originalbild. Das bedeutet, dass das gesamte Originalbild noch gespeichert ist. Angenommen, wenn Sie das Bild "zuschneiden", möchten Sie tatsächlich ein kleineres Bild, müssen Sie es als neues Bild neu zeichnen, anstatt nur das Teilbild zu erhalten.

Versuche dies:

BufferedImage img = image.getSubimage(startX, startY, endX, endY); //fill in the corners of the desired crop location here
BufferedImage copyOfImage = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics g = copyOfImage.createGraphics();
g.drawImage(img, 0, 0, null);
return copyOfImage; //or use it however you want

Diese Technik gibt Ihnen das zugeschnittene Bild, das Sie suchen, ohne den Link zurück zum Originalbild. Dies bewahrt die Integrität des Originalbilds und erspart Ihnen den Speicheraufwand für das Speichern des größeren Bildes. (Wenn Sie das Originalbild später ausgeben)

Joshua Zollinger
quelle
Sie hätten einfach die Funktion clone () der Klasse Object verwenden können.
Skaldebane
15

Dies ist eine Methode, die funktionieren wird:

import java.awt.image.BufferedImage;
import java.awt.Rectangle;
import java.awt.Color;
import java.awt.Graphics;

public BufferedImage crop(BufferedImage src, Rectangle rect)
{
    BufferedImage dest = new BufferedImage(rect.getWidth(), rect.getHeight(), BufferedImage.TYPE_ARGB_PRE);
    Graphics g = dest.getGraphics();
    g.drawImage(src, 0, 0, rect.getWidth(), rect.getHeight(), rect.getX(), rect.getY(), rect.getX() + rect.getWidth(), rect.getY() + rect.getHeight(), null);
    g.dispose();
    return dest;
}

Natürlich müssen Sie Ihre eigene JComponent erstellen:

import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.awt.Rectangle;
import java.awt.Graphics;
import javax.swing.JComponent;

public class JImageCropComponent extends JComponent implements MouseListener, MouseMotionListener
{
   private BufferedImage img;
   private int x1, y1, x2, y2;

   public JImageCropComponent(BufferedImage img)
   {
       this.img = img;
       this.addMouseListener(this);
       this.addMouseMotionListener(this);
   }

   public void setImage(BufferedImage img)
   {
       this.img = img;
   }

   public BufferedImage getImage()
   {
       return this;
   }

   @Override
   public void paintComponent(Graphics g)
   {
      g.drawImage(img, 0, 0, this);
      if (cropping)
      {
          // Paint the area we are going to crop.
          g.setColor(Color.RED);
          g.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.max(x1, x2), Math.max(y1, y2));
      }
   }

   @Override
   public void mousePressed(MouseEvent evt)
   {
       this.x1 = evt.getX();
       this.y1 = evt.getY();
   }

   @Override
   public void mouseReleased(MouseEvent evt)
   {
       this.cropping = false;
       // Now we crop the image;
       // This is the method a wrote in the other snipped
       BufferedImage cropped = crop(new Rectangle(Math.min(x1, x2), Math.min(y1, y2), Math.max(x1, x2), Math.max(y1, y2));
       // Now you have the cropped image;
       // You have to choose what you want to do with it
       this.img = cropped;
   }

   @Override
   public void mouseDragged(MouseEvent evt)
   {
       cropping = true;
       this.x2 = evt.getX();
       this.y2 = evt.getY();
   }

   //TODO: Implement the other unused methods from Mouse(Motion)Listener

}

Ich habe es nicht getestet. Vielleicht gibt es einige Fehler (ich bin mir nicht sicher über alle Importe).

Sie können die crop(img, rect)Methode in diese Klasse einfügen. Hoffe das hilft.

Martijn Courteaux
quelle
1
Vielen Dank für die Antwort, aber es gibt viele Fehler! Kannst du mir einen einfachen Code zum Zuschneiden eines Bildes sagen?
Hussain
11
File fileToWrite = new File(filePath, "url");

BufferedImage bufferedImage = cropImage(fileToWrite, x, y, w, h);

private BufferedImage cropImage(File filePath, int x, int y, int w, int h){

    try {
        BufferedImage originalImgage = ImageIO.read(filePath);

        BufferedImage subImgage = originalImgage.getSubimage(x, y, w, h);



        return subImgage;
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
}
Pankaj Mandale
quelle
6

Diese Frage enthält nicht genügend Informationen, um sie zu beantworten. Eine allgemeine Lösung (abhängig von Ihrem GUI-Framework): Fügen Sie einen Maus-Ereignishandler hinzu, der Klicks und Mausbewegungen erfasst. Dies gibt Ihnen Ihre (x, y) Koordinaten. Verwenden Sie als Nächstes diese Koordinaten, um Ihr Bild zuzuschneiden.

Maurits Rijk
quelle
2

Sie müssen etwas über die Java Image-API und die mausbezogene API lesen, möglicherweise irgendwo unter der java.awt.event package.

Zunächst müssen Sie in der Lage sein, das Bild zu laden und auf dem Bildschirm anzuzeigen. Vielleicht verwenden Sie ein JPanel.

Von dort aus werden Sie versuchen, eine Mausbewegungs-Listener-Schnittstelle und andere verwandte Schnittstellen zu implementieren. Vielleicht sind Sie an die mouseDraggedMethode gebunden ...

Für eine mousedraggedAktion erhalten Sie die Koordinate der Rechteckform durch Ziehen ...

Aus diesen Koordinaten erhalten Sie dann das Teilbild des Bildes, das Sie haben, und Sie zeichnen es neu.

Und dann das zugeschnittene Bild anzeigen ... Ich weiß nicht, ob das funktionieren wird, nur ein Produkt meiner Fantasie ... nur ein Gedanke!

Ultrajohn
quelle
1

Ich gebe dieses Beispiel, weil dies tatsächlich für meinen Anwendungsfall funktioniert.

Ich habe versucht, die AWS Rekognition API zu verwenden . Die API gibt ein BoundingBox-Objekt zurück:

BoundingBox boundingBox = faceDetail.getBoundingBox();

Der folgende Code verwendet es, um das Bild zuzuschneiden:

import com.amazonaws.services.rekognition.model.BoundingBox;

private BufferedImage cropImage(BufferedImage image, BoundingBox box) {
        Rectangle goal = new Rectangle(Math.round(box.getLeft()* image.getWidth()),Math.round(box.getTop()* image.getHeight()),Math.round(box.getWidth() * image.getWidth()), Math.round(box.getHeight() * image.getHeight()));

        Rectangle clip = goal.intersection(new Rectangle(image.getWidth(), image.getHeight()));

        BufferedImage clippedImg = image.getSubimage(clip.x, clip.y , clip.width, clip.height);

        return clippedImg;
    }
edubriguenti
quelle
Wie diese BoundingBox an die Funktion übergeben wird, erklären Sie bitte besser, da Sie Ihre Funktion nicht verwenden können.
Vijay
Entschuldigung für die Verzögerung @vijay. Das BoundingBox-Objekt ist ein Objekt aus der AWS-Erkennungs-API.
Edubriguenti