Як обрізати зображення на Java?


75

Я хочу обрізати зображення вручну за допомогою миші.
Припустимо, що зображення має якийсь текст, і я хочу виділити якийсь текст із зображення, то для цього я хочу обрізати цю область за допомогою миші.


Кілька хороших ідей нижче. Дивіться також java.sun.com/docs/books/tutorial/2d
trashgod

Хуссейн: дайте одну з цих детальних відповідей перевірку
IcedDante

Відповіді:


153

Рішення, яке я вважав найбільш корисним для обрізання буферизованого зображення, використовує getSubImage (x, y, w, h);

Моя процедура обрізання закінчилася виглядати так:

  private BufferedImage cropImage(BufferedImage src, Rectangle rect) {
      BufferedImage dest = src.getSubimage(0, 0, rect.width, rect.height);
      return dest; 
   }

59
чому б не включити також координати x & y. BufferedImage dest = src.getSubimage(rect.x, rect.y, rect.width, rect.height);
Сортер

46

Існує дві потенційно великі проблеми з провідною відповіддю на це питання. По-перше, згідно з документами:

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

Повертає субзображення, визначене вказаною прямокутною областю. Повернутий BufferedImage використовує той самий масив даних, що і вихідне зображення.

По суті, це означає, що результат getSubimage діє як покажчик, який вказує на підрозділ вихідного зображення.

Чому це важливо? Добре, якщо ви плануєте редагувати субзображення з будь-якої причини, редагування також відбуватиметься до вихідного зображення. Наприклад, я зіткнувся з цією проблемою, коли використовував менше зображення в окремому вікні для збільшення вихідного зображення. (на зразок лупи). Я дав можливість інвертувати кольори, щоб легше бачити певні деталі, але область, яку «збільшили», також перетворилася на оригінальне зображення! Тож був невеликий фрагмент оригінального зображення, який мав перевернуті кольори, тоді як решта залишалася нормальним. У багатьох випадках це не має значення, але якщо ви хочете відредагувати зображення або якщо вам потрібна просто копія обрізаного розділу, можливо, вам слід розглянути метод.

Що підводить нас до другої проблеми. На щастя, це не така велика проблема, як перша. getSubImage використовує той самий масив даних, що і вихідне зображення. Це означає, що все оригінальне зображення все ще зберігається в пам'яті. Якщо припустити, що, "обрізавши" зображення, ви насправді хочете зменшити зображення, вам потрібно буде перемалювати його як нове зображення, а не просто отримати субзображення.

Спробуйте це:

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

Цей прийом надасть вам обрізане зображення, яке ви шукаєте, без посилання на вихідне зображення. Це збереже цілісність оригінального зображення, а також заощадить витрати пам’яті на зберігання більшого зображення. (Якщо ви дамп оригінального зображення пізніше)


Ви могли б просто використовувати функцію clone () класу Object.
Скальдебане

15

Це метод, який буде працювати:

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

Звичайно, вам потрібно створити власний JComponent:

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

}

Я не тестував. Можливо, є якісь помилки (я не впевнений у всьому імпорті).

Ви можете помістити crop(img, rect)метод у цей клас. Сподіваюся, це допомагає.


1
дякую за відповідь, але це дає багато помилок! можеш сказати мені простий код для обрізання зображення?
Хуссен

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

6

На це запитання недостатньо інформації для відповіді. Загальне рішення (залежно від вашого графічного інтерфейсу): додайте обробник подій миші, який буде фіксувати клацання та рухи миші. Це дасть вам ваші координати (x, y). Далі використовуйте ці координати, щоб обрізати зображення.


2

Вам потрібно прочитати про Java Image API та пов'язаний з мишею API, можливо, десь під java.awt.event package.

Для початку вам потрібно вміти завантажувати та відображати зображення на екрані, можливо, ви будете використовувати JPanel.

Потім ви спробуєте реалізувати інтерфейс слухача руху миші та інші пов’язані інтерфейси. Можливо, ви зв’яжетесь із mouseDraggedметодом ...

Для mousedraggedдії ви отримаєте координату форми прямокутника шляхом перетягування ...

Потім за цими координатами ви отримаєте прообраз із зображення, яке у вас є, і ви перекреслюєте його заново ....

А потім покажіть обрізане зображення ... Я не знаю, чи це спрацює, лише продукт моєї уяви ... просто думка!


1

Я наводжу цей приклад, оскільки це насправді працює для мого випадку використання.

Я намагався використовувати API перезначення AWS . API повертає об'єкт BoundingBox:

BoundingBox boundingBox = faceDetail.getBoundingBox();

Код нижче використовує його для обрізання зображення:

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

Як цей BoundingBox передається функції, будь ласка, поясніть це краще, не вдавшись використати вашу функцію.
vijay

Вибачте за затримку @vijay. Об'єкт boundingBox - це об'єкт із API рекогнітування AWS.
edubriguenti
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.