如何在 Java 中裁剪图像?

Posted

技术标签:

【中文标题】如何在 Java 中裁剪图像?【英文标题】:How do I crop an image in Java? 【发布时间】:2010-03-05 10:43:00 【问题描述】:

我想使用鼠标手动裁剪图像。 假设图像有一些文字,我想从图像中选择一些文字,然后 为此,我想使用鼠标裁剪该区域。

【问题讨论】:

以下几个好主意。另见java.sun.com/docs/books/tutorial/2d 侯赛因:请给出这些详细答案之一 【参考方案1】:

我发现对裁剪缓冲图像最有用的解决方案是使用 getSubImage(x,y,w,h);

我的裁剪程序最终看起来像这样:

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

【讨论】:

为什么不包括 x & y 坐标。 BufferedImage dest = src.getSubimage(rect.x, rect.y, rect.width, rect.height);【参考方案2】:

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

公共 BufferedImage getSubimage(int x, 整数, 诠释 w, 诠释 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() 函数。【参考方案3】:

这是一个可行的方法:

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) 方法放在此类中。 希望这会有所帮助。

【讨论】:

感谢您的回复,但它给出了很多错误!你能告诉我一个简单的代码来裁剪图像吗?【参考方案4】:
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;
    

【讨论】:

【参考方案5】:

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

【讨论】:

【参考方案6】:

您需要阅读有关 Java Image API 和鼠标相关 API 的信息,可能在 java.awt.event package 下的某个地方。

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

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

对于一个mousedragged的动作,你会通过拖动得到矩形窗体的坐标...

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

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

【讨论】:

【参考方案7】:

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

我尝试使用 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。 boundingBox 对象是来自 AWS rekognintion API 的对象。

以上是关于如何在 Java 中裁剪图像?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 OS Lollipop 在 Java 中为 Android 裁剪图像

如何使用 Java 裁剪图像而不将其加载到内存中

如何在opencv java中裁剪检测到的面部图像

如何在 J2ME 中裁剪图像

如何裁剪来自java端的动态图像?

使用 Java 裁剪图像