【问题标题】:How do I create an Area object using a PathIterator?如何使用 PathIterator 创建一个 Area 对象?
【发布时间】:2018-10-20 03:47:18
【问题描述】:

我显然在这里遗漏了一个重要概念。我已经编写了使用鼠标事件在现有 BufferedImage 上绘制边界(多边形)的代码。以下是相关部分:

public void paintComponent(Graphics g) 
{
    super.paintComponent(g);  //Paint parent's background

    //G3 displays the BufferedImage "Drawing" with each paint
    Graphics2D G3 = (Graphics2D)g;
    G3.drawImage(this.Drawing, 0, 0, null);
    G3.dispose();
} 

public void updateDrawing()
{               
    int x0, y0, x1, y1; // Vertex coordinates
    Line2D.Float seg;
    // grafix is painting the mouse drawing to the BufferedImage "Drawing"     
    if(this.pts.size() > 0)
    {                   
        for(int ip = 0; ip < pts.size(); ip++)
        {
            x0 = (int)this.pts.get(ip).x;
            y0 = (int)this.pts.get(ip).y;
            this.grafix.drawRect(x0 - this.sqw/2, y0 - this.sqh/2, + this.sqw, this.sqh);
            if (ip > 0)
            {
                x1 = (int)this.pts.get(ip-1).x;
                y1 = (int)this.pts.get(ip-1).y; 
                this.grafix.drawLine(x1, y1, x0, y0);
                seg = new Line2D.Float(x1, y1, x0, y0);
                this.segments.add(seg);
            }
        }
    }
    repaint();
}

接下来的两个例程由鼠标事件调用:左键单击获取下一个点,右键单击关闭该区域。

public void getNextPoint(Point2D p)
{
    this.isDrawing = true;
    Point2D.Float next = new Point2D.Float();
    next.x = (float) p.getX();
    next.y = (float) p.getY();
    this.pts.add(next);
    updateDrawing();
}

public void closeBoundary()
{
    //Connects the last point to the first point to close the loop
    Point2D.Float next = new Point2D.Float(this.pts.get(0).x, this.pts.get(0).y);
    this.pts.add(next);
    this.isDrawing = false;
    updateDrawing();
}

一切正常,我可以保存带有我的绘图的图像: image with drawing 顶点(pts)列表和线段(segments)都是描述区域/形状/多边形的。 我希望仅从原始图像中提取边界内的区域。也就是说,我计划通过移动所有像素来创建一个新的 BufferedImage,测试它们是否落入图中,如果有则保留它们。 所以我想根据我在绘制形状时收集的点和线段创建一个区域。一切都在说:创建一个 AREA 变量和“getPathIterator”。但在什么形状上?我的 AREA 变量将为空。路径迭代器如何访问我列表中的点?

我也浏览过文献和这个网站。 我错过了一些东西。

【问题讨论】:

  • 在绘画时存储所有点,然后从点创建一个Polygon。如果需要,从它创建一个Area (new Area(polygon))。但您也可以直接从Polygon 创建一个PathIterator。很难确切地说出您为什么要这样做...也许有关您尝试做的一些伪代码会有所帮助。

标签: java bufferedimage shapes area


【解决方案1】:

感谢 haraldK 的建议。在我看到你的帖子之前,我得出了类似的结论: 使用绘制操作中的顶点数组列表,我通过遍历在“绘制”操作期间创建的点列表填充了一个名为“contour”的“Path2D.Float”对象。使用这个“轮廓”对象,我实例化了一个名为“干涉图”的区域。为了检查我的工作,我从区域创建了另一个 PathIterator“PI”,并将区域“干涉图”分解为“段”,将结果发送到控制台。我在下面显示代码:

private void mnuitmKeepInsideActionPerformed(java.awt.event.ActionEvent evt)                                                 
{                                                     
    // Keeps the inner area of interest
    // Vertices is the "pts" list from Class MouseDrawing (mask)
    // It is already a closed path
    ArrayList<Point2D.Float> vertices = 
            new ArrayList<>(this.mask.getVertices()); 
    this.contour = new Path2D.Float(Path2D.WIND_NON_ZERO);

    // Read the vertices into the Path2D variable "contour"
    this.contour.moveTo((float)vertices.get(0).getX(), 
        (float)vertices.get(0).getY()); //Starting location

    for(int ivertex = 1; ivertex < vertices.size(); ivertex++)
    {
        this.contour.lineTo((float)vertices.get(ivertex).getX(), 
            (float)vertices.get(ivertex).getY());                           
    }      
    this.interferogram = new Area(this.contour);        
    PathIterator PI = this.interferogram.getPathIterator(null);

    //Test print out the segment types and vertices for debug
    float[] p = new float[6];
    int icount = 0;
    while( !PI.isDone())
    {
        int type = PI.currentSegment(p);
        System.out.print(icount);
        System.out.print(" Type " + type);
        System.out.print(" X " + p[0]);
        System.out.println(" Y " + p[1]);
        icount++;
        PI.next();
    }

    BufferedImage masked = Mask(this.image_out, this.interferogram);
    // Write image to file for debug
    String dir;
    dir = System.getProperty("user.dir");
    dir = dir + "\\00masked.png";
    writeImage(masked, dir, "PNG");

}                                                

接下来,我将遮罩应用到图像上,使用以下代码测试每个像素是否包含在该区域中:

public BufferedImage Mask(BufferedImage BIM, Area area)
{
    /** Loop through the pixels in the image and test each one for inclusion
    *   within the area.
    *   Change the colors of those outside
    **/

    Point2D p = new Point2D.Double(0,0);
    // rgb should be white
    int rgb = (255 << 24);
    for (int row = 0; row < BIM.getWidth(); row++)
    {
        for (int col = 0; col < BIM.getHeight(); col++)
        {
            p.setLocation(col, row);
            if(!area.contains(p))
            {
                BIM.setRGB(col, row, rgb);
            }
        }
    }
    return BIM;
}
public static BufferedImage deepCopy(BufferedImage B2M) 
{
    ColorModel cm = B2M.getColorModel();
    boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
    WritableRaster raster = B2M.copyData(B2M.getRaster()
            .createCompatibleWritableRaster());
    return new BufferedImage(cm, raster, isAlphaPremultiplied, null);
}

这效果很好(我很惊讶!),除了一个细微的细节:该区域的线条出现在蒙版图像的外部周围。 为了解决这个问题,我在绘画操作之前复制了原始(调整大小的)图像。非常感谢 user1050755(2014 年 11 月)为我在本网站上找到的例程 deepCopy。将我的蒙版应用于复制的图像会导致我想要的原始图像部分没有蒙版线。结果显示在附图中。我很兴奋! masked image

【讨论】:

    猜你喜欢
    • 2016-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多