【问题标题】:Apply stroke to an image in Java将笔画应用于Java中的图像
【发布时间】:2012-08-23 10:41:27
【问题描述】:

我想在 Java 中对图像应用描边(轮廓)。在阅读了thisthis 之后,看起来Java2D API 只将笔划应用于形状?当然,我可以进行位图填充,然后对该形状应用笔触,但我想知道是否可以直接在给定的位图上应用它。

更新: 我设法应用描边位勾勒出整个图像。我的图像具有 PNG 透明度。如何仅在图像的可见像素周围应用描边?

 public static void main(String[] args) {
    try {
        // TODO code application logic here
        URL u = GraphicsDemo.class.getResource("Capture222.png");
        BufferedImage img = ImageIO.read(new File(u.getPath()));
        System.out.print("loaded");
        Graphics2D g = img.createGraphics();
        Rectangle2D tr = new Rectangle2D.Double(0, 0,
                img.getWidth(), img.getHeight());
        // Create the TexturePaint.
        TexturePaint tp = new TexturePaint(img, tr);
        g.setStroke(new BasicStroke(20));
        g.setPaint(Color.ORANGE);
        //   g.fill(tr);
        g.draw(tr);


        ImageIO.write(img, "PNG", new File("myeditedimage.png"));
        g.dispose();
    } catch (IOException ex) {
        Logger.getLogger(GraphicsDemo.class.getName()).log(Level.SEVERE, null, ex);
    }
 } 

更新 1: 我不确定使用 Java Graphics API 是否可以尝试做。再一次。我需要根据可见像素轮廓而不是围绕它的边界框来勾勒图像。 这就是我想要实现的目标:

【问题讨论】:

    标签: java image image-processing java-2d stroke


    【解决方案1】:

    是的,Java2D API 仅将笔划应用于形状。你可以做两件事:

    根据bitmap 图像的透明度信息创建一个Shape,这样您就可以只描边不透明的部分。这在任何语言中都很困难,因为这意味着将位图信息转换为vector-based information

    检查这个:Image/Graphic into a Shape

    还有这个:Smoothing a jagged path

    但基本上我会尽量避免转换问题,并以仅位图的方式解决它 - 例如,对可以在给定像素处找到透明像素的那些像素(使用“描边颜色”)着色-distance(“笔画宽度”)。

    【讨论】:

      【解决方案2】:
      • 首先,通过调用setStroke() 告诉Graphics2D 您希望如何绘制轮廓。此方法接受任何实现java.awt.Stroke interface 的对象。 2D API 带有一个类 java.awt.BasicStroke,它实现了常见的描边选项。
      • 使用setPaint() 告诉Graphics2D 应该如何绘制轮廓本身。轮廓,就像形状的内部一样,可以使用颜色、渐变、纹理或任何其他实现 Paint 接口的东西来绘制。
      • 使用 Graphics2D 的draw() 方法绘制形状的轮廓。 Graphics2D 使用步骤 1 中的 Stroke 来确定轮廓的外观。第 2 步中的 Paint 用于实际渲染轮廓。

      Graphics2D 使用 Stroke 来确定特定形状的轮廓是什么样子。当您询问Graphics2Ddraw() 一个形状时,它会询问它的 Stroke 形状的轮廓应该是什么样子。有趣的是,Stroke 将描边的轮廓作为另一种形状返回:

      public abstract Shape createStrokedShape(Shape p)
      

      此方法返回一个表示所提供形状的描边轮廓的形状。 这是 Stroke 中唯一的方法。通常,您不会自己调用它,Graphics2D 会在您 draw() 形状时代表您调用它。

      Graphics2D 上调用draw() 等效于以下代码:

      public void longwindedDraw(Graphics2D g2, Shape s) 
      {
          Stroke stroke = g2.getStroke();
          Shape strokedOutline = stroke.createStrokedShape(s);
          g2.fill(strokedOutline);
      }
      

      【讨论】:

        【解决方案3】:

        试试这个:

        final static BasicStroke dash_stroke =new BasicStroke(1.0f,
                                BasicStroke.CAP_BUTT,
                                BasicStroke.JOIN_MITER,
                                10.0f, dash1, 0.0f);
        

        然后设置 Stroke :

        g2.getStroke()
        

        【讨论】:

          【解决方案4】:

          要获取在位图上绘制的 Graphics2D 对象,您应该使用 BufferedImage。

          BufferedImage img = ImageIO.read(new File("myimage.png"));
          Graphics2D g = img.createGraphics();
          
          // Paint on it like you want here...
          
          
          g.dispose();
          ImageIO.write(img, "PNG", new File("myeditedimage.png"));
          

          【讨论】:

          • 你还没有解释最重要的部分。我使用 g.setStroke() 应用了笔触,然后用红色绘制并保存。没有任何改变。我错过了什么?
          【解决方案5】:

          像这样?如果没有,请附上显示所需结果的图片。

          import java.awt.*;
          import java.awt.image.BufferedImage;
          import java.net.URL;
          import javax.imageio.ImageIO;
          import javax.swing.*;
          
          public class StrokedImage {
          
              public BufferedImage getStrokedImage(
                      BufferedImage bi, Shape shape, int strokeWidth) {
                  int w = bi.getWidth();
                  int h = bi.getHeight();
                  BufferedImage bib = new BufferedImage(w,h,bi.getType());
                  Graphics2D g = bib.createGraphics();
          
                  BasicStroke bs = new BasicStroke(strokeWidth);
                  g.setStroke(bs);
                  Rectangle rect = new Rectangle(0,0,w,h); 
                  TexturePaint tp = new TexturePaint(bi, rect); 
                  g.setPaint(tp);
                  g.draw(shape);
          
                  g.dispose();
                  return bib;
              }
          
              public static void main(String[] args) throws Exception {
                  URL url = new URL("http://pscode.org/media/stromlo1.jpg");
                  final BufferedImage bi = ImageIO.read(url);
                  SwingUtilities.invokeLater(new Runnable(){
                      @Override
                      public void run() {
                          StrokedImage si = new StrokedImage();
          
                          int strokeWidth = 12;
                          int pad = 50;
                          Shape shape = new Rectangle(
                                  pad,pad,
                                  bi.getWidth()-(2*pad),bi.getHeight()-(2*pad)); 
                          Image i = si.getStrokedImage(bi, shape, strokeWidth);
          
                          JPanel p = new JPanel(new GridLayout(1,0,5,5));
                          p.add(new JLabel(new ImageIcon(i)));
                          p.add(new JLabel(new ImageIcon(bi)));
                          JOptionPane.showMessageDialog(null, p);
                      }
                  });
              }
          }
          

          发布问题编辑 - 更新

          看看this answer。它在绘制图像之前应用Shape 的剪辑。然后它清除剪辑并将Shape 本身绘制为边框。

          【讨论】:

          • 请参阅“发布问题编辑 - 更新”并注意我们不会自动收到问题编辑通知。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-11
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多