
I did it.
It’s another idea than mentioned.
This Sketch just searches white points and
- checks a circle around it. The entire circle must be black (surrounding the white hole).
 
- It checks a 2nd circle around it. This must be mostly white (the white area around the black area).
 
- When both circles are correct, we have found a hole.
 
The circles are critical in this project. For example you can change the radius. There are also two thresholds you can tinker with (for the counting of points of the 2 circles which is probably mostly due to rounding float to int…).
The correct points are stored (the holes).
You can delete points/rects that are wrong (they are in positions where in fact no hole is). These wrong rects are there because of the radius / threshold issues discussed above.
The green color is placed in the remaining holes.
The image is shown.
you can save with s.
Chrisir
// This Sketch can analyze an image of circuit where the holes for the pins are marked by black circles with a white hole.
// We fill these with green color.
// https://discourse.processing.org/t/how-to-fill-circles-in-image/42190/4
PImage img;
int iw;// its width
ArrayList<PVector> listOfHolePositions = new ArrayList();
int state=0;
// -----------------------------------------------------------------------------------------------------------
// Core functions
void setup() {
  size(900, 900);
  noFill();
  img=loadImage("c1.jpeg");
  iw = img.width;
}//func
void draw () {
  switch(state) {
  case 0:
    analyzeImage(); // search the holes
    break;
  case 1:
    showAndEditImage(); // edit the holes
    break;
  case 2:
    fillImage(); // fill the holes
    break;
  case 3:
    // image is ready
    showAndSaveImage();
    break;
  default:
    println("Error "+state);
    exit();
    break;
  }//switch
}//func
// -----------------------------------------------------------------------------------------------------------
// Inputs
void keyPressed() {
  //
  switch(state) {
  case 3:
    if (key=='s') {
      img.save("result.jpg");
      println("Saved.");
    }//if
  }//switch
}//func
// -----------------------------------------------------------------------------------------------------------
// Called from draw()
void analyzeImage() {
  image(img, 0, 0);
  box("Mouse "
    + mouseX + " , "
    + mouseY + ": color: "
    + get(mouseX, mouseY)
    + ":"
    + color(255)
    + "\nAny key to start (can take a minute!).");
  if (mousePressed) {
    analyzeOnePoint(mouseX, mouseY);
  }
  if (keyPressed) {
    print(">please wait...");
    img.loadPixels();
    searchImage();
    img.updatePixels();
    println("<");
    state=1;
  }
}//func
void showAndEditImage() {
  // when we have the points in the list, we can delete wrong points
  background(0);
  image(img, 0, 0);
  box("You can delete wrong rects by holding mouse and dragging over the top left corner. \nAny key to continue. ");
  // display
  for (PVector pv : listOfHolePositions) {
    fill(255, 0, 0);
    noStroke();
    rect(pv.x, pv.y, 8, 8);
  }
  // delete by mouse
  for (int i=listOfHolePositions.size()-1; i>=0; i--) {
    PVector pv=listOfHolePositions.get(i);
    if (mousePressed) {
      if (dist(mouseX, mouseY, pv.x, pv.y) < 4 )
        listOfHolePositions.remove(i);
    }
  }
  // go on
  if (keyPressed) {
    for (PVector pv : listOfHolePositions) {
      println(pv.x +","+pv.y);
    }
    state=2;
  }
} // func
void fillImage() {
  // when we have the points in the list,
  // we can flood fill them
  println("");
  print(">please wait...");
  img.loadPixels();
  for (PVector pv : listOfHolePositions) {
    fillMy (int(pv.x), int(pv.y),
      color( 0, 255, 0)); //Green
  }//for
  img.updatePixels();
  println("<");
  // go on
  state=3;
} // func
void showAndSaveImage() {
  background(0);
  image(img, 0, 0);
  box("DONE.\nHit 's' to save (overwriting)");
} // func
// ----------------------------------------------------------------------------------
// Tools I.
void fillMy(int x_, int y_,
  color col_) {
  // flood fill
  int dist = 5;
  for (int i1=-dist; i1<dist; i1++) {
    for (int i2=-dist; i2<dist; i2++) {
      // if white, fill it
      if (brightness(img.get(x_+i1, y_+i2))>22)
        img.set(x_+i1, y_+i2, col_);
    }
  }
} // func
// ----------------------------------------------------------------------------------
// Tools II.
void searchImage() {
  for (int startX=0; startX<img.width; startX++) {
    for (int startY=0; startY<img.height; startY++) {
      analyzeOnePoint(startX, startY);
    }//for
  }//for
}//func
void analyzeOnePoint(int startX, int startY) {
  // search a hole
  // wrong position?
  if (! (startX<iw&&startY<img.height)) {
    return;
  }
  // wrong color?
  color backColor = img.pixels[startX + startY * iw];
  if (backColor!=color(255)) {
    return;//skip
  }
  // it's white from now on
  // 1. count black points within inner circle.
  int countBlack=0;
  for (int angle=0; angle<360; angle++) {
    float xC=cos(radians(angle))*6+startX;
    float yC=sin(radians(angle))*6+startY;
    // stroke(255, 0, 0);
    // point(xC, yC);
    if (xC>=0&&yC>=0) {
      if (xC<iw&&yC<img.height) {
        if (img.pixels[int(xC) + int(yC) * iw] == color (0) ) {
          countBlack++;
        }
      }
    }
  }
  // 2. count WHITE points within outer circle.
  int countWhite=0;
  for (int angle=0; angle<360; angle++) {
    float xC=cos(radians(angle))*13+startX;
    float yC=sin(radians(angle))*13+startY;
    //stroke(255, 0, 0);
    //point(xC, yC);
    if (xC>=0&&yC>=0) {
      if (xC<iw&&yC<img.height) {
        if (img.pixels[int(xC) + int(yC) * iw] == color (255)) {
          countWhite++;
        }
      }
    }
  }
  fill(0);
  text(countWhite+":"+countBlack,
    width-100+66, 200);
  //stroke(0, 255, 0);
  //point(startX, startY);
  noStroke();
  // When the number of counts is correct, we have a hole
  // if (countBlack>210 && countWhite>170) {
  if (countBlack>180 && countWhite>160) {
    //match
    listOfHolePositions.add(new PVector(startX, startY)) ;
  }//if
}
// ----------------------------------------------------------
// Minor Tools
void box(String text_) {
  // box with text
  // box
  fill( #FAF028 );//Yellow
  noStroke();
  rect(width-180, 3,
    170, 300);
  // frame
  float dist1=4;
  noFill();
  stroke(0);
  rect(width-180+dist1, 3+dist1,
    170-2*dist1, 300-2*dist1);
  // state
  fill(0);
  text ("state "+state, width-160, 22 );
  // text
  text(text_,
    width-170, 100,
    150, 900);
}//func
//