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.
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)
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;
publicclassJImageCropComponentextendsJComponentimplementsMouseListener, MouseMotionListener{
private BufferedImage img;
privateint x1, y1, x2, y2;
publicJImageCropComponent(BufferedImage img){
this.img = img;
this.addMouseListener(this);
this.addMouseMotionListener(this);
}
publicvoidsetImage(BufferedImage img){
this.img = img;
}
public BufferedImage getImage(){
returnthis;
}
@OverridepublicvoidpaintComponent(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));
}
}
@OverridepublicvoidmousePressed(MouseEvent evt){
this.x1 = evt.getX();
this.y1 = evt.getY();
}
@OverridepublicvoidmouseReleased(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 itthis.img = cropped;
}
@OverridepublicvoidmouseDragged(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.
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.
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!
Antworten:
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; }
quelle
BufferedImage dest = src.getSubimage(rect.x, rect.y, rect.width, rect.height);
Es gibt zwei potenziell große Probleme mit der führenden Antwort auf diese Frage. Erstens, wie in den Dokumenten beschrieben:
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)
quelle
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.quelle
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; } }
quelle
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.
quelle
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
mouseDragged
Methode gebunden ...Für eine
mousedragged
Aktion 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!
quelle
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:
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; }
quelle