We are about to switch to a new forum software. Until then we have removed the registration on this forum.
I've created a basic magic wand program that I can't figure out what's gone wrong. I'm trying to keep the code basic without getting into crazy complicated coding. Can anyone tell me what isn't working please? The color picker function doesn't seem to be reading the image pixel color correctly, which is preventing me from seeing if the color distance or magic wand functions are working either. Thanks for any assistance.
// Variables
PImage img;
// Boolean variables for the buttons
boolean buttonSelect = false;
boolean buttonFill = false;
// picked color
color pickedColor;
boolean c = false;
int loc;
// Position of button 1
// Position of button 2
void setup() {
size(1000,900);
img = loadImage ("sunflower.jpg");
rect(925, 200, 50, 25);
rect(925, 400, 50, 25);
// draw buttons
// initialize variables if necessary
}
void draw() {
// load image pixels: loadPixels();
loadPixels();
image(img, 0, 0);
fill(random(255),random(255),random(255));
// if button 1 is clicked and currently there is no color picked
// if button_2 is clicked and a color is picked
}
// default function offered by Processing for Button click detection
boolean overRect(int x, int y, int width, int height) {
if (mouseX >= x && mouseX <= x+width &&
mouseY >= y && mouseY <= y+height) {
return true;
} else {
return false;
}
}
void mouseClicked() {
// if first button clicked
if (overRect(925, 200, 50, 25)==true)
{
buttonSelect = true;
rect(925,200,50,25);
}
if (buttonSelect == true) {
// { select color}
pickedColor = pickColor();
}
if (overRect(925, 400, 50, 25) && c==true){
// magic wand (select pixels with similar color)
rect(925, 400, 50, 25);
magicWand(pickedColor);
buttonFill = true;
}
}
// if (overRect(first button position and size))
//
// if second button clicked
// function to Pick A Color
color pickColor()
{
// allocate location in pixel array based on mouse position
// for example: int loc = mouseX + mouseY*img.width;
loc = mouseX + mouseY * img.width;
// get the color from that pixel
float r = red(pixels[loc]);
float g = green(pixels[loc]);
float b = blue(pixels[loc]);
// return the color
pickedColor = color(r,g,b);
c = true;
return pickedColor;
}
// function for MagicWand
void magicWand(color c_selected)
{
// load pixels
loadPixels();
// get the r, g, b value for the selected color
// use for loops to access each pixel in image
color current;
for (int i = 0; i < width*height; i++) {
current = pixels[i];
float dist = colorDist(current,c_selected);
if (dist < 50){
pixels[i] = color(255,0,0);
}
updatePixels();
}
//updatePixels();
// get each pixel's color
// compare the pixel's color with the selected color
// if the distance between the two color is less than 50
// highlight the pixel with a new color: for example, pixels[loc] = color(255,0,0);
// update image Pixels
}
// function to find color distance
float colorDist(color c1, color c2){
float r1 = red(c1);
float g1 = green(c1);
float b1 = blue(c1);
float r2 = red(c2);
float g2 = blue(c2);
float b2 = blue(c2);
// get the r, g, b values from each color
// compute the distance using pythagorean theorom:
float dist = sqrt( (r1-r2)*(r1-r2) + (g1-g2)*(g1-g2) + (b1-b2)*(b1-b2));
return dist;
}
Answers
Please edit your post and format your code to help people help you: https://forum.processing.org/two/discussion/15473/readme-how-to-format-code-and-text
Thanks
There are a bunch of good ideas in this sketch and a few really strange things happening.
For example, in draw() you are currently randomizing fill every single draw loop. Don't do that there in a sketch where you are testing a color picker, it confuses the issue (as often the color you are seeing has already been changed).
Strategy: I would recommend breaking this into two sketches that work separately, then combining. The first sketch simply tests the magic wand, which is always on and always pours red. The second sketch simply tests a color picker, which is always on and always displays the latest color in a floating status box which is non-interactive.
Once both work perfectly, think about combining them. At that point it should be obvious that you need at least two mouse modes -- picking and pouring. Consider triggering these modes with keyboard keys at first -- having special controls regions and adds complexity.
Also -- could you explain how your magic wand is supposed to work? Right now it appears to be attempting to change every pixel in the image that is similar -- no matter where that pixel is. Is it supposed to operate on contiguous, spatially connected pixels?
The top button is supposed to activate the color picker and then when you click on a pixel in the image it selects that color. Upon pressing the bottom button it "highlights" every pixel in the image red that's less than 50 difference in color value. The redraw of the rectangle and the random fill was just to show that the color picker has been activated.
Do you see anything wrong with the actual code in the color picker? I've tested it by having the second button draw a rectangle with that fill and it doesn't seem to be storing the color value correctly. Also, the flood fill doesn't do anything at all.
@CodeSloth -- like I said, break it down into multiple simpler sketches!
There are several potential problems that I haven't tried to tease out in the more complex sketch. Just one example:
That's going to play merry hell with your distance checking. Especially in a picture of a sunflower.
Also, you might not want to call loadPixels every draw. Just call it when you need it (look at the loadPixels() reference).
I didn't go through all the code but I did minor changes to show hot to get the color picker working. Notice those changes I indicated in the code below. Few things to keep in mind:
loadPixels should be called only after you draw the image with the image() function.
There is a difference calling loadPixels before or after drawing your buttons. If you call them after drawing your buttons, then your buttons will also be included as part of your loadPixell array.
If you draw your buttons in setup, then they are drawn only once. If the image takes over all the sketch area, it will cover your buttons. That is why I moved the buttons into your drawing and after drawing the image, so are are drawn on top of it.
I hope this helps,
Kf
@CodeSloth -- Try this to start. Work our your color picker in a separate simple sketch. Then combine.
Thank you so much, the help is greatly appreciated.
Good luck!
If you ever decide to implement a "flooding" (neighbors) flood fill, check out:
It has been a long time, but we have recently gotten several questions about flood filling, so...
I am contributing a flood fill demo sketch that I did last year based on this discussion.
Magic fill (above) changes any pixel in the image that matches the color profile. It is easy to implement -- check every pixel. Flood fill only changes pixels that are contiguous (like a paint bucket pour). It is harder to implement -- you to implement a method of "flooding" through the pixels.
The easiest naive implementation of a flood fill algorithm is recursive -- it calls itself of its four neighbors -- but this leads to stack overflow problems. One way to making the flooding manageable is to change recursion into adding points to a queue while processing the queue. See the Java implementation here:
...and an interesting previous discussion of queues in Processing here:
...and it like I forgot that @quark had already created a flood fill example. It also uses ArrayDeque, only with his only Point class instead of PVector. That example uses a scanline flood fill rather than a four way flood fill.
https://forum.processing.org/two/discussion/14390/fill-algorithm