Drawing bezier curve in Java - java

I need to create a simple Java program, that draws a bezier curve pixel by pixel through any amount of points. At the moment, everything seems to be ok except that the curve always ends at x=0 y=0 coordinates.
Screenshot 1
Screenshot 2
I need it to end at the last point. My brain is not quite working today, so I'm looking for some help.
Here is what I have:
private void drawScene(){
precision = Float.parseFloat(this.jTextField4.getText());
//Clears the screen and draws X and Y lines
g.setColor(Color.white);
g.fillRect(0, 0, pWidth, pHeight);
g.setColor(Color.gray);
g.drawLine(0, offsetY, pWidth, offsetY);
g.drawLine(offsetX, 0, offsetX, pHeight);
//Drawing the points
if(pointCount > 0){
for(int i = 0;i<pointCount;i++){
g.setColor(Color.red);
g.drawString(String.valueOf(i+1), points[i].x + offsetX, points[i].y - 6 + offsetY);
g.drawOval(points[i].x + offsetX, points[i].y - 6 + offsetY, 3, 3);
}
}
//Drawing the curve
if(pointCount > 1){
float t = 0;
while(t <= 1){
g.setColor(Color.gray);
this.besierCurvePixel(t);
t += precision;
}
}
}
//Factorial
private static int fact(int n) {
int fact = 1;
for (int i = 1; i <= n; i++) {
fact *= i;
}
return fact;
}
//Bernstein polynomial
private static double bernstein(float t, int n, int i){
return (fact(n) / (fact(i) * fact(n-i))) * Math.pow(1-t, n-i) * Math.pow(t, i);
}
private void besierCurvePixel(float t){
double bPoly[] = new double[pointCount];
for(int i = 0; i < pointCount; i++){
bPoly[i] = bernstein(t, pointCount, i+1);
}
double sumX = 0;
double sumY = 0;
for(int i = 0; i < pointCount; i++){
sumX += bPoly[i] * points[i].x;
sumY += bPoly[i] * points[i].y;
}
int x, y;
x = (int) Math.round(sumX);
y = (int) Math.round(sumY);
g.drawLine(x + offsetX, y + offsetY, x + offsetX, y + offsetY);
}
This is the method for adding the points (pointCount is 0 initially):
points[pointCount] = new Point();
points[pointCount].x = evt.getX() - this.offsetX;
points[pointCount].y = evt.getY() - this.offsetY;
pointCount++;
this.drawScene();

The problem was here
for(int i = 0; i < pointCount; i++){
bPoly[i] = bernstein(t, pointCount, i+1);
}
The second parameter in the bernstein method was incorrect. Basically If I have 3 points, it should be 2 not 3;
bPoly[i] = bernstein(t, pointCount-1, i+1);

Where does "pointcount" get set (and to what)?
Have you tried stepping through your code to see why it continues after reaching the last point?
Is it possible that you are stepping through a loop 1 extra time, which is why the last point would have a destination set to (0,0)?
Could you set the number of steps for the app to make to each point?
Hopefully I am bringing up points to help you find your answer
*Edit: If I had to guess- you are accidentally adding an additional point of (0,0) to points[]; Here is where I am seeing it go to (0,0) after the last point:
for(int i = 0; i < pointCount; i++){
sumX += bPoly[i] * **points[i]**.x;
sumY += bPoly[i] * **points[i]**.y;
}
Edit: Glad you were able to fix it, and hopefully i helped with finding that issue. Best of luck in the future!

Related

display array sorted

Suppose I have a two-dimensional grid of pixels (4 by 4 pixels) - and I have an image the size of my sketch that has been cut into 16 parts.
Now I load all 16 parts into an array. I want to map this array onto the 2D grid in turn, so that my overall image is put together again correctly. That is, top left image 0.png and bottom right image 16.png.
I just can't find the formula that allows me to do this. For example, I know that with x+y*width you can run trough all pixels – from top left to bottom right - so I tried that. Without *width it doesn't sit together properly - with x+y*width- ArrayIndexOutOfBoundsException (for sure).
So I thought I needed a 2D array - but with images[x][y] i get a NullPointerException. I attached you an image of what I am trying to create:
This is my code so far – without the 2D Array…
float pixelamount = 4;
float pixelsize;
PImage[] images = new PImage [16];
void setup() {
size(1080, 1080);
pixelsize = width/pixelamount;
for (int i = 0; i < images.length; i++) {
images[i] = loadImage(i + ".png");
}
imageMode(CENTER);
}
void draw() {
background(0);
pushMatrix();
translate(pixelsize/2, pixelsize/2);
for (int x = 0; x < pixelamount; x++) {
for (int y = 0; y < pixelamount; y++) {
pushMatrix();
translate(pixelsize*x, pixelsize*y);
image(images[x+y], 0, 0, pixelsize, pixelsize);
popMatrix();
}
}
popMatrix();
}
As I said – in the line image(images[x+y], 0, 0, pixelsize, pixelsize); I just do not get the math right. Do I need a 2D Array to solve this? Or something totally different?
This should be resolved without 2D array.
If the dimensions of the field are known 4x4, then possibly the loop should run from 0 to 4 something like this:
void draw() {
background(0);
pushMatrix();
translate(pixelsize/2, pixelsize/2);
for (int x = 0; x < 4; x++) {
for (int y = 0; y < 4; y++) {
pushMatrix();
translate(pixelsize * x, pixelsize * y);
image(images[4 * x + y], 0, 0, pixelsize, pixelsize);
popMatrix();
}
}
popMatrix();
}
Alex is correct.
Cyrill, you're on the right track but seem to get confused between 3 ways at looking at your data:
The images array is a 1D array (indices 0 to 15)
The for loop is nested therefore you need to convert 2D indices to 1D. You are right: x+y*width would give you the correct array index, but in this case width is not the full width of your sketch in pixels but the width of the grid (i.e. the number of columns in the 4x4 grid: 4)
You are getting a null pointer pointer because you're trying to access elements in a 1D array as if it's 2D.
Something like this should work:
float pixelamount = 4;
float pixelsize;
PImage[] images = new PImage [16];
void setup() {
size(1080, 1080);
pixelsize = width/pixelamount;
for (int i = 0; i < images.length; i++) {
images[i] = loadImage(i + ".png");
}
//imageMode(CENTER);
}
void draw() {
background(0);
pushMatrix();
translate(pixelsize/2, pixelsize/2);
for (int x = 0; x < pixelamount; x++) {
for (int y = 0; y < pixelamount; y++) {
pushMatrix();
translate(pixelsize*x, pixelsize*y);
image(images[x + y * pixelamount], 0, 0, pixelsize, pixelsize);
popMatrix();
}
}
popMatrix();
}
If you want to loop with a single for loop (instead of a nested for loop) which would match how you store your data you can use this formula to go from 1D index to 2D indices:
x = index % gridColumns
y = index / gridColumns
(Bare in mind these are integers (so in other languages (like Python/JS/etc.) you'd pay attention to the division operation))
Here's a basic example to illustrate this:
size(1080, 1080);
textAlign(CENTER, CENTER);
textFont(createFont("Courier New Bold", 12));
int pixelAmount = 4;
int pixelSize = width/pixelAmount;
int gridColumns = 4;
// iterate once
for(int i = 0; i < 16; i++){
// calculate 2D grid indices
int xIndex = i % gridColumns;
int yIndex = i / gridColumns;
// convert from index to pixel size
int x = xIndex * pixelSize;
int y = yIndex * pixelSize;
// render debug data
String debugText = "1D index:" + i +
"\n2D indices:[" + xIndex + "][" + yIndex + "]" +
"\nx, y pixels::" + x + "," + y;
fill(255);
rect(x, y, pixelSize, pixelSize);
fill(0);
text(debugText, x + pixelSize / 2, y + pixelSize / 2);
}
Here's the same example as the above using a 2D array and nested loops:
size(1080, 1080);
textAlign(CENTER, CENTER);
textFont(createFont("Courier New Bold", 12));
int pixelAmount = 4;
int pixelSize = width/pixelAmount;
int[][] grid = new int[pixelAmount][pixelAmount];
// mimick image loading (storing 1D index)
int index = 0;
for(int y = 0; y < pixelAmount; y++)
for(int x = 0; x < pixelAmount; x++)
grid[x][y] = index++;
// mimick reading 2D array data
for(int y = 0; y < pixelAmount; y++){
for(int x = 0; x < pixelAmount; x++){
int xPixels = x * pixelSize;
int yPixels = y * pixelSize;
// manually copute index
// index = x + y * pixelAmount;
// or retrieve stored index
index = grid[x][y];
String debugText = "1D index:" + index + ".png" +
"\n2D indices:[" + x + "][" + y + "]" +
"\nx, y pixels::" + xPixels + "," + yPixels;
fill(255);
rect(xPixels, yPixels, pixelSize, pixelSize);
fill(0);
text(debugText, xPixels + pixelSize / 2, yPixels + pixelSize / 2);
}
}
My answer is more for the sake of completeness: displaying both 1D/2D ways at looking at the data.
Based on the latest answer – this is my code – working perfectly!
float pixelamount = 4;
float pixelsize;
PImage[] images = new PImage [16];
void setup() {
size(1080, 1080);
pixelsize = width/pixelamount;
for (int i = 0; i < images.length; i++) {
images[i] = loadImage(i + ".png");
}
imageMode(CENTER);
}
void draw() {
background(0);
pushMatrix();
translate(pixelsize/2, pixelsize/2);
for (int x = 0; x < pixelamount; x++) {
for (int y = 0; y < pixelamount; y++) {
pushMatrix();
translate(pixelsize * x, pixelsize * y);
image(images[x + y * int(pixelamount)], 0, 0, pixelsize, pixelsize);
popMatrix();
}
}
popMatrix();
}

How to Get an Objects X position in processing

I am trying to make Space Invaders in Processing. I am currently working on getting the enemy to move correctly. I have got them to be drawn in the right spot but I haven't gotten them to be moved correctly. Here is my code:
PImage mainPlayer;
PImage enemyPlayer;
float Xspeed = 60;
float Yspeed = 60;
float X;
float Y;
Enemy EnemyPlayer = new Enemy("EnemyPlayerSpaceInvaders.png", 10, 10, 6);
void setup() {
size(1400, 800);
//enemyPlayer = loadImage("EnemyPlayerSpaceInvaders.png");
mainPlayer = loadImage("MainPlayerSpaceInvaders.png");
}
void draw() {
background(0);
Enemy[] enemyPlayer = new Enemy[60];
for (int i = 0; i < 5; i += 1) {
for (int j = 0; j < 11; j += 1) {
enemyPlayer[j *i] = new Enemy("EnemyPlayerSpaceInvaders.png", 50 + j * 100, 5 + 75 * i, 6);
}
}
for (int i = 0; i < 5; i += 1) {
for (int j = 0; j < 11; j += 1) {
if(enemyPlayer[j * i].alive){
enemyPlayer[j * i].Draw();
}
enemyPlayer[j *i].moveAndDraw(6);
}
}
}
class Enemy {
boolean alive = true;
float x;
float y;
float speed;
String playerTexFile;
PImage playerTex;
Enemy(String PlayerTexFile, float X, float Y, float Speed){
x = X;
y = Y;
speed = Speed;
playerTexFile = PlayerTexFile;
}
void Draw(){
playerTex = loadImage(playerTexFile);
image(playerTex, x, y);
}
void moveAndDraw(float Speed){
playerTex = loadImage(playerTexFile);
if(alive){
x += Speed;
if (x >= 1300) {
x = 100;
y += 50;
}
}
}
}
Here is my result:
The Draw function works but what you're seeing that is messing it up is the moveAndDraw() function.
And the enemy drawings aren't moving. I have made this before with c++ SFML but in that there is a very basic getPosition function. The reason I want to get position is that right now I'm having to use inaccurate numbers as the X and Y position and for the enemy to move correctly I need to know exactly what it's position is. I have checked multiple pages on processing.org but none of them helped. I haven't found any getPosition void and all the ones I've seen other people using a void to do this I just haven't been able to get it to work. If there is some code that could get me this to work or just some function I've looked over and even a website page I could look at I'd be open to it. Please tell me anything I can do to get this working.
The issue is that you recreate the enemies in every frame at it's initial position:
void draw() {
background(0);
Enemy[] enemyPlayer = new Enemy[60];
for (int i = 0; i < 5; i += 1) {
for (int j = 0; j < 11; j += 1) {
enemyPlayer[j *i] = new Enemy("EnemyPlayerSpaceInvaders.png", 50 + j * 100, 5 + 75 * i, 6);
}
}
// [...]
}
You've to:
Create a global array of enemies Enemy[] enemyPlayer (and delete PImage enemyPlayer).
Create and initialize the enemies in setup.
Use and move the existing enemies in draw:
Further note, that your loops doesn't do what you expect it to do. Create the enemies in 2 nested loops. If i runs from o to 6 and j from 0 to 10, the the index of an enemy is i*10 + j.
The enemies can be moved in a single loop from 0 to enemyPlayer.length.
//PImage enemyPlayer; <--- DELETE
// global array of enemies
Enemy[] enemyPlayer = new Enemy[60];
// [...]
void setup() {
size(1400, 800);
mainPlayer = loadImage("MainPlayerSpaceInvaders.png");
// create enemies
for (int i = 0; i < 6; i += 1) {
for (int j = 0; j < 10; j += 1) {
enemyPlayer[i*10 + j] = new Enemy("rocket64.png", 50 + j * 100, 5 + 75 * i, 6);
}
}
}
void draw() {
background(0);
// move enemies
for(int i = 0; i < enemyPlayer.length; ++i ) {
if(enemyPlayer[i].alive){
enemyPlayer[i].Draw();
}
enemyPlayer[i].moveAndDraw(6);
}
}

Java hsb degrees or 255

I was wondering if when you call color.HSBtoRGB if the hue value would be entered as a range of 0-255, 0-1, 0-360? I am inquiring because I am trying to convert an edge angle to a color but it is only giving me blue or purple? can anyone explain what I am doing?
public void sobelGrey(){
this.greyScale();
double edgex;
double edgey;
Picture pi = new Picture(this.getWidth(), this.getHeight());
Picture tou = new Picture(this.getWidth(), this.getHeight());
Pixel[][] Y = pi.getPixels2D();
Pixel[][] X = tou.getPixels2D();
Pixel[][] h = this.getPixels2D();
for (int y = 1; y< X.length-1; y++){
for(int x= 1; x<X[1].length-1; x++){
edgex =
h[y-1][x-1].getRed() * -1 +
h[y][x-1].getRed() * -2+
h[y+1][x-1].getRed() * -1+
h[y-1][x+1].getRed() * 1 +
h[y][x+1].getRed() * 2+
h[y+1][x+1].getRed() * 1;
Y[y][x].setRed((int)Math.abs(edgex/2));
Y[y][x].setGreen((int)Math.abs(edgex/2));
Y[y][x].setBlue((int)Math.abs(edgex/2));
}
}
for (int y = 1; y< X.length-1; y++){
for(int x= 1; x<X[1].length-1; x++){
edgex =
h[y-1][x-1].getRed() * -1 +
h[y-1][x].getRed() * -2+
h[y-1][x+1].getRed() * -1+
h[y+1][x-1].getRed() * 1 +
h[y+1][x].getRed() * 2+
h[y+1][x+1].getRed() * 1;
X[y][x].setRed((int)Math.abs(edgex/2));
X[y][x].setGreen((int)Math.abs(edgex/2));
X[y][x].setBlue((int)Math.abs(edgex/2));
}
}
for (int y = 1; y< X.length-1; y++){
for(int x= 1; x<X[1].length-1; x++){
int x1 = (int) Math.sqrt(Math.pow(X[y][x].getRed(), 2) + Math.pow(X[y][x].getGreen(), 2) + Math.pow(X[y][x].getBlue(), 2));
int y1 = (int) Math.sqrt(Math.pow(Y[y][x].getRed(), 2) + Math.pow(Y[y][x].getGreen(), 2) + Math.pow(Y[y][x].getBlue(), 2));
int hr = (int) (200/(2*Math.PI)*(Math.tanh(y1/ (x1+.000000000000001))));
int rgb = Color.HSBtoRGB(hr/255, hr, (int) Math.sqrt(Math.pow(x1, 2) + Math.pow(y1, 2)));
Color fixed = new Color(rgb&0xFF*7/10, (rgb>>8)&0xFF*80/255/10, (rgb>>16)&0xFF*4/10);
if( !(Math.sqrt(Math.pow(x1, 2) + Math.pow(y1, 2))< 40))
h[y][x].setColor(fixed);
else
h[y][x].setColor(Color.black);
}
}
pi.explore();
tou.explore();
explore();
}
i am using a computer science AP image processing from Eimacs, and using the swan
You declared hr (and the other variables) to be an int. Then in Color.HSBtoRGB(hr/255, ... you divide an int by an int. For all values of hr below 255, the result will be 0.
Probably it is sufficient to divide by 255.0 to force a floating point division.

I try to rotat without lib but it make black points in picture

I am trying to rotate image without standard method , making color array and manipulate it, but when I invoke the, rotation I get black points (look the picture)
Here is my code, colScaled is the picture I am trying to convert to an array:
public void arrays() {
colScaled = zoom2();
int j = 0;
int i = 0;
angel = Integer.parseInt(this.mn.jTextField1.getText());
float degree = (float) Math.toRadians(angel);
float cos = (float) Math.cos(degree);
float sin = (float) Math.sin(degree);
int W = Math.round(colScaled[0].length * Math.abs(sin) + colScaled.length * Math.abs(cos));
int H = Math.round(colScaled[0].length * Math.abs(cos) + colScaled.length * Math.abs(sin));
int x;
int y;
int xn = (int) W / 2;
int yn = (int) H / 2;
int hw = (int) colScaled.length / 2;
int hh = (int) colScaled[0].length / 2;
BufferedImage image = new BufferedImage(W + 1, H + 1, im.getType());
for (i = 0; i < colScaled.length; i++) {
for (j = 0; j < colScaled[0].length; j++) {
x = Math.round((i - hw) * cos - (j - hh) * sin + xn);
y = Math.round((i - hw) * sin + (j - hh) * cos + yn);
image.setRGB(x, y, colScaled[i][j]);
}
}
ImageIcon ico = new ImageIcon(image);
this.mn.jLabel1.setIcon(ico);
}
Notice this block in your code :-
for (i = 0; i < colScaled.length; i++) {
for (j = 0; j < colScaled[0].length; j++) {
x = Math.round((i - hw) * cos - (j - hh) * sin + xn);
y = Math.round((i - hw) * sin + (j - hh) * cos + yn);
image.setRGB(x, y, colScaled[i][j]);
}
}
The x and y is pixel coordinate in source image (colScaled).
The objective of this code is to fill all pixels in destination image (image).
In your loop, there is no guarantee that all pixels in the destination image will be filled, even it is in the rectangle zone.
The above image depict the problem.
See? It is possible that the red pixel in the destination image will not be written.
The correct solution is to iterating pixel in destination image, then find a corresponding pixel in source image later.
Edit: After posting, I just saw the Spektre's comment.
I agree, it seems to be a duplicated question. The word "pixel array" made me thing it is not.

Get average color on bufferedimage and bufferedimage portion as fast as possible

I am trying to find image in an image. I do this for desktop automation. At this moment, I'm trying to be fast, not precise. As such, I have decided to match similar image solely based on the same average color.
If I pick several icons on my desktop, for example:
And I will search for the last one (I'm still wondering what this file is):
You can clearly see what is most likely to be the match:
In different situations, this may not work. However when image size is given, it should be pretty reliable and lightning fast.
I can get a screenshot as BufferedImage object:
MSWindow window = MSWindow.windowFromName("Firefox", false);
BufferedImage img = window.screenshot();
//Or, if I can estimate smaller region for searching:
BufferedImage img2 = window.screenshotCrop(20,20,50,50);
Of course, the image to search image will be loaded from template saved in a file:
BufferedImage img = ImageIO.read(...whatever goes in there, I'm still confused...);
I explained what all I know so that we can focus on the only problem:
Q: How can I get average color on buffered image? How can I get such average color on sub-rectangle of that image?
Speed wins here. In this exceptional case, I consider it more valuable than code readability.
I think that no matter what you do, you are going to have an O(wh) operation, where w is your width and h is your height.
Therefore, I'm going to post this (naive) solution to fulfil the first part of your question as I do not believe there is a faster solution.
/*
* Where bi is your image, (x0,y0) is your upper left coordinate, and (w,h)
* are your width and height respectively
*/
public static Color averageColor(BufferedImage bi, int x0, int y0, int w,
int h) {
int x1 = x0 + w;
int y1 = y0 + h;
long sumr = 0, sumg = 0, sumb = 0;
for (int x = x0; x < x1; x++) {
for (int y = y0; y < y1; y++) {
Color pixel = new Color(bi.getRGB(x, y));
sumr += pixel.getRed();
sumg += pixel.getGreen();
sumb += pixel.getBlue();
}
}
int num = w * h;
return new Color(sumr / num, sumg / num, sumb / num);
}
There is a constant time method for finding the mean colour of a rectangular section of an image but it requires a linear preprocess. This should be fine in your case. This method can also be used to find the mean value of a rectangular prism in a 3d array or any higher dimensional analog of the problem. I will be using a gray scale example but this can be easily extended to 3 or more channels simply by repeating the process.
Lets say we have a 2 dimensional array of numbers we will call "img".
The first step is to generate a new array of the same dimensions where each element contains the sum of all values in the original image that lie within the rectangle that bounds that element and the top left element of the image.
You can use the following method to construct such an image in linear time:
int width = 1920;
int height = 1080;
//source data
int[] img = GrayScaleScreenCapture();
int[] helperImg = int[width * height]
for(int y = 0; y < height; ++y)
{
for(int x = 0; x < width; ++x)
{
int total = img[y * width + x];
if(x > 0)
{
//Add value from the pixel to the left in helperImg
total += helperImg[y * width + (x - 1)];
}
if(y > 0)
{
//Add value from the pixel above in helperImg
total += helperImg[(y - 1) * width + x];
}
if(x > 0 && y > 0)
{
//Subtract value from the pixel above and to the left in helperImg
total -= helperImg[(y - 1) * width + (x - 1)];
}
helperImg[y * width + x] = total;
}
}
Now we can use helperImg to find the total of all values within a given rectangle of img in constant time:
//Some Rectangle with corners (x0, y0), (x1, y0) , (x0, y1), (x1, y1)
int x0 = 50;
int x1 = 150;
int y0 = 25;
int y1 = 200;
int totalOfRect = helperImg[y1 * width + x1];
if(x0 > 0)
{
totalOfRect -= helperImg[y1 * width + (x0 - 1)];
}
if(y0 > 0)
{
totalOfRect -= helperImg[(y0 - 1) * width + x1];
}
if(x0 > 0 && y0 > 0)
{
totalOfRect += helperImg[(y0 - 1) * width + (x0 - 1)];
}
Finally, we simply divide totalOfRect by the area of the rectangle to get the mean value:
int rWidth = x1 - x0 + 1;
int rheight = y1 - y0 + 1;
int meanOfRect = totalOfRect / (rWidth * rHeight);
Here's a version based on k_g's answer for a full BufferedImage with adjustable sample precision (step).
public static Color getAverageColor(BufferedImage bi) {
int step = 5;
int sampled = 0;
long sumr = 0, sumg = 0, sumb = 0;
for (int x = 0; x < bi.getWidth(); x++) {
for (int y = 0; y < bi.getHeight(); y++) {
if (x % step == 0 && y % step == 0) {
Color pixel = new Color(bi.getRGB(x, y));
sumr += pixel.getRed();
sumg += pixel.getGreen();
sumb += pixel.getBlue();
sampled++;
}
}
}
int dim = bi.getWidth()*bi.getHeight();
// Log.info("step=" + step + " sampled " + sampled + " out of " + dim + " pixels (" + String.format("%.1f", (float)(100*sampled/dim)) + " %)");
return new Color(Math.round(sumr / sampled), Math.round(sumg / sampled), Math.round(sumb / sampled));
}

Categories

Resources