参考论文:
http://www.cs.ucla.edu/~rothrock/pages/cvpr13/
在标注part的时候 先标注part的状态,然后才标注part的bounding box
(用一条直线和两个点(这两个点是另外一条直线的简化)来表示,即模拟一个bounding box,为了方便标注,其中 non-occluded 和 Default 是默认的)
*******************************
鼠标左键:确认点和当前线段
鼠标右键:取消点和当前线段
0: non-occluded, // default
1: partial-occluded,
2: full-occluded
3: right, // head
4: left, // head
5: front, // head
6: wide, // torse
7: narrow // torse
u: back to pre-part
n: ahead to next-part
r: reset the current image
s: save
a: back to pre-image
d: ahead to next image
********************************
图片示例:
********************************
import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.datatransfer.DataFlavor; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.util.Arrays; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import javax.imageio.ImageIO; import javax.swing.JFrame; import javax.swing.JOptionPane; public class DatasetAnnotated_BB_Occ extends JFrame implements DropTargetListener { private static final long serialVersionUID = 1L; private static String[] annoName = { "Head", "LUA", "LLA", "Torse", "RUA", "RLA", "LUL", "LLL", "RUL", "RLL" }; //private static int[] annoNameIndex = {3, 0, 1, 2, 4, 5, 6, 7, 8, 9}; private static int[] annoNameIndex = {3, 0, 4, 5, 1, 2, 8, 9, 6, 7}; private static String[] symbolNameForAG = { "Head", "UA", "LA", "Torse", "UA", "LA", "UL", "LL", "UL", "LL" }; private static String[] symbolNameForAOG = { "Head", "LUA", "LA", "Torse", "RUA", "LA", "LUL", "LLL", "RUL", "RLL" }; private static String[] symbolName = { "Head", "RUA", "LA", "Torse", "LUA", "LA", "RUL", "RLL", "LUL", "LLL", // ************************ "UA", "LA", "UL", "LL" }; private static String[] prodNameForAG = { "Default", // Head, RUA, RLA, LUA, LLA, RUL, RLL, LUL, LLL "Occluded", // RLA, LUA "", // nothing "", "", "", // nothing "Wide", "Narrow" // Torse }; private static String[] prodNameForAOG = { "Default", // Head, RUA, RLA, LUA, LLA, RUL, RLL, LUL, LLL "Occluded", // RLA, LUA "", // nothing "Right", "Left", "Front", // Head "Wide", "Narrow" // Torse }; private static String[] prodName = { "Default", "Occluded", "", "Right", "Left", "Front", "Wide", "Narrow" }; private Image offScreenImage = null; // avoid flicker private Graphics gOffScreenGraphics; // handler of the annotated image private Image initImage = null; // path to the annotated dataset private String path = null; // the image name without extension private String fileName = null; // image file list private LinkedList<File> file_list = new LinkedList<File>(); // index of images private int curFileIdx = 0; // if shift is pressed, then draw // horizontal or // vertical line. private boolean shift_flag = false; // flag to occlusion state // 0: non-occluded, 1: partial-occluded, 2: full-occluded private int[] isOccluded = new int[annoName.length]; // flag to production state // 0: default, // 1: occluded, // 3: right, 4: left, 5: front, // 6: wide, 7: narrow private int[] isDefault = new int[annoName.length]; // ??? private int[] points = new int[annoName.length * 4]; // each part is annotated by two line private static final int numXY = 4; private int[][] xPoints = new int[annoName.length][numXY]; private int[][] yPoints = new int[annoName.length][numXY]; // index of parts private int idx1 = 0; // index of line points private int idx2 = 0; private static final double scale = 1; private static final int _width = 300; private static final int _height = 300; private static final int _startX = 450; private static final int _startY = 180; private static final int border = 10; private static final int _startJframeX = 0; private static final int _startJframeY = 20; private static final int _circleLen = 3; public DatasetAnnotated_BB_Occ() { // setTitle("Dataset Annotation"); setSize(_width, _height); setLocation(_startX, _startY); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // button1: the left mouse button // button2: the mouse wheel // button3: the right mouse button addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { System.out.println("mouse click " + e.getButton()); if (initImage == null || idx1 == annoName.length || e.getButton() == MouseEvent.BUTTON2) return; if (e.getButton() == MouseEvent.BUTTON3) { xPoints[idx1][idx2] = 0; yPoints[idx1][idx2] = 0; idx2--; if (idx2 < 0) { // need to be reset isDefault[idx1] = 0; // set to be default isOccluded[idx1] = 2; // set to be full-occlusion Arrays.fill(xPoints[idx1], 0); Arrays.fill(yPoints[idx1], 0); idx2 = 0; } DatasetAnnotated_BB_Occ.this.repaint(); return; } // get the point location xPoints[idx1][idx2] = e.getX() - _startJframeX; yPoints[idx1][idx2] = e.getY() - _startJframeY; // System.out.println("mouse click point: (" + e.getX() + ", " + e.getY() + ")"); System.out.println("mouse click point: (" + xPoints[idx1][idx2] + ", " + yPoints[idx1][idx2] + ")"); if (xPoints[idx1][idx2] < border) xPoints[idx1][idx2] = border; if (xPoints[idx1][idx2] >= initImage.getWidth(null) + border) xPoints[idx1][idx2] = initImage.getWidth(null) + border - 1; if (yPoints[idx1][idx2] < border) yPoints[idx1][idx2] = border; if (yPoints[idx1][idx2] >= initImage.getHeight(null) + border) yPoints[idx1][idx2] = initImage.getHeight(null) + border - 1; if ((idx2 == 1 || idx2 == 3) && shift_flag && idx1 < annoName.length) { if (xPoints[idx1][idx2] != xPoints[idx1][idx2 - 1] && yPoints[idx1][idx2] != yPoints[idx1][idx2 - 1]) { double dy = yPoints[idx1][idx2] - yPoints[idx1][idx2 - 1] + 0.00; double dx = xPoints[idx1][idx2] - xPoints[idx1][idx2 - 1] + 0.00; double k = dy / dx; if (Math.abs(k) <= 1) { yPoints[idx1][idx2] = yPoints[idx1][idx2 - 1]; } else { xPoints[idx1][idx2] = xPoints[idx1][idx2 - 1]; } } } idx2++; if (idx2 == numXY) { // isOccluded[idx1] = 0; // set to be visual // isDefault[idx1] = ??? idx1++; idx2 = 0; } else if (idx2 == 1 || idx2 == 3) { xPoints[idx1][idx2] = xPoints[idx1][idx2 - 1]; yPoints[idx1][idx2] = yPoints[idx1][idx2 - 1]; } // repaint DatasetAnnotated_BB_Occ.this.repaint(); // if (idx1 == annoName.length) { int choice = JOptionPane.showConfirmDialog( DatasetAnnotated_BB_Occ.this, "complete! save annotation or not?", "tips", JOptionPane.YES_NO_OPTION ); if (choice == JOptionPane.YES_OPTION) { // save the annotation saveAnnotation(); // set next image if (file_list.size() > 1) setNextPic(1); } } } }); addMouseMotionListener(new MouseMotionAdapter() { @Override public void mouseMoved(MouseEvent e) { if (initImage == null || idx1 == annoName.length || idx2 == 0) return; // System.out.println("mouse move"); // get the point location -- keep idx2 xPoints[idx1][idx2] = e.getX() - _startJframeX; yPoints[idx1][idx2] = e.getY() - _startJframeY; // System.out.println("mouse move point: (" + e.getX() + ", " + e.getY() + ")"); System.out.println("mouse click point: (" + xPoints[idx1][idx2] + ", " + yPoints[idx1][idx2] + ")"); if (xPoints[idx1][idx2] < border) xPoints[idx1][idx2] = border; if (xPoints[idx1][idx2] >= initImage.getWidth(null) + border) xPoints[idx1][idx2] = initImage.getWidth(null) + border - 1; if (yPoints[idx1][idx2] < border) yPoints[idx1][idx2] = border; if (yPoints[idx1][idx2] >= initImage.getHeight(null) + border) yPoints[idx1][idx2] = initImage.getHeight(null) + border - 1; if ( (idx2 == 1 || idx2 == 3) && shift_flag && idx1 < annoName.length ) { if (xPoints[idx1][idx2] != xPoints[idx1][idx2 - 1] && yPoints[idx1][idx2] != yPoints[idx1][idx2 - 1]) { double dy = yPoints[idx1][idx2] - yPoints[idx1][idx2 - 1] + 0.00; double dx = xPoints[idx1][idx2] - xPoints[idx1][idx2 - 1] + 0.00; double k = dy / dx; if (Math.abs(k) <= 1) { yPoints[idx1][idx2] = yPoints[idx1][idx2 - 1]; } else { xPoints[idx1][idx2] = xPoints[idx1][idx2 - 1]; } } } // repaint repaint(); } }); // 0: non-occluded, 1: partial-occluded, 2: full-occluded // 3: right, 4: left, 5: front, // 6: wide, 7: narrow // u: back to pre-part // n: ahead to next-part // r: reset the current image // s: save // a: back to pre-image // d: ahead to next image addKeyListener(new KeyListener() { @Override public void keyTyped(KeyEvent e) { } // dose not modify @Override public void keyReleased(KeyEvent e) { switch (e.getKeyCode()) { case KeyEvent.VK_SHIFT: shift_flag = false; break; } } // need to be modified @Override public void keyPressed(KeyEvent e) { switch (Character.toLowerCase(e.getKeyChar())) { // back to pre-part case 'u': if (idx1 != 0) { System.out.println("u" + " " + annoName[idx1]); // current part -- need to be reset Arrays.fill(xPoints[idx1], 0); Arrays.fill(yPoints[idx1], 0); isDefault[idx1] = 0; // set to be default isOccluded[idx1] = 2; // set to be full-occlusion // if (idx2 == 0) idx1--; idx2 = 0; // pre part - need to be reseted isDefault[idx1] = 0; // set to be default isOccluded[idx1] = 2; // set to be full-occlusion Arrays.fill(xPoints[idx1], 0); Arrays.fill(yPoints[idx1], 0); } break; // save the annotation case 's': System.out.println("s" + " " + annoName[idx1] + " " + file_list.get(curFileIdx)); saveAnnotation(); break; // ahead to next part case 'n': // skip current annotation due to missing if (idx1 >= annoName.length) return; System.out.println("n" + " " + annoName[idx1]); Arrays.fill(xPoints[idx1], 0); Arrays.fill(yPoints[idx1], 0); isDefault[idx1] = 0; // set to be default isOccluded[idx1] = 2; // set to be full-occlusion idx1++; if (idx1 == annoName.length) { int choice = JOptionPane.showConfirmDialog( DatasetAnnotated_BB_Occ.this, "complete! save annotation or not?", "tips", JOptionPane.YES_NO_OPTION ); if (choice == JOptionPane.YES_OPTION) { // saveAnnotation(); // set and init next image if (file_list.size() > 1) setNextPic(1); } } idx2 = 0; break; // back to pre image case 'a': // set and init pre image System.out.println("a" + " " + file_list.get(curFileIdx)); setNextPic(0); break; // ahead to next image case 'd': // set and init next image //saveAnnotation(); ????? System.out.println("d" + " " + file_list.get(curFileIdx)); setNextPic(1); break; // reset the current image case 'r': System.out.println("r" + " " + file_list.get(curFileIdx)); idx1 = 0; idx2 = 0 ; for(int i = 0; i < annoName.length; i++) { Arrays.fill(xPoints[i], 0); Arrays.fill(yPoints[i], 0); } Arrays.fill(isOccluded, 2); Arrays.fill(isDefault, 0); break; // 1: partial occluded case '1': System.out.println("1" + " " + annoName[idx1]); isOccluded[idx1] = 1; break; // 2: full occluded case '2': System.out.println("2" + " " + annoName[idx1]); isOccluded[idx1] = 2; break; // 3: right case '3': System.out.println("3" + " " + annoName[idx1]); isDefault[idx1] = 3; break; // 4: left case '4': System.out.println("4" + " " + annoName[idx1]); isDefault[idx1] = 4; break; // 5: front case '5': System.out.println("5" + " " + annoName[idx1]); isDefault[idx1] = 5; break; // 6: wide case '6': System.out.println("6" + " " + annoName[idx1]); isDefault[idx1] = 6; break; // 7: narrow case '7': System.out.println("7" + " " + annoName[idx1]); isDefault[idx1] = 7; break; default: switch (e.getKeyCode()) { case KeyEvent.VK_ESCAPE: Arrays.fill(xPoints[idx1], 0); Arrays.fill(yPoints[idx1], 0); idx2 = 0; break; case KeyEvent.VK_SHIFT: shift_flag = true; break; } } // repaint DatasetAnnotated_BB_Occ.this.repaint(); } }); new DropTarget(this, this); setVisible(true); } protected void saveAnnotation() { saveAnnotationForAG(); saveAnnotationForAOG(); } protected void saveAnnotationForAG() { try { File file = new File(path + "/../AnnotationsForAG"); file.mkdir(); file = new File(path + "/../AnnotationsForAG/" + fileName + ".label"); BufferedWriter bw = new BufferedWriter(new FileWriter(file)); String str = ""; for (int j = 0; j < annoName.length; j++) { int i = annoNameIndex[j]; str = str + annoName[i]; str = str + " " + symbolNameForAOG[i] + " "; str = str + prodNameForAOG[isDefault[i]] + " "; // x - border // y - border // line 1 double x1 = Math.max( (xPoints[i][0] - border) / scale, 0 ); double y1 = Math.max( (yPoints[i][0] - border) / scale, 0 ); double x2 = Math.max( (xPoints[i][1] - border) / scale, 0 ); double y2 = Math.max( (yPoints[i][1] - border) / scale, 0 ); // line 2 double x3 = Math.max( (xPoints[i][2] - border) / scale, 0 ); double y3 = Math.max( (yPoints[i][2] - border) / scale, 0 ); double x4 = Math.max( (xPoints[i][3] - border) / scale, 0 ); double y4 = Math.max( (yPoints[i][3] - border) / scale, 0 ); double xx1, yy1; // bottom end point double xx2, yy2; // top end point double dx, dy; // ·-------------------> x // | // | // y if(annoName[i].equals("Head")) { xx1 = x2; yy1=y2; xx2 = x1; yy2 = y1; //dx = xx1 - xx2 + 0.00; //dy = yy1 - yy2 + 0.00; } else { xx1 = x1; yy1 = y1; xx2 = x2; yy2 = y2; //dx = xx2 - xx1 + 0.00; //dy = yy2 - yy1 + 0.00; } // dx = xx2 - xx1 + 0.00; dy = yy2 - yy1 + 0.00; /* * public static double atan2(double y, double x) * Returns the angle theta from the conversion of rectangular coordinates (x, y) * to polar coordinates (r, theta). This method computes the phase theta * by computing an arc tangent of y/x in the range of -pi to pi. */ double orientation = Math.atan2(dy, dx); // double orientation = 0; // if(x1 == x2) // orientation = Math.PI / 2; // else { // orientation = Math.atan(dy / dx); // // } double length = Math.sqrt( (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) ); double prodWidth = Math.sqrt( (x3 - x4) * (x3 - x4) + (y3 - y4) * (y3 - y4) ); double distWidth = prodWidth; str = str + xx1 + " " + yy1 + " " + orientation; str = str + " " + length + " " + prodWidth + " " + distWidth; str = str + " " + isOccluded[i] + " 0 \n"; } bw.write(str); bw.close(); } catch (Exception e) { e.printStackTrace(); JOptionPane.showMessageDialog(this, "failed to save annotation"); } } protected void saveAnnotationForAOG() { try { File file = new File(path + "/../AnnotationsForAOG"); file.mkdir(); file = new File(path + "/../AnnotationsForAOG/" + fileName + ".label"); BufferedWriter bw = new BufferedWriter(new FileWriter(file)); String str = ""; for (int j = 0; j < annoName.length; j++) { int i = annoNameIndex[j]; str = str + annoName[i]; str = str + " " + symbolNameForAOG[i] + " "; str = str + prodNameForAOG[isDefault[i]] + " "; // x - border // y - border // line 1 double x1 = Math.max( (xPoints[i][0] - border) / scale, 0 ); double y1 = Math.max( (yPoints[i][0] - border) / scale, 0 ); double x2 = Math.max( (xPoints[i][1] - border) / scale, 0 ); double y2 = Math.max( (yPoints[i][1] - border) / scale, 0 ); // line 2 double x3 = Math.max( (xPoints[i][2] - border) / scale, 0 ); double y3 = Math.max( (yPoints[i][2] - border) / scale, 0 ); double x4 = Math.max( (xPoints[i][3] - border) / scale, 0 ); double y4 = Math.max( (yPoints[i][3] - border) / scale, 0 ); double xx1, yy1; // bottom end point double xx2, yy2; // top end point double dx, dy; // ·-------------------> x // | // | // y if(annoName[i].equals("Head")) { xx1 = x2; yy1=y2; xx2 = x1; yy2 = y1; //dx = xx1 - xx2 + 0.00; //dy = yy1 - yy2 + 0.00; } else { xx1 = x1; yy1 = y1; xx2 = x2; yy2 = y2; //dx = xx2 - xx1 + 0.00; //dy = yy2 - yy1 + 0.00; } // dx = xx2 - xx1 + 0.00; dy = yy2 - yy1 + 0.00; /* * public static double atan2(double y, double x) * Returns the angle theta from the conversion of rectangular coordinates (x, y) * to polar coordinates (r, theta). This method computes the phase theta * by computing an arc tangent of y/x in the range of -pi to pi. */ double orientation = Math.atan2(dy, dx); // double orientation = 0; // if(x1 == x2) // orientation = Math.PI / 2; // else { // orientation = Math.atan(dy / dx); // // } double length = Math.sqrt( (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) ); double prodWidth = Math.sqrt( (x3 - x4) * (x3 - x4) + (y3 - y4) * (y3 - y4) ); double distWidth = prodWidth; str = str + xx1 + " " + yy1 + " " + orientation; str = str + " " + length + " " + prodWidth + " " + distWidth; str = str + " " + isOccluded[i] + " 0 \n"; } bw.write(str); bw.close(); } catch (Exception e) { e.printStackTrace(); JOptionPane.showMessageDialog(this, "failed to save annotation"); } } @Override public void update(Graphics g) { if (initImage == null) return; if (offScreenImage == null || offScreenImage.getHeight(this) != this.getHeight() || offScreenImage.getWidth(this) != this.getWidth() ) { offScreenImage = this.createImage(this.getWidth(), this.getHeight()); gOffScreenGraphics = offScreenImage.getGraphics(); } int imgWidth = initImage.getWidth(null); int imgHeigth = initImage.getHeight(null); int oImgWidth = offScreenImage.getWidth(null); int oImgHeight = offScreenImage.getHeight(null); System.out.println("imgWidth: " + imgWidth + ", imgHeight: " + imgHeigth + ", oImgWidth: " + oImgWidth + ", oImgHeight: " + oImgHeight); // a top-left corner (border, border) gOffScreenGraphics.drawImage(initImage, border, border, this); ((Graphics2D) gOffScreenGraphics).setStroke(new BasicStroke(1.50f)); gOffScreenGraphics.setColor(Color.YELLOW); if (idx1 < annoName.length) gOffScreenGraphics.drawString(annoName[idx1], 10, 20); else gOffScreenGraphics.drawString("annotatation is done!", 10, 50); // draw the current line for (int i = 0; i < idx2; i += 2) { gOffScreenGraphics.drawLine(xPoints[idx1][i], yPoints[idx1][i], xPoints[idx1][i + 1], yPoints[idx1][i + 1]); } // draw the pre lines gOffScreenGraphics.setColor(Color.GREEN); for (int i = 0; i < idx1 && i < annoName.length; i++) for(int j = 0; j < numXY; j += 2) { // gOffScreenGraphics.drawLine(xPoints[i][j], yPoints[i][j], xPoints[i][j + 1], yPoints[i][j + 1]); // gOffScreenGraphics.drawOval(xPoints[i][j], yPoints[i][j], _circleLen, _circleLen); // gOffScreenGraphics.drawOval(xPoints[i][j + 1], yPoints[i][j + 1], _circleLen, _circleLen); // gOffScreenGraphics.fillOval(xPoints[i][j], yPoints[i][j], _circleLen, _circleLen); // gOffScreenGraphics.fillOval(xPoints[i][j + 1], yPoints[i][j + 1], _circleLen, _circleLen); if(j < 1) { gOffScreenGraphics.drawLine(xPoints[i][j], yPoints[i][j], xPoints[i][j + 1], yPoints[i][j + 1]); } else { gOffScreenGraphics.fillOval(xPoints[i][j], yPoints[i][j], _circleLen, _circleLen); gOffScreenGraphics.fillOval(xPoints[i][j + 1], yPoints[i][j + 1], _circleLen, _circleLen); } } // paint(gOffScreen); g.drawImage(offScreenImage, _startJframeX, _startJframeY, this); g.dispose(); } @Override public void paint(Graphics g) { update(g); } @Override public void dragEnter(DropTargetDragEvent dtde) { } @Override public void dragOver(DropTargetDragEvent dtde) { } @Override public void dropActionChanged(DropTargetDragEvent dtde) { } @Override public void dragExit(DropTargetEvent dte) { } // drop the images into UI // get the image file list @SuppressWarnings("rawtypes") @Override public void drop(DropTargetDropEvent dtde) { try { if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); List list = (List) (dtde.getTransferable() .getTransferData(DataFlavor.javaFileListFlavor)); Iterator iterator = list.iterator(); file_list.clear(); curFileIdx = -1; while (iterator.hasNext()) { File file = (File) iterator.next(); if (file.isDirectory()) { addFileToQueue(file); } else { if (file.getName().endsWith(".jpg") || file.getName().endsWith(".png")) file_list.add(file); } } setNextPic(1); dtde.dropComplete(true); } else { dtde.rejectDrop(); } } catch (Exception e) { e.printStackTrace(); dtde.rejectDrop(); JOptionPane.showMessageDialog(this, "Failed to open image"); } } // flag == 0 -- previous pic // flag == 1 -- next pic private void setNextPic(int flag) { int tmp = curFileIdx; if (flag == 0) { if (curFileIdx == 0) { JOptionPane.showMessageDialog(this, "The first one!"); return; } curFileIdx--; } else { curFileIdx++; } boolean ok = false; while (!ok) { try { if (curFileIdx >= file_list.size()) { curFileIdx = tmp; if (curFileIdx == -1) return; JOptionPane.showMessageDialog(this, "The last one!"); return; } File file = file_list.get(curFileIdx); initImage = ImageIO.read(file); initImage = initImage.getScaledInstance( (int) (initImage.getWidth(null) * scale), (int) (initImage.getHeight(null) * scale), Image.SCALE_SMOOTH); // SCALE_DEFAULT, SCALE_SMOOTH // path and fileName path = file.getParent(); fileName = file.getName(); int imgLen = file_list.size(); setTitle(imgLen + " images - " + fileName); int idx = fileName.lastIndexOf('.'); if (idx != -1) fileName = fileName.substring(0, idx); idx1 = 0; idx2 = 0; // set default value Arrays.fill(isOccluded, 2); // full occluded Arrays.fill(isDefault, 0); // default Arrays.fill(points, 0); for (int i = 0; i < annoName.length; i++) { Arrays.fill(xPoints[i], 0); Arrays.fill(yPoints[i], 0); } setSize(initImage.getWidth(null) + border * 3 + _startJframeX, initImage.getHeight(null) + border * 3 + _startJframeY ); // readAnnotation(path + "/Annotations/" + fileName + ".xml"); repaint(); ok = true; } catch (Exception e) { e.printStackTrace(); if (flag == 0) { if (curFileIdx == 0) { return; } curFileIdx--; } else { curFileIdx++; } } } } private void addFileToQueue(File folder) { for (File file : folder.listFiles()) { if (file.isDirectory()) addFileToQueue(file); else if (file.getName().endsWith(".jpg") || file.getName().endsWith(".png")) file_list.add(file); } } private boolean readAnnotation(String path) { File gt = new File(path); if (!gt.exists()) return false; int choice = JOptionPane.showConfirmDialog(this, "Annotation file is found, read it or not?", "tips", JOptionPane.YES_NO_OPTION); if (choice != JOptionPane.YES_OPTION) return false; try { } catch (Exception e) { e.printStackTrace(); idx1 = 0; idx2 = 0; for (int i = 0; i < 6; i++) { Arrays.fill(xPoints[i], 0); Arrays.fill(yPoints[i], 0); } JOptionPane.showMessageDialog(this, "Invalid annotation file"); } return true; } public static void main(String[] args) { new DatasetAnnotated_BB_Occ(); } }