Как создать объект Area с помощью PathIterator? - PullRequest
0 голосов
/ 10 мая 2018

Я явно упускаю важную концепцию здесь. Я написал код, используя события мыши, чтобы нарисовать границу (многоугольник) на существующем 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();
}

Все отлично работает, и я могу сохранить изображение с моим рисунком на нем: изображение с рисунком Список вершин (pts) и отрезки (сегменты) линии - все, что описывает область / форму / многоугольник. Я хочу извлечь из исходного изображения только ту область, которая находится внутри границы. То есть я планирую создать новый BufferedImage, перемещаясь по всем пикселям, проверяя, попадают ли они в фигуру, и сохраняя их, если они это делают. Поэтому я хочу создать ОБЛАСТЬ из точек и сегментов, которые я собрал при рисовании фигуры. Все говорит: создайте переменную AREA и getPathIterator. Но в какой форме? Моя переменная AREA будет пустой. Как итератор пути получает доступ к точкам в моем списке?

Я был по всей литературе и на этом сайте. Я что-то упускаю.

1 Ответ

0 голосов
/ 11 мая 2018

Спасибо, haraldK за ваше предложение. Прежде чем я увидел ваш пост, я пришел к аналогичному выводу: Используя Arraylist для вершин из операции рисования, я заполнил объект Path2D.Float, называемый «контур», просматривая список точек, созданный во время операции «рисования». Используя этот «контурный» объект, я создал экземпляр Area под названием «интерферограмма». Просто чтобы проверить мою работу, я создал еще один 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) за рутину deepCopy , которую я нашел на этом сайте. Применение моей маски к скопированному изображению привело к той части исходного изображения, которую я хотел, без линий маски. Результат показан на прикрепленной картинке. Я в восторге! Маскированное изображение

...