Webcam Pixel Manipulation/Sorting via Processing - java

I am attempting to write a Processing sketch that will take each row's center pixel's color and apply that color to the entire row. However, I am having trouble with even getting the pixels to change. It seems like the sketch doesn't even go through the for-loops where I am trying to change the pixels because it doesn't print out any of the statements except the end draw at the end of draw(). I just end up with an unmanipulated feed. Does anyone know why this isn't working?
Also, currently using Processing's standard Video library with Capture at the moment, but if there is a better library that I could utilize please let me know! Thanks!
UPDATE: Testing out my algorithm with an array of numbers, it seems like using an inner for loop isn't working like how I thought it should. The i of the outer-loop is only incremented once after the first time the inner for loop completes itself, and then it just exits the outer loop instead of starting the inner loop again. What's going on here?
import processing.video.*;
Capture feed; // webcam
int pixelCount = width * height; // total # of pixels
int center = width / 2; // value for center pixel
int widthPlus = width + 1; // value to go row-to-row
color c; // center pixel color
void setup(){
size(displayWidth, displayHeight);
feed = new Capture(this);
feed.start();
}
void draw(){
if (feed.available() == true){
feed.read();
}
image(feed, 0, 0);
feed.loadPixels(); // load pixels from webcam
/** Use to look at each row one at a time*/
for (int i = 0; i < pixelCount; i+=widthPlus){
println("Outer for-loop");
c = feed.pixels[i + center]; //get center pixel
/** Make each pixel in row the color of 'c' */
for (int j = i; j < width; j++){
println("Inner for-loop");
feed.pixels[j] = c; // set pixel to 'c'
println(i + " - " + j);
}
}
feed.updatePixels(); // update pixels from webcam
println("end draw");
}

Related

Creating a clickable grid in Processing 3

I'm trying to make a grid of squares that change their fill (from black to white and vice-versa) when clicked. I'm able to turn the entire grid on or off currently, but I'm unable to figure out how to specify which particular square should be toggled when the mouse clicks within its borders. I've created buttons using mouseX and mouseY coordinates before, but they were for specific objects that I could adjust manually. I can't figure out how to do this using for loops and arrays.
I've been told to create a boolean array and pass the value of that array to the grid array, but again, I don't know how to specify which part of the array it needs to go to. For example, how do I change the fill value of square [6][3] upon mousePressed?
Here is my code so far:
int size = 100;
int cols = 8;
int rows = 5;
boolean light = false;
int a;
int b;
void setup() {
size (800, 600);
background (0);
}
void draw() {
}
void mousePressed() {
light = !light;
int[][] box = new int[cols][rows];
for (int i = 0; i < cols; i++) {
for (int j = 0; j < rows; j++) {
box[i][j] = i;
int a = i*100;
int b = j*100;
if (light == true) {
fill(255);
} else {
fill(0);
}
rect(a, b, 100, 100);
println(i, j);
}
}
}
First of all, you are currently recreating the entire board whenever the mouse is pressed. You must retain that info between mouse clicks, so make box a global array up there with the others. Further, it's sufficient to make it a boolean array if all you care about is the on/off state of each square:
boolean[][] isSquareLight = new boolean[cols][rows];
Instead of
if (light == true) {
you should then just check
if (isSquareLight[i][j] == true) {
(note that the == true is redundant).
Now, you've already written code that finds the coordinates for each box: You're passing it to rect!
rect(a, b, 100, 100);
All that is left to do is check whether the mouse is inside this rect, i.e. whether mouseX is between a and a+100 (and similar for mouseY) - if that's the case, then the user clicked in the box given by the current (i, j), so you can just negate isSquareLight[i][j] (before checking it like above) and it will work.
There are ways to calculate this without looping through the entire grid every time, but maybe the above helps you find the path yourself instead of just getting the code made for you.
PS: The int a; int b; at the top does nothing and can be removed. You are using the local variables a and b in your function, which is correct.

processing: trouble using global array in if condition in for loop

I am trying to write a small program that has a given number of balls (in the example code below it's 3) travel back and forth across the screen at different speeds and phases (start offset).
This much has been achieved in the code. Although I want to be able to select the balls (one at a time) using a mouse click.
I have used the word "HIT!!!" to signify in the console that a ball has been clicked.
My problem is that when I run the code below, I only get a "HIT!" in the console when I click the top ball. That is when the first element y[0] matches with the click_Y variable. When I am sure (but obviously mistaken somehow) that there should be matches when I click in the vicinity of y[1] & y[2].
I'd really be grateful for any help with these. As it's gotten to the point where I am starting to stare blankly at the screen. Thanks.
int noCircles; // the number of items in the array (# of circles)
float[] y; // y-position of each circle (fixed)
float[] speed; // speed of each circle
float[] phase; // phase of each circle
float red = 120;
float green = 120;
float blue = 120;
float click_X;
float click_Y;
void setup() {
size(500, 500);
noCircles = 3;
// allocate space for each array
y = new float[noCircles];
speed = new float[noCircles];
phase = new float[noCircles];
// calculate the vertical gap between each circle based on the total number
// of circles
float gap = height / (noCircles + 1);
//setup an initial value for each item in the array
for (int i=0; i<noCircles; i++) {
y[i] = gap * (i + 1);
// y is constant for each so can be calculated once
speed[i] = random(10);
phase[i] = random(TWO_PI);
}
}
void draw() {
background(155);
for (int i=0; i<noCircles; i++) {
// calculate the x-position of each ball based on the speed, phase and
//current frame
float x = width/2 + sin(radians(frameCount*speed[i] ) + phase[i])* 200;
if (dist(x, y[i], click_X, click_Y) <= 20){
println("HIT!!!!!!!!!!!!!!!!!!");
}
ellipse(x, y[i], 20, 20);
click_X = 0;
click_Y = 0;
}
}
void mousePressed() {
println("You clicked******************************************");
click_X = mouseX;
click_Y = mouseY;
println("click_X =" + click_X);
println("click_Y =" + click_Y);
}
Problems like these are best solved by debugging your program. Start by tracing through the code by hand, then add print statements (more than you've already added), and if that doesn't work then don't be afraid to use the debugger.
You're using the click_X and click_Y variables to check the position of the mouse against the position of each ball. Trace through the for loop in your draw() function. What happens at the end of the first iteration?
You reset the values of click_X and click_Y. That's why you aren't detecting any hits on the other circles.
You could probably refactor your code to only reset those variables if something has been hit, but really, I would stop using them altogether.
I'm guessing that you're using those variables because you only want to check when the mouse is pressed? Just use the mousePressed variable for that. Then you can use the mouseX and mouseY variables directly.
Then your if statement would look like this:
if (mousePressed && dist(x, y[i], mouseX, mouseY) <= 20) {
println("HIT: " + i);
}
Also, using separate arrays like this is called parallel arrays, and is general a bad habit to get into. You should probably use classes instead.

How to process information in an image?

I want to write a java program so that when I capture the image of any one face of a Rubik's Cube, it tells which color is present on which tile. I dont want to use any prewritten library/api. I want to write the code myself. I want to ask how I should go about....I mean the steps.
Thanks in advance!
You can do something like this it analyzing one pixel at the time
img = ImageIO.read(new File("/mydir/pic.png"));
for (int y = 0; y < img.getHeight(); y++) {
for (int x = 0; x < img.getWidth(); x++) {
int rgb = img.getRGB(x, y);
if (rgb == Color.RED.getRGB()) {
//Do stuff
} else if (rgb == Color.GREEN.getRGB()){
//Do more stuff
}
}
}
If the size of face of the cube in the image is variable then its not an easy task. Otherwise you can just use #urag's code but instead of checking for all pixels just check only 6 pixels in a row with an offset of tile width starting from first center of 1st tile.

Loop which creates "windows" in buildings? - Java Swing

I am a beginner with Java and especially Java Swing. What I am trying to do is create randomly generated "buildings" (which I have done) and on top of them add windows in rows/columns that are equally sized and spaced apart. However I want to do this in a loop (for loop?). My end goal is to also only have a few of the windows light up each time (this also being randomly generated) the code is run. Here is what I have so far, the window I have created is basically the size I want them to be. I know my attribute maxX is not used but I have created it to remind me of the max X value and in case I need it later.
import java.awt.*;
import javax.swing.*;
public class JPanelExample extends JPanel
{
private int maxX = 784;
private int maxY = 712;
#Override
public void paint(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.WHITE);
g2d.fillRect(5, 5, 25, 25);
int width = (int)(Math.random()*100+100);
int height = (int)(Math.random()*350+100);
for (int i =10; i<634; i+=(width+10))
{
for (int j = 462 ; j>=462; j--)
{
g2d.setColor(Color.GRAY);
g2d.drawRect(i, maxY-height, width, height);
g2d.fillRect(i, maxY-height, width, height);
g2d.setColor(Color.YELLOW);
g2d.drawRect(i+5, (maxY-height)+5, width/6, width/6);
g2d.fillRect(i+5, (maxY-height)+5, width/6, width/6);
height = (int)(Math.random()*462+100);
while (width == i+(width+10))
{
width = (int)(Math.random()*100+100);
}
}
}
}
public static void main(String[] args)
{
JFrame frame = new JFrame("Frame");
frame.add(new JPanelExample());
frame.setBackground(Color.BLACK);
frame.setSize(800, 750);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
I hope you're having fun with Java and if you're still looking for an answer (though there are many) here's my suggestion:
In order to get a row of windows on the buildings you've drawn here, you need to know:
how many windows you'll be drawing (from your code, it looks like you always want 6 windows)
where to begin drawing (from your code, this seems to be 5px after the start of each building
how much spacing between windows you want (this isn't evident in your code, but it can be whatever you want -- for this example we will use 5px again)
what colour the window should be (for this example we will use white for no-light and yellow for light turned on).
Set Up
We can store all these numbers in variables like this (using values from your code):
// for the lights:
Color off = Color.WHITE;
Color on = Color.YELLOW;
// for window calculations
int space = 5;
int startx = i+space;
int starty = maxY-height+space;
int interval = (width-space)/6;
Note that we subtract one space from the building's width before dividing by 6 to discount the initial space before the first window. I'm sure you've seen this already, but drawing diagrams can also be very helpful when starting with Java/Swing
The Loop
We can now loop through the number of windows you'd like to place in that row of windows. In this case, it looks like you'll want 6 windows every time. For each window (inside the for-loop) we first want to decide on the color (in the example we use a 10% chance of the lights being on, as noted below). Once we've set the colour, we simply use the values we've noted above to fill the next window rectangle, which is explained below. Make sure your for-loops have different variable names, since we have them nested here
for(int k = 0; k < 6; k++) {
if((int)(Math.random()*100) < 10) //10% of the time, turn the light color on
g2d.setColor(on);
else
g2d.setColor(off);
//g2d.drawRect(i+5, (maxY-height)+5, width/6, width/6);
g2d.fillRect(startx+(k*interval), starty, (interval)-space, (interval)-space);
}
As a note: the drawRect followed by fillRect here are redundant. I'm not sure if you have a specific purpose for drawing the rect first (in which case, ignore this), but view your app with the drawRect commented out to see what it does.
If you have any trouble with the Math.random function here, check out these resources:
http://docs.oracle.com/javase/7/docs/api/java/lang/Math.html
Math.random() explained
Exploring the fillRect in our example:
fillRect takes a few variables noted below (details at: http://docs.oracle.com/javase/7/docs/api/java/awt/Graphics.html)
fillRect(int x, int y, int width, int height)
In our example we've set the following:
x = startx + (k * interval) , k being the incremental variable for the for loop (runs from 1 .. 6), increasing the x value for the rectangle by a window's interval after each window drawn.
y = starty , this is consistent for each row.
width, height = interval - space , this sets the dimensions of the window and ensures a proper space before the next window.
This should give you a working 1 row of windows.
Columns
Getting columns of windows is very similar to getting the row. There are many ways to do all of these things, but I'll briefly go through another nested-for-loop.
In order to get columns of windows we need to know:
How many rows you want to have (how many windows per column)
Because we've already set up window dimensions we can determine the number of windows that can fit in a column using the following:
int num_rows = (height - space) / interval;
//and to set a maximum number of rows to a column (ex: 6)
int num_rows = Math.min(((height-space) / interval), 6); //a max number can replace 6 here
Here we'll use another for-loop to continuously add rows, num_rows times. Note: we've changed fillRect such that y = starty + (l*interval) , incrementing the start position y to the next location of rows each time one row is drawn.
for(int l = 0; l < num_rows; l++){
for(int k = 0; k < 6; k++) {
if((int)(Math.random()*100) < 10) //10% of the time, turn the light color on
g2d.setColor(on);
else
g2d.setColor(off);
g2d.fillRect(startx+(k*interval), starty + (l*interval), (interval)-space, (interval)-space);
}
}
And that's that. Hope that's helpful and not too confusing.
After a long time, I figured out a solution. I have changed the for-loop to this:
for (int i =10; i<634; i+=(a+10))//buildings
{
g2d.setColor(Color.GRAY);
g2d.drawRect(i, maxY-height, width, height);
g2d.fillRect(i, maxY-height, width, height);
rows = Math.round((height)/25);
columns = Math.round(width/25);
for (int j = 1; j<=columns; j++)//windows
{
for (int k = 1; k<=rows; k++)
{
g2d.setColor(Color.BLACK);
g2d.drawRect(i+5*j+20*(j-1), (maxY-height)+5*k+20*(k-1), 20, 20);
if (Math.random()<0.7)
{
g2d.setColor(Color.YELLOW);
g2d.fillRect(i+5*j+20*(j-1), (maxY-height)+5*k+20*(k-1), 20, 20);
}
else
{
g2d.setColor(transYellow);
g2d.fillRect(i+5*j+20*(j-1), (maxY-height)+5*k+20*(k-1), 20, 20);
g2d.setColor(transYellow);
g2d.fillRect(i+5*j+20*(j-1), (maxY-height)+5*k+20*(k-1), 20, 20);
}
}
}
addBuilding();
a = width;
height = (int)(Math.random()*462+100);
width = (int)(Math.random()*100+100);
}

How do I flip an image vertically in Java?

I have to flip the image horizontally but when I put in my code it only flips half of so that it reflects halfway through the image.
What am I doing wrong?
public static void flipVertical(Pixel[][] imageArr)
{
int height = imageArr.length;
int width = imageArr[0].length;
for(int row = 0; row < height; row++)
{
for(int col = 0; col < width; col++)
{
Pixel p = imageArr[row][col];
imageArr[height - row - 1][col] = p;
}
}
Your code doesn't work currently because it is copying the flipped bottom half of the image into the top half without keeping the original data in the top half of the image. As such, when it processes the bottom half of the image, it is effectively copying the same data back to the bottom half again.
When you swap two values, a and b, you would need to use a temporary variable:
Pixel tmp = a;
a = b;
b = a;
If you do it like you have:
a = b; // After, a == b and b == b.
b = a;
then the second assignment is effectively a no-op, since a's value is already b.
As such, you need to update your inner loop to:
Pixel p = imageArr[row][col];
imageArr[row][col] = imageArr[height - row - 1][col];
imageArr[height - row - 1][col] = p;
Also, the outer for loop should be:
for(int row = 0; row < height/2; row++)
Otherwise you flip the image, and then flip it back again.
You can use the AffineTransform class and its method translate to flip the image horizontally. See the code here:
// Flip the image horizontally
tx = AffineTransform.getScaleInstance(-1, 1);
tx.translate(-image.getWidth(null), 0);
op = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
image = op.filter(image, null);
The problem is that you're changing pixels that you will still need later. When row goes through the top half of the rows, you modify the pixels in the bottom half by copying them from the top half. When row later goes through the bottom half of the rows, you try to modify the pixels in the top half by copying them from the bottom half--but the first half of the algorithm already changed the bottom half. So you're not copying the original pixels when you set the top half.
There are at least two ways to solve this:
(1) Don't use the same array. Create a new array to hold the result, and copy after you're done.
(2) Let row go only up to half the height, and for each loop iteration, swap the pixels in imageArr[row][col] and imageArr[height-row-1][col], something like:
Pixel p1 = imageArr[row][col];
Pixel p2 = imageArr[height-row-1][col];
imageArr[row][col] = p2;
imageArr[height-row-1][col] = p1;
(Specifically, you want to do this only as long as row < height-row-1. When you reach a point where row >= height-row-1, then you have to exit the loop. Otherwise you're going to start undoing the work you've already done.)
What do you mean by flipping the image horizontally? It seems taht you want to swap it vertically... Swapping horizontally (resp. vertically) means mirroring it through vertical (resp. horizontal) axe.
Anyway. Two things : swap pixels correctly and limit your loop to half the dimension (once you swap two pixels, you don't need to swap them again) :
public static void flipHorizontal(Pixel[][] imageArr)
{
int height = imageArr.length;
int width = imageArr[0].length;
for(int row = 0; row < height; row++)
{
for(int col = 0; col < width/2; col++)
{ // swap two symmetric pixels
Pixel tmp = imageArr[row][col];
imageArr[row][col] = imageArr[row][width-col-1];
imageArr[row][width-col-1] = tmp;
}
}
}

Categories

Resources