如何在Java中裁剪图像?


Answers:


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);
Sorter

46

这个问题的主要答案有两个潜在的主要问题。首先,根据文档:

公共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

此技术将为您提供您正在寻找的裁剪图像,而无需链接回到原始图像。这将保留原始图像的完整性,并为您节省存储较大图像的内存开销。(如果以后要转储原始图像)


您可以简单地使用Object类的clone()函数。
Skaldebane

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

这个问题没有足够的信息来回答。通用解决方案(取决于您的GUI框架):添加鼠标事件处理程序,以捕获单击和鼠标移动。这将为您提供(x,y)坐标。接下来,使用这些坐标来裁剪图像。


2

您需要阅读Java Image API和与鼠标相关的API,也许在下方java.awt.event package

首先,您需要能够加载图像并将其显示在屏幕上,也许您将使用JPanel

然后,从那里开始,您将尝试实现鼠标运动侦听器接口和其他相关接口。也许您会被束缚在mouseDragged方法...

对于mousedragged动作,您将通过拖动获得矩形形式的坐标。

然后从这些坐标中,您将从所拥有的图像中获得子图像,然后重新绘制它。

然后显示裁剪的图像...我不知道这是否行得通,只是我的想象力的产物...只是一个想法!


1

我给出这个例子是因为这实际上适用于我的用例。

我正在尝试使用AWS Rekognition API。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 '18

对不起@vijay的延迟。boundingBox对象是AWS rekognintion API中的对象。
edubriguenti
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.