I need to draw a simple histogram for a project I'm working on that needs to look this...
I know there is got to be some simple for loop to run on my H[] array which consists of how many pixels belong to each gray scale value... so in H[] we have lets say "10 pixels in gray scale value 1" so at 1 there would be a line of length 10 going vertically next to my image...
if anyone could offer their help, I would greatly appreciate it!
Thanks.
wrote this but its too big and upside down and angled for some reason.
if (H != null) {
int width = getWidth();
int height = getHeight();
int HhPos = (width - (width/2));
int HvPos = (height - (height));
for(int i = 0 ; i <255 ; i++){
g.drawRect(i+HhPos, i+HvPos, 1, H[i]);
}
As Gilbert said, you need to normalize you values, to determine the maximum range or ceiling.
From this you can then determine the percentage of a given value compared to the maximum and then plot it on the graph, based on the available height.
(Taken from the previous answer to this question)
// Determine the maximum vertical value...
int maxValue = 0;
for (Integer key : mapHistory.keySet()) {
int value = mapHistory.get(key);
maxValue = Math.max(maxValue, value);
}
int xPos = xOffset;
for (Integer key : mapHistory.keySet()) {
int value = mapHistory.get(key);
// Calculate the percentage that the given value uses compared to that of the
// maximum value
float percentage = (float)value / (float)maxValue;
// Calculate the line height based on the available vertical space...
int barHeight = Math.round(percentage * height);
g2d.setColor(new Color(key, key, key));
int yPos = height + yOffset - barHeight;
Rectangle2D bar = new Rectangle2D.Float(xPos, yPos, barWidth, barHeight);
g2d.fill(bar);
g2d.setColor(Color.DARK_GRAY);
g2d.draw(bar);
xPos += barWidth;
}
Now in the previous example, I used a Map to to store the values, but it should relativly easy to replace that with your data array...
for (Integer key : mapHistory.keySet()) would become for (int key : H)
Also, with Graphics.drawLine, it is drawing a line from one point to another, not one point to a width/height value (like say Graphics.drawRectangle)
You're plotting points that have an x and y value. You're drawing a histogram that has a width and height in pixels.
For example, let's say your histogram is 500 pixels in width, and 300 pixels in height.
You go through your data points once, looking for the minimum x, minimum y, maximum x, and maximum y.
Assuming we're plotting Y points (the X axis is the width), you subtract the minimum x from the maximum x. Divide 500 pixels (the width) by the difference, and you get the number of pixels per x value. This number can be greater than one, so you have more than one pixel per x value. This number can be less than one, so you have more data values than pixels.
width pixels per value = width of histogram in pixels / difference in X points
You do the same for the Y axis. Calculate the pixels per y value.
height pixels per value = height of histogram in pixels / difference in y points
Now, you go through your data points a second time. For each data point, you calculate the width and height in pixels from the x and y value of the data point. You use the number of pixels per value for both the width and the height to make the conversion.
width = x value * width pixels per value
height = y value * height pixels per value
You use the Java Graphics drawLine or drawRect method to draw the line or bar in your histogram. Just remember that the Y dimension in Java graphics goes down, rather than up like in your histograph. You'll have to take this into account when you're drawing.
Related
How do you find out the height and width of a PFont string in Processing or Java?
The best thing you can do when you have a question like this is to read through the Processing reference.
Specifically you're probably looking for the textWidth(), textAscent(), and textDescent() functions.
size(400, 400);
textSize(36);
String str = "Hello world";
float x = 100;
float y = 100;
float strWidth = textWidth(str);
float strAscent = textAscent();
float strDescent = textDescent();
float strHeight = strAscent + strDescent;
rect(x, y - strAscent, strWidth, strHeight);
fill(0);
text(str, x, y);
Using the inbuilt functions textWidth(), textAscent(), and textDescent() are an easy way to get a good approximate result for the height and width of a string, but they are not exact.
Why?
textAscent() returns text height above the line based on the letter 'd'
textDescent() returns text height below the line based on the letter 'p'.
textWidth() includes glyph whitespace (aka padding; ideally we want to ignore this for the first and last characters)
textAscent() + textDescent() therefore measures the maximum height of a string in a given font and font size, and not the height of a specific string. In other words, if your text doesn't include both 'd' and 'p' characters, then using these methods to determine text height will overestimate the result (as we see in Kevin's screenshot).
Getting the exact height
We can use this approach to get an exact result for height:
Get a vector representation of each character
Iterate over the vector's vertices, finding:
The vertex with highest Y position
The vertex with lowest Y position
Subtract the highest Y position from the lowest Y position to determine the exact string height
Code Example
Note you'll need to explicitly create a PFont for this.
String string = "Hello world";
PFont font = createFont("Arial", 96, true); // arial, size 96
textFont(font);
float minY = Float.MAX_VALUE;
float maxY = Float.NEGATIVE_INFINITY;
for (Character c : string.toCharArray()) {
PShape character = font.getShape(c); // create character vector
for (int i = 0; i < character.getVertexCount(); i++) {
minY = min(character.getVertex(i).y, minY);
maxY = max(character.getVertex(i).y, maxY);
}
}
final float textHeight = maxY - minY;
Result
(Note we're still using textWidth() for width here)
text(string, mouseX, mouseY);
rect(mouseX, mouseY, textWidth("Hello world"), -textHeight);
Getting the exact width
Code Example
String string = "Hello world";
PFont font = createFont("Arial", 96, true); // arial, size 96
textFont(font);
float textWidth = textWidth(string); // call Processing method
float whitespace = (font.width(string.charAt(string.length() - 1)) * font.getSize()
- font.getGlyph(string.charAt(string.length() - 1)).width) / 2;
textWidth -= whitespace; // subtract whitespace of last character
whitespace = (font.width(string.charAt(0)) * font.getSize() - font.getGlyph(string.charAt(0)).width) / 2;
textWidth -= whitespace; // subtract whitespace of first character
Result
(Putting the two together...)
text(string, mouseX, mouseY);
rect(mouseX + whitespace, mouseY, textWidth, -textHeight);
Y-Axis Alignment
A rectangle drawn around "Hello world" happens to be aligned because none of the glyphs descend below the baseline.
With a string like ##'pdXW\, both # and p descend below the baseline such that the rectangle, although it is the correct height, is out of alignment with the string on the y-axis, as below:
A programmatic way to determine the y-offset would be to find the Y-coordinate of the lowest (although remember Processing's y-axis extends downwards so we're actually looking for the highest value) vertex . Fortunately, this was calculated as part of finding the exact height.
We can simply use the maxY value that was calculated there to offset the text bounding box.
Result
text(string, mouseX, mouseY);
rect(mouseX + whitespace, mouseY + maxY, textWidth, -textHeight);
I want to crop an image using its x,y coordiates using BufferedImage.getSubimage(x,y,width,height) function in java. But i only have bounding box of an image to crop some part of it.
How can i get x,y coordinates from bounding box using java? Is there any calculation available?
I am giving bounding box values (xMin,yMin,xMax,yMax)(0.46476197,0.46967554,0.8502463,0.67080903 )
How can i get x,y coordinates from bounding box using java? Is there
any calculation available?
If your calculated bounding box coordinates correspond to the image fractions you will first have to calculate the pixel values for xMin, xMax, yMin and yMax.
Using those it is easy to calculate the necessary parameters for the functionBufferedImage.getSubimage(x,y,width,height).
x and y correspond to the upper left corner of the bounding box, therefore:
x = xMin and y = yMin
The width of the box can be calculated using the image width and substracting the left space length leading to the box as well as the right space length where the box ends, therefore you can calculate it using the formula:
width = imageWidth - xMin - (imageWidth - xMax)
Same goes for the height, just use the y-coordinates instead:
height = imageHeight - yMin - (imageHeight - yMax)
I am multiplying bounding box values with image width and height respectively to get its pixel values.
int y1 = yMin * ImageHeight;
int x1 = xMin * ImageWidth;
int y2 = yMax * ImageHeight;
int x2 = xMax * ImageWidth;
And applied the values to below given formula
BufferedImage.getSubimage((int)x1, (int)y1, (x2-x1), (y2-y1));
Thanks gilbert for giving solution to get pixel values.
I made a program where user enters number of rectangles to be drawn and coordinates at which the rectangles are drawn. My rectangles are currently drawn like this:
and I want to achieve this:
This is the code I use to draw the rectangles:
int povecaj_kvadrat=0;
for(int x=0;x<broj_kvadrata;x++) {
Rectangle2D.Float kvadrat=new Rectangle2D.Float(brojevi_koordinate[0],brojevi_koordinate[1],50+povecaj_kvadrat,50+povecaj_kvadrat);
ploca.draw((kvadrat));
povecaj_kvadrat=povecaj_kvadrat+15;
}
}
How do I set the coordinates of the rectangles so that they are drawn like in the second image?
You will have to take into account the additional size of each Rectangle, along with its position within the loop to compute the correct coordinates of each rectangle.
The additional size has been moved as a variable (diffSize), so that your loop can use its value.
The difference in coordinates between two iterations will be half this diff size, multiplied by the inverse of the position in the loop, because the lower the increment (x) and the Rectangle size, the bigger the coordinates .
int gap = 0;
int maxNumber = 3;
int diffSize = 20;
int[] coordinates = { 10, 10 };
for (int x = 0; x <= maxNumber; x++) {
Rectangle2D.Float rectangle = new Rectangle2D.Float(
coordinates[0] + ((diffSize / 2) * (maxNumber - x)),
coordinates[1] + ((diffSize / 2) * (maxNumber - x)),
50 + gap, 50 + gap);
g2d.draw((rectangle));
gap = gap + diffSize;
}
Note that I am unsure of the correct behaviour if diffSize is odd (because (diffSize / 2) will be rounded down to the nearest int value), so I would keep an even value for diffSize.
This is part of a project for my computer science class. One of the tasks is to take an image and reflect it. I've already initialized a picture called image. When I run this method, instead of reflecting the picture it mirrors it.
public void reflect()
{
//Creating a for loop to get all of the x values for the image object
for(int x = 0; x < image.getWidth(); x++)
{
//Creating a nested for loop to get all of the y values for each x value
for(int y = 0; y < image.getHeight(); y++)
{
//Getting a pixel object for the given x and y value
Pixel pixelObj = image.getPixel(x, y);
//I'm pretty sure this next line is where I'm screwing up.
//It's probably really simple, but I can't figure it out.
Pixel newPixel = image.getPixel(image.getWidth()-x-1, y);
//This sets the color values of the new pixel to the ones of the old pixel
newPixel.setRed(pixel0bj.getRed());
newPixel.setGreen(pixel0bj.getGreen());
newPixel.setBlue(pixel0bj.getBlue());
}
}
image.show();
}
You have to swap the corresponding pixel values. Currently, you are overwriting the right half of the image before saving their pixel values in a reference for putting them to the left half.
Below I've illustrated what I mean by "swapping" value instead of just assigning them uni-directionally:
//Getting a pixel object for the given x and y value
Pixel pixelObj = image.getPixel(x, y);
Pixel oppositePixel = image.getPixel(image.getWidth()-x-1, y);
//Store the RGB values of the opposite pixel temporarily
int redValue = oppositePixel.getRed();
int greenValue = oppositePixel.getGreen();
int blueValue = oppositePixel.getBlue();
//This swaps the color values of the new pixel to the ones of the old pixel
oppositePixel.setRed(pixel0bj.getRed());
oppositePixel.setGreen(pixel0bj.getGreen());
oppositePixel.setBlue(pixel0bj.getBlue());
pixelObj.setRed(redValue);
pixelObj.setGreen(greenValue);
pixelObj.setBlue(blueValue);
If you swap pixels both ways in each round, it's sufficient to loop from 0 to image.getWidth() / 2.
Have a look how it's done in ImageJ's ImageProcessor class as a reference.
Another solution is to use a matrix transformation and scale by -1 in the x direction. See the ImageJ scale op for a more elaborate example using the ImgLib2 library for image processing in Java.
I've created a graph using java and swing but it is only good for showing positive numbers and some negative numbers less than -14 the idea that I've used was :
create a box
add my X and Y axis label
get an array of numbers
get max number for indicating the max number in the array
create an scale using following code :
double scale = (double)(height - 2*borderSpace)/getMax();
and then plot my line graph , above solutions is perfect for positive values for negative values I did a trick
int height2 = getHeight() - getHeight()/2;
double scale = (double)(height2 - 2*borderSpace)/getMax();
which is only works till -14 not less than that.
for drawing lines I use this code
//borderspace = 20
double xInc = (double)(width - 2*borderSpace)/(data.length-1);
double scale = (double)(height - 2*borderSpace)/getMax();
g2.setPaint(Color.green.darker());
for(int i = 0 ; i < data.length-1; i++) {
double x1 = borderSpace + i*xInc;
double y1 = height - borderSpace - scale*data[i];
double x2 = borderSpace + (i+1)*xInc;
double y2 = height - borderSpace - scale*data[i+1];
g2.draw(new Line2D.Double(x1, y1, x2, y2));
}
I want to have the box but Y axis should be on the left side( I don't want to change the Y axis place) and I just want to change the place X axis in case of having negative numbers
for making it more clarify you can have a look at this picture :
You might want to take a look at JFreeChart to create your graphs rather than trying to brew your own solution from scratch.