I suggest finding the boundary points that exist on the border between white and dark pixels. After that we can digitize these points. To do this, we must define a DELTA that indicates which point we should skip and which we should add to the list of results.
DELTA = 3, Number of points = 223

DELTA = 5, Number of points = 136

DELTA = 10, Number of points = 70

Below I put the source code, which prints the image and looks for points. Hope you can read it and find a way to solve your problem.
import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.image.BufferedImage; import java.awt.image.DataBufferByte; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.imageio.ImageIO; import javax.swing.JFrame; import javax.swing.JPanel; public class Program { public static void main(String[] args) throws IOException { BufferedImage image = ImageIO.read(new File("/home/michal/Desktop/FkXG1.png")); PathFinder pathFinder = new PathFinder(10); List<Point> borderPoints = pathFinder.findBorderPoints(image); System.out.println(Arrays.toString(borderPoints.toArray())); System.out.println(borderPoints.size()); JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new ImageBorderPanel(image, borderPoints)); frame.pack(); frame.setMinimumSize(new Dimension(image.getWidth(), image.getHeight())); frame.setVisible(true); } } class PathFinder { private int maxDelta = 3; public PathFinder(int delta) { this.maxDelta = delta; } public List<Point> findBorderPoints(BufferedImage image) { int width = image.getWidth(); int[][] imageInBytes = convertTo2DWithoutUsingGetRGB(image); int[] borderPoints = findBorderPoints(width, imageInBytes); List<Integer> indexes = dwindlePoints(width, borderPoints); List<Point> points = new ArrayList<Point>(indexes.size()); for (Integer index : indexes) { points.add(new Point(index, borderPoints[index])); } return points; } private List<Integer> dwindlePoints(int width, int[] borderPoints) { List<Integer> indexes = new ArrayList<Integer>(width); indexes.add(borderPoints[0]); int delta = 0; for (int index = 1; index < width; index++) { delta += Math.abs(borderPoints[index - 1] - borderPoints[index]); if (delta >= maxDelta) { indexes.add(index); delta = 0; } } return indexes; } private int[] findBorderPoints(int width, int[][] imageInBytes) { int[] borderPoints = new int[width]; int black = Color.BLACK.getRGB(); for (int y = 0; y < imageInBytes.length; y++) { int maxX = imageInBytes[y].length; for (int x = 0; x < maxX; x++) { int color = imageInBytes[y][x]; if (color == black && borderPoints[x] == 0) { borderPoints[x] = y; } } } return borderPoints; } private int[][] convertTo2DWithoutUsingGetRGB(BufferedImage image) { final byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); final int width = image.getWidth(); final int height = image.getHeight(); final boolean hasAlphaChannel = image.getAlphaRaster() != null; int[][] result = new int[height][width]; if (hasAlphaChannel) { final int pixelLength = 4; for (int pixel = 0, row = 0, col = 0; pixel < pixels.length; pixel += pixelLength) { int argb = 0; argb += (((int) pixels[pixel] & 0xff) << 24); // alpha argb += ((int) pixels[pixel + 1] & 0xff); // blue argb += (((int) pixels[pixel + 2] & 0xff) << 8); // green argb += (((int) pixels[pixel + 3] & 0xff) << 16); // red result[row][col] = argb; col++; if (col == width) { col = 0; row++; } } } else { final int pixelLength = 3; for (int pixel = 0, row = 0, col = 0; pixel < pixels.length; pixel += pixelLength) { int argb = 0; argb += -16777216; // 255 alpha argb += ((int) pixels[pixel] & 0xff); // blue argb += (((int) pixels[pixel + 1] & 0xff) << 8); // green argb += (((int) pixels[pixel + 2] & 0xff) << 16); // red result[row][col] = argb; col++; if (col == width) { col = 0; row++; } } } return result; } } class ImageBorderPanel extends JPanel { private static final long serialVersionUID = 1L; private BufferedImage image; private List<Point> borderPoints; public ImageBorderPanel(BufferedImage image, List<Point> borderPoints) { this.image = image; this.borderPoints = borderPoints; } @Override public void paintComponent(Graphics g) { super.paintComponent(g); g.drawImage(image, 0, 0, null); Graphics2D graphics2d = (Graphics2D) g; g.setColor(Color.YELLOW); for (Point point : borderPoints) { graphics2d.fillRect(point.x, point.y, 3, 3); } } }
In my source code, I used an example from this question:
MichaΕ Ziober
source share