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
//