I am working on an idea wherein I have to identify lines in a JPG or PNG file. The PNG file contains one graph of a single value - one x,y combination. For example, the graph looks like Y = mx+c.
I would like to identify the line in the graph - if I can indentify the position of the pixel in the frame, I believe I can get back the values (x,y) which were used to plot the graph. The assumptions here is - I know the scale i.e 1 pixel = what unit of Y ?
Can somebody please help me to write a code which will identify the pixels of a specific color in one PNG file?
EDIT
Lets take an example to make it clear. Lets say I have a set of data values X and Y like this -
X = 1, Y = 10
X = 2, Y = 20
X = 3, Y = 30
X = 4, Y = 40
X = 5, Y = 50
X = 6, Y = 60
In this case, if I use jfreechart type of charting tool and make a chart, it tools like a straight line.
So the input is the dataset and output is the .PNG file (using jchart or jfreechart) containing this line graph for Y values.
Question is - if we reverse the flow, can we develop one program which will take the PNG file (that contains the graph) and give me back the dataset.
The context of the problem is -- I want to store the PNG files in my application and not the raw dataset. But given a PNG file, I should be able to get back my dataset.
I'm a bit confused as to whether your problem is simply determining the colour of pixels in an image, or if the problem is the mathematics of what you're trying to do.
For the former, do something such as the following:
BufferedImage bimg = ImageIO.read(new File("whatever.png"));
// get the colour of the pixel at position (x, y)
int col = bimg.getRGB(x, y);
// decode red, green and blue components of colour if necessary
int r = (col >> 16) & 0xff;
int g = (col >> 8) & 0xff;
int b = col & 0xff;
If from the graph you just want to get back the dataset (i.e. not derive an equation from that data), then you essentially loop through each X position and find the Y position where there's a pixel of the colour that the graph plotting program uses. If the graph has axes, antialiasing etc, then the task will be more complex.
The task of deriving an equation from the data is potentially much more complex, but you can start by checking for certain suspected formulae such as y = mx + c as you mention. For example, you can loop through checking the difference between each Y position for the last; if that difference is always the same, then you've got a straight line graph (and at that point, deriving the formula should be trivial).
For testing for other equations, it helps to know a bit of calculus. Then, a starting point is to see if the differences in the differences match the derivative for the equation in question. (Just as an example, if the equation is y = ax^2 + c, then for every increase in X, the increase in Y will itself increase by 2a.)
Do I read that correctly: you have an image of a single line on an otherwise blank canvas? If so, you can just look down the leftmost pixel column and find the pixel that is different, then take a column a bit to the right and find the pixel there. Now you have two points, and generating a linear function from that is trivial. As unit, why not use pixels?
Generally, on a computer monitor you don't have a central (0,0) point, as that point is defined to be the top left corner of the screen. So if we are looking at a function f(x)=ax+b then b parameter is defined to be the y value of the function at x=0, meaning the left border of the screen. So it's important to define exactly what you are offsetting from.
To find the slope, just take some central point on the screen you know you have a point of the function there, go x pixels to the left or the right, find the y height delta, and y/x is the function slope, or parameter a in the function aforementioned.
i am not sure where you reached with your project, but i needed to detect lines in an image as well. Here is what helped me.
http://www.music.mcgill.ca/~cmckay/software/musictech/ScoreReader/HorizontalLineDetection.html
Related
g.setColor(c);
double changeFactor = (2<<count);
g.fillRect(x+1, y+1+(int)(boxHeight*(double)(1/changeFactor)), boxWidth-2, boxHeight-2-(int)(boxHeight*(double)(1/changeFactor)));
count++;
if(count == iterations)
{
count = 0;
}
Above is the code for a graphical halfing mechanism that I've been trying to make. In short, the idea for it is a simple graphics exercise that starts with a filled bar and subtracts from its current height by half the height every 250ms. In this way, it is an exponential decline in height. This is the current output:
Link for those of you who are having trouble viewing the image
This is the exact opposite of the output that I want. The white region in the bar is a flipped image of what I want the red region to do. Can you guys help me figure out why the code is not behaving correctly?
Sorry for the newbie question, by the way.
EDIT:
here's the answer:
g.fillRect(x+1, y+1+(int)(boxHeight*(double)((changeFactor-1)/changeFactor)), boxWidth-2, boxHeight-2-(int)(boxHeight*(double)((changeFactor-1)/changeFactor)));
Long story short, it's because I miscalculated the numerator for what I would want the height/y-coordinate to be.
According to the fillRect definition, the second parameter is the location of the top of the box. (In computer graphics, numbers often get bigger as you go downward along the Y axis, which is the opposite from how mathematicians draw graphs.) Assuming you want the top of your bar to keep heading downward (as opposed to the bottom of the bar going upward), that means that the second parameter needs to keep getting larger. However, in your code, the parameter keeps getting smaller, since 1/count keeps getting smaller.
If h is the total height and y is the top of the box, then the successive values you want for this parameter are:
y
y + h/2
y + h/2 + h/4
y + h/2 + h/4 + h/8 ...
or, expressed another way:
y + h - h
y + h - h/2
y + h - h/4
y + h - h/8
Based on that, I think you can see how to make some small modifications to the code and get it to work.
Also, make sure you clear the box in between iterations. fillRect won't touch anything outside the rectangle that you're drawing. So if you want to make the filled part smaller, you have to do something to clear out the part that was previously colored that you don't want colored any more.
My question can be simplified to the following: If a 3d triangle is being projected and rendered to a 2d viewing plane, how can the z value of each pixel being rendered be calculated in order to be stored to a buffer?
I currently have a working Java program that is capable of rendering 3d triangles to the 2d view as a solid color, and the camera can be moved, rotated, etc. with no problem, working exactly how one would expect it to, but if I try to render two triangles over each other, the one closer to the camera being expected to obscure the farther one, this isn't always the case. A Z buffer seems like the best idea as to how to remedy this issue, storing the z value of each pixel I render to the screen, and then if there's another pixel trying to be rendered to the same coordinate, I compare it to the z value of the current pixel when deciding which one to render. The issue I'm now facing is as follows:
How do I determine the z value of each pixel I render? I've thought about it, and there seem to be a few possibilities. One option involves finding the equation of the plane(ax + by + cz + d = 0) on which the face lies, then some sort of interpolation of each pixel in the triangle being rendered(e.g. halfway x-wise on the 2d rendered triangle -> halfway x-wise through the 3d triangle, same for the y, then solve for z using the plane's equation), though I'm not certain this would work. The other option I thought of is iterating through each point, with a given quantum, of the 3d triangle, then render each point individually, using the z of that point(which I'd also probably have to find through the plane's equation).
Again, I'm currently mainly considering using interpolation, so the pseudo-code would look like(if I have the plane's equation as "ax + by + cz + d = 0"):
xrange = (pixel.x - 2dtriangle.minX)/(2dtriangle.maxX - 2dtriangle.minX)
yrange = (pixel.y - 2dtriangle.minY)/(2dtriangle.maxY - 2dtriangle.minY)
x3d = (3dtriangle.maxX - 3dtriangle.minX) * xrange + 3dtriangle.minX
y3d = (3dtriangle.maxY - 3dtriangle.minY) * yrange + 3dtriangel.minY
z = (-d - a*x3d - b*y3d)/c
Where pixel.x is the x value of the pixel being rendered, 2dtraingle.minX and 2dtriangle.maxX are the minimum and maximum x values of the triangle being rendered(i.e. of its bounding box) after having been projected onto the 2d view, and it's min/max Y variables are the same, but for its Y. 3dtriangle.minX and 3dtriangle.maxX are the minimum and maximum x values of the 3d triangle before having been projected onto the 2d view, a, b, c, and d are the coefficients of the equation of the plane on which the 3d triangle lies, and z is the corresponding z value of the pixel being rendered.
Will that method work? If there's any ambiguity please let me know in the comments before closing the question! Thank you.
The best solution would be calculating the depth for each vertex of the triangle. Then we are able to get the depth of each pixel the same way we do for the colors when rendering a triangle with Gouraud shading. Doing that simultaneously with rendering allows to check the depth easily.
If we have a situation like this:
And we start to draw lines from the top to the bottom. We calculate the slopes from the point one to the others, and add the correct amount of depth every time we move to the next line... And so on.
You did't provide your rendering method, so can't say anything specific to it, but you should take a look at some tutorials related to Gouraud shading. Do some simple modifications to them and you should be able to use it with depth values.
Well, hopefully this helps!
I am trying to create a hollow pyramid of sorts using a loop. The way I would like to approach this is to start at a certain Y, and decrease it by 1, while expanding the X and the Z out by one while covering the perimeter.
*
* *
* *
* *
* *
Granted this would be 3D, using XYZ.
So my main question is, if I have 3 points, X=50 Y=50 Z=50, how would I go down each level of Y while getting the points around the center?
So far
for (int y = 1; y<15; y++) {
l.setY(l.getY() - 1);
l.setX(l.getX() + 1);
l.setZ(l.getZ() + 1);
l.getBlock().setType(Material.GLASS);
}
will only generate a staircase of sorts going 15 blocks down from the starting position
Please imagine the graph of the 3 axis, if you are not practice with it just take a look at this graph.
We will use z as height, by rotating the axis in order to have a clear picture of what is happening. You may as well use z as the depth parameter but it will be harder for you to understand what is going on.
You obtain a wrong plot because you are not moving towards the space in the right way..
What you are looking for is starting by a point, say S=(x,y,z) = (5,5,5) and you want to go down each level by printing your edges for the piramid.
the starting point is plotted as shown in the following figure
By moving down decrementing z you want to draw 4 points (you may want to draw some more, I just draw the edges in this case).
so in the next cycle you have z = z-1;
thus you have to move in the 4 directions allowed by the graph.
The point in the middle keeps the center of the pyramid, while the others are respectively
(5,4,4) (5,6,4) --> moving along y axis
(4,5,4) (6,5,4) --> moving along x axis
while you cycle you keep moving this, by using as metrics the difference between the center, the level(height) and the axis while drawing the pyramid..
HOW? see the last following picture, I added some color to help you keeping track of what is happening. Further I added axis and main points coordinates.
Red points keep the center of the pyramid, by starting at S = (5,5,5) (which is the top) you go down to S1 =(5,5,4) and S2 = (5,5,3).. so imagine this are 2 cicles of your while loop.
Green points keep track of the first cycle, when z = 4,
the center of the pyramid is S1 this time. You want to expand in the space by moving on the y and x axis.
By the center you move -1 and -+1 on y.. so obtaining (5,4,4) and (5,6,4). So far you obtain 2 edges. Let's move on the x axis keeping the center as is, the same this time you move by 1 unit toward such plane so that you have (6,5,4) and (4,5,4)..
The same happens with the second cycle. The distance you move is obtained by
starting height - actual level height
in the case of z = 3 you have to from the center by 5 - 3 = 2 unit (by previous statement)
so on and so forth for the rest of the cycle up to the point you end up.
You may want to stop at 0 unit of shift from center (when starting height == actual level height) by obtaining a nice and well drawn pyramid, other wise you can keep cycling but you have to find another way to stop, the previous subtraction in fact works also with negative height, you can notice that if you reach z = -1 the previous will tell you to shift of 6 units, in this case you have to find another way to stop and break your cycle.
This said you have to adjust your cycle to draw the 4 points, instead of those that you actually draw =)
You go the staircase at only one side down. On the other side, x and z grow in the other direction.
I am writing a code where I have a world filled with various obstacles (of rectangular shapes). My robot which is a circle, originates randomly at any place inside the world. I assume that it has a range sensor on its head and want to get the distance between the nearest obstacle/boundary wall which is in its straight line of view.
I am using a random orientation between 0 and 360 degrees to orient the robot and use sin and cos of orientation to move the robot in the same orientation. But how can I get the distance between any obstacle or the boundary wall along this orientation? It should be able to tell me the distance of the first object it encounters in its vision which would be an angle from 0 to 360.
Please provide me a hint of logic how to encounter this issue?
Thanks
Assuming you know the angle, the robot's position and the position of all the obstacles, you could have a function like this:
if the angle if less than 90 or greater than 270 you increment the x coordinate by 1, otherwise you decrement by 1
you make a for loop from the current x coordinate until the edge of the world (I don't know how you have the world implemented), scanning for any obstacles at position (x, x*tan(angle)), incrementing or decrementing in accordance with the step above
the first obstacle you run across, return sqrt(x^2 + (x*tan(angle))^2) - that's just the pythagorean theorem
Here's what i think you could do.
In real game development, they uses a lot of optimization tricks, often giving approximates for better performances.
Also note that there's a lot of libraries out there for game development, that probably could get you what you want a lot simplified.
But anyway, here's what i'ld do.
identify object you'd pass through if you go straight forward.
identify the nearest one, in the list of objects you just made.
1:
A)
make a formula for your position/angle in the form y = mx + b
[y = tan(angle)x + (positionY - (tan(angle)*x))]
B)
for each object, divide the object in multiple lines segments (2 points).
check if the segment crosses the line made by the formula in point A
(if a point is smaller and the other is greater than the same X value in the formula, it's crossing)
do the same thing for your world boundaries
2: This part is more tricky (to do in programmation).
Next, you have to find the position where your robot orientation formula intersect
with all the lines you previously identified.
For each line, you must again turn the line into a y=mx+b
Let say we have:
y=3x+5 and
y=5x+1
3x+5 = 5x+1
3x-5x = 1-5
-2x = -4
x = 2
Then you replace x with 2 in either formula, you'll get the intersection point:
y = 3(2)+5 = 11
y = 5(2)+1 = 11
So these two lines intersect on point (2, 11)
Next you have to see if that point is in the domain of you're robot path formula.
Since your robot is looking at a single direction, and the formula we made in point 1.A is infinite in both directions, you must ensure the line intersection you found is not in the back of your robot (unless he moves backward...)
I guess you can make it simple, look at cos(angle) signs, then look at the position of the intersection point, if it's to the left of your robot, and cos(angle) is negative it's fine.
Finally,
Once you found ALL the intersect point, you can find the nearest one by using the Pythagorean theorem sqrt((x1-x2)^2 + (y1-y2)^2)
Also, note that it won't work for 90 and 270 angles, since tan(90) doesn't exists.
In that case, just look if both points of the segments are at both side of your robot, and the intersect point is in the right direction, it means you pass through it.
Again, there's a lot of place for optimization.
I'm wondering if there is a "smart" way of splitting an image based on certain features.
The images are 300x57, black and white (actually grayscale, but most colors are either black or white), it is comprised of two main features (let's call them blobs) separated by black space, each blob slightly varies in width and height, the position of the blobs also varies, the blobs NEVER overlap!
Here is what an image "looks" like:
-------------------------
----WWW---------WWWWW----
---WWWWWWW----WWWWWW-----
-----WWWW-------WWW------
-------------------------
The resulting split would be something like this:
------------ -------------
----WWW----- ----WWWWW----
---WWWWWWW-- --WWWWWW-----
-----WWWW--- ----WWW------
------------ -------------
Steps I plan to take in order to split the image:
Scan the image from one side to the other.
Determine the edges of the blobs.
Take the distance between the two inside edges.
Split the image at the middle of the inside distance.
Save the two images as separate files.
It would be nice if I normalize the image widths, so all of my images have a uniform width when they're saved.
I have no experience in image manipulation, so I don't know what's an efficient way to do this. I'm currently using a BufferedImage, getting the width/height, iterating over each pixel, etc. There is no wrong solution for my problem, but I'm looking for a more efficient one (less code + faster). I've also been looking into java.awt.Graphics...
I would appreciate if I get some ideas for more efficient ways to do this task. I want to stick with Java's built-in libraries, so is BufferedImage or Graphics2D the most efficient thing to use in this case?
EDIT:
Here is the code after reading the suggestions:
public void splitAndSaveImage( BufferedImage image ) throws IOException
{
// Process image ------------------------------------------
int height = image.getHeight();
int width = image.getWidth();
boolean edgeDetected = false;
double averageColor = 0;
int threshold = -10;
int rightEdge = 0;
int leftEdge = 0;
int middle = 0;
// Scan the image and determine the edges of the blobs.
for(int w = 0; w < width; ++w)
{
for(int h = 0; h < height; ++h)
{
averageColor += image.getRGB(w, h);
}
averageColor = Math.round(averageColor/(double)height);
if( averageColor /*!=-1*/< threshold && !edgeDetected )
{
// Detected the beginning of the right blob
edgeDetected = true;
rightEdge = w;
}else if( averageColor >= threshold && edgeDetected )
{
// Detected the end of the left blob
edgeDetected = false;
leftEdge = leftEdge==0? w:leftEdge;
}
averageColor = 0;
}
// Split the image at the middle of the inside distance.
middle = (leftEdge + rightEdge)/2;
// Crop the image
BufferedImage leftImage = image.getSubimage(0, 0, middle, height);
BufferedImage rightImage = image.getSubimage(middle, 0, (width-middle), height);
// Save the image
// Save to file -------------------------------------------
ImageIO.write(leftImage, "jpeg", new File("leftImage.jpeg"));
ImageIO.write(rightImage, "jpeg", new File("rightImage.jpeg"));
}
A simple way to do this is to sum the pixel values in each column (going down) to create a single array (the same width as your input image) of average values. Starting in the middle of the array, search for the minimum value. This will be the column where you can split the image.
This column probably won't be the center of the gap between your blobs. You can do another outward search from this column, going left first to find all similar columns, and then going right.
-------------------------
----WWW---------WWWWW----
---WWWWWWW----WWWWWW-----
-----WWWW-------WWW------
-------------------------
col avg:
---wwWWwww-----wWWWWww---
Depending on how blank the space is (pixel value wise) between the two blobs, you can set your threshold value pretty low. If there is some noise, it will have to be a little higher.
Finding the right threshold value can be a chore, unless you can determine it algorithmically.
I'm not aware of an edge detection algorithm that doesn't require iterating through the pixels, so your present approach may be optimal. Depending on other factors, you may be able to leverage ImageJ, which has an extensive collection of analytical plugins.
Addendum: Given a preference for avoiding external dependencies, BufferedImage is a good choice. Once you identify the edges, the getSubimage() method is convenient. You may be able to use one of the Raster getPixels() methods effectively in the convolution. ImageIO can write the results.
Does the gap between blobs matter? If you don't need to balance the white space, less work would be needed to just find a vertical white line between blobs. Check if the center vertical line has only white pixels. If the middle line has a black pixel, scan left and right for the first line that has only white pixels. To check for situations where both blobs are to one side of center, scan a horizontal line for black-white-black intervals. If the selected vertical line is within a white interval surrounded by black intervals, you'll know there's at least one blob on each side of the image split.
Failing these checks would require scanning additional lines, but for all well formed images, where the blobs are centered in the right and left halves of the image, this method will take only two line scans. This method may take longer for other images, or even break, for edge case images. This would break for this example:
-------------------------
----WWW----WWWWWWWWWW----
---WWWWWWW----WWWWWW-----
-----WWWWWWWW---WWW------
-------------------------
But the question seems to indicate this situation is impossible. If the reason behind this image splitting requires processing every image, you'll need a fall back method. You wouldn't need a fall back method if the edge cases can be rejected. Once the scanning finds that the image falls outside of acceptable ranges, you can stop checking the image. For example, if a vertical all white line can't be found in the center third of the image, you may be able to reject the image. Or you can just use this method as an optimization, running this check on just two lines to find and split the well formed images, then passing the poorly formed images to a more thorough algorithm.
I don't think there is any reason to do anything other than scanning each line and stop when you have gotten a white->black->white transition (no need to scan the entire line!).
If you can make any guess about the position of the blobs you might be able to refine it a little by picking a starting point in the middle of the image and then searching left and right from there.
But I seriously doubt it would be worth the effort.
There is also no need to first run an edge detection algorithm on the image. Just scan the lines!
EDIT: Mr. Berna pointed out that this will not work with concave objects.