I'm currently developing a script for a map in COD4. I think that the language is so simple that I'm tagging this as language-agnostic since the problem is in the algorithm for this situation.
There is a room which is 960 units wide. And inside it there's an object in the middle, which we'll count as the axis. The ball is supposed to move to a random position each time it is hit, but should not traverse further than the walls. Here's a diagram:
The API of the game only allows the moving of objects relative to its position, as far as I know, so here's code that I came up with. The problem is that after the second call to head_move() it begins to produce unexpected results and this is crashing my head. Could somebody help me out?
movementThink():
while (1)
{
self waittill ("trigger", player); //Wait till player hits the object
head_origin thread head_move();
}
head_move()
{
/* level.prevx is a global variable which I use to store
the distance traveled in the previous shot. Defaults to 0 */
/*This works in the first and second hit, but then it begins to show
incorrect max and min values*/
x_min = (0-480) + level.prevx;
x_max = x_min + 960;
x_units = RandomIntRange( x_min, x_max ); //Create a random integrer
log2screen("MIN: " + x_min + " and MAX: " + x_max + " and MOVED " + x_units);
log2screen("Moved " + x_units);
//Movement function, first parameter is the distance to be traveled, and the second one is the speed
self movex (x_units , level.movespeed);
level.prevx = x_units;
}
EDIT: Just to clarify. When the user shoots the ball, its position changes to a certain value. Now, if he hits it again, the min and max values of the random int generator should change to prevent the ball from moving outside the walls. Example:
Level starts. The ball is in the middle of the room. The min and max ranges are -480 and 480 respectively
The user hits the ball and its moved -200 units (200 units to the left).
Now, the min and max range should be -280 and 680.
I hope this is clear enough.
EDIT 2: Edited the sign as FlipScript suggested. Here's the output from the log2screen functions, what is actually happening:
MIN: -480 and MAX 480. MOVED 67
MIN: -413 and MAX 547. MOVED 236
MIN: -244 and MAX 716. MOVED 461
Just a sample case. Something is backwards I believe, these aren't the right calculations to do.
Your code works only when self.prevx contains your displacement from the starting position, i.e. your absolute position. However, what you are storing is your displacement from your current position. It works the first two times because that displacement happens to be the same as your absolute position, but once you move again, you lose all track of where you are.
What you should do instead is get rid of min and max, and start by calculating a random absolute position within the bounds. Then use your previously stored absolute position to calculate the relative movement needed to get you there, and store the new absolute position.
head_move()
{
new_x = RandomIntRange( -480, 480 ); //create a random location
delta_x = new_x - level.prev; //determine relative movement needed to get there
self movex (delta_x , level.movespeed); //move to new position
level.prevx = new_x; //store new position
}
I dont know much about the programming environment, but this line
head_origin thread head_move();
is suspicious for troublemaking. What are these tokens? Anything that says thread could be duplicating data structures and throwing your local variables astray.
And why do x_min and x_max change? Where's y_min and y_max?
Something doesn't look right in this line here:
x_max = x_min - 960;
Is the MAX really the MIN MINUS 960? From your description, it sounds like that should be a '+' sign.
EDIT:
In your additional comments, the minus sign wouldn't allow these truths:
Level starts....The min and max ranges are -480 and 480 respectively
...
Now, the min and max range should be -280 and 680.
Comments 1 and 3 point to that sign needing to be '+' sign.
Related
I am trying to create an android smartphone application which uses Apples iBeacon technology to determine the current indoor location of itself. I already managed to get all available beacons and calculate the distance to them via the rssi signal.
Currently I face the problem, that I am not able to find any library or implementation of an algorithm, which calculates the estimated location in 2D by using 3 (or more) distances of fixed points with the condition, that these distances are not accurate (which means, that the three "trilateration-circles" do not intersect in one point).
I would be deeply grateful if anybody can post me a link or an implementation of that in any common programming language (Java, C++, Python, PHP, Javascript or whatever). I already read a lot on stackoverflow about that topic, but could not find any answer I were able to convert in code (only some mathematical approaches with matrices and inverting them, calculating with vectors or stuff like that).
EDIT
I thought about an own approach, which works quite well for me, but is not that efficient and scientific. I iterate over every meter (or like in my example 0.1 meter) of the location grid and calculate the possibility of that location to be the actual position of the handset by comparing the distance of that location to all beacons and the distance I calculate with the received rssi signal.
Code example:
public Location trilaterate(ArrayList<Beacon> beacons, double maxX, double maxY)
{
for (double x = 0; x <= maxX; x += .1)
{
for (double y = 0; y <= maxY; y += .1)
{
double currentLocationProbability = 0;
for (Beacon beacon : beacons)
{
// distance difference between calculated distance to beacon transmitter
// (rssi-calculated distance) and current location:
// |sqrt(dX^2 + dY^2) - distanceToTransmitter|
double distanceDifference = Math
.abs(Math.sqrt(Math.pow(beacon.getLocation().x - x, 2)
+ Math.pow(beacon.getLocation().y - y, 2))
- beacon.getCurrentDistanceToTransmitter());
// weight the distance difference with the beacon calculated rssi-distance. The
// smaller the calculated rssi-distance is, the more the distance difference
// will be weighted (it is assumed, that nearer beacons measure the distance
// more accurate)
distanceDifference /= Math.pow(beacon.getCurrentDistanceToTransmitter(), 0.9);
// sum up all weighted distance differences for every beacon in
// "currentLocationProbability"
currentLocationProbability += distanceDifference;
}
addToLocationMap(currentLocationProbability, x, y);
// the previous line is my approach, I create a Set of Locations with the 5 most probable locations in it to estimate the accuracy of the measurement afterwards. If that is not necessary, a simple variable assignment for the most probable location would do the job also
}
}
Location bestLocation = getLocationSet().first().location;
bestLocation.accuracy = calculateLocationAccuracy();
Log.w("TRILATERATION", "Location " + bestLocation + " best with accuracy "
+ bestLocation.accuracy);
return bestLocation;
}
Of course, the downside of that is, that I have on a 300m² floor 30.000 locations I had to iterate over and measure the distance to every single beacon I got a signal from (if that would be 5, I do 150.000 calculations only for determine a single location). That's a lot - so I will let the question open and hope for some further solutions or a good improvement of this existing solution in order to make it more efficient.
Of course it has not to be a Trilateration approach, like the original title of this question was, it is also good to have an algorithm which includes more than three beacons for the location determination (Multilateration).
If the current approach is fine except for being too slow, then you could speed it up by recursively subdividing the plane. This works sort of like finding nearest neighbors in a kd-tree. Suppose that we are given an axis-aligned box and wish to find the approximate best solution in the box. If the box is small enough, then return the center.
Otherwise, divide the box in half, either by x or by y depending on which side is longer. For both halves, compute a bound on the solution quality as follows. Since the objective function is additive, sum lower bounds for each beacon. The lower bound for a beacon is the distance of the circle to the box, times the scaling factor. Recursively find the best solution in the child with the lower lower bound. Examine the other child only if the best solution in the first child is worse than the other child's lower bound.
Most of the implementation work here is the box-to-circle distance computation. Since the box is axis-aligned, we can use interval arithmetic to determine the precise range of distances from box points to the circle center.
P.S.: Math.hypot is a nice function for computing 2D Euclidean distances.
Instead of taking confidence levels of individual beacons into account, I would instead try to assign an overall confidence level for your result after you make the best guess you can with the available data. I don't think the only available metric (perceived power) is a good indication of accuracy. With poor geometry or a misbehaving beacon, you could be trusting poor data highly. It might make better sense to come up with an overall confidence level based on how well the perceived distance to the beacons line up with the calculated point assuming you trust all beacons equally.
I wrote some Python below that comes up with a best guess based on the provided data in the 3-beacon case by calculating the two points of intersection of circles for the first two beacons and then choosing the point that best matches the third. It's meant to get started on the problem and is not a final solution. If beacons don't intersect, it slightly increases the radius of each up until they do meet or a threshold is met. Likewise, it makes sure the third beacon agrees within a settable threshold. For n-beacons, I would pick 3 or 4 of the strongest signals and use those. There are tons of optimizations that could be done and I think this is a trial-by-fire problem due to the unwieldy nature of beaconing.
import math
beacons = [[0.0,0.0,7.0],[0.0,10.0,7.0],[10.0,5.0,16.0]] # x, y, radius
def point_dist(x1,y1,x2,y2):
x = x2-x1
y = y2-y1
return math.sqrt((x*x)+(y*y))
# determines two points of intersection for two circles [x,y,radius]
# returns None if the circles do not intersect
def circle_intersection(beacon1,beacon2):
r1 = beacon1[2]
r2 = beacon2[2]
dist = point_dist(beacon1[0],beacon1[1],beacon2[0],beacon2[1])
heron_root = (dist+r1+r2)*(-dist+r1+r2)*(dist-r1+r2)*(dist+r1-r2)
if ( heron_root > 0 ):
heron = 0.25*math.sqrt(heron_root)
xbase = (0.5)*(beacon1[0]+beacon2[0]) + (0.5)*(beacon2[0]-beacon1[0])*(r1*r1-r2*r2)/(dist*dist)
xdiff = 2*(beacon2[1]-beacon1[1])*heron/(dist*dist)
ybase = (0.5)*(beacon1[1]+beacon2[1]) + (0.5)*(beacon2[1]-beacon1[1])*(r1*r1-r2*r2)/(dist*dist)
ydiff = 2*(beacon2[0]-beacon1[0])*heron/(dist*dist)
return (xbase+xdiff,ybase-ydiff),(xbase-xdiff,ybase+ydiff)
else:
# no intersection, need to pseudo-increase beacon power and try again
return None
# find the two points of intersection between beacon0 and beacon1
# will use beacon2 to determine the better of the two points
failing = True
power_increases = 0
while failing and power_increases < 10:
res = circle_intersection(beacons[0],beacons[1])
if ( res ):
intersection = res
else:
beacons[0][2] *= 1.001
beacons[1][2] *= 1.001
power_increases += 1
continue
failing = False
# make sure the best fit is within x% (10% of the total distance from the 3rd beacon in this case)
# otherwise the results are too far off
THRESHOLD = 0.1
if failing:
print 'Bad Beacon Data (Beacon0 & Beacon1 don\'t intersection after many "power increases")'
else:
# finding best point between beacon1 and beacon2
dist1 = point_dist(beacons[2][0],beacons[2][1],intersection[0][0],intersection[0][1])
dist2 = point_dist(beacons[2][0],beacons[2][1],intersection[1][0],intersection[1][1])
if ( math.fabs(dist1-beacons[2][2]) < math.fabs(dist2-beacons[2][2]) ):
best_point = intersection[0]
best_dist = dist1
else:
best_point = intersection[1]
best_dist = dist2
best_dist_diff = math.fabs(best_dist-beacons[2][2])
if best_dist_diff < THRESHOLD*best_dist:
print best_point
else:
print 'Bad Beacon Data (Beacon2 distance to best point not within threshold)'
If you want to trust closer beacons more, you may want to calculate the intersection points between the two closest beacons and then use the farther beacon to tie-break. Keep in mind that almost anything you do with "confidence levels" for the individual measurements will be a hack at best. Since you will always be working with very bad data, you will defintiely need to loosen up the power_increases limit and threshold percentage.
You have 3 points : A(xA,yA,zA), B(xB,yB,zB) and C(xC,yC,zC), which respectively are approximately at dA, dB and dC from you goal point G(xG,yG,zG).
Let's say cA, cB and cC are the confidence rate ( 0 < cX <= 1 ) of each point.
Basically, you might take something really close to 1, like {0.95,0.97,0.99}.
If you don't know, try different coefficient depending of distance avg. If distance is really big, you're likely to be not very confident about it.
Here is the way i'll do it :
var sum = (cA*dA) + (cB*dB) + (cC*dC);
dA = cA*dA/sum;
dB = cB*dB/sum;
dC = cC*dC/sum;
xG = (xA*dA) + (xB*dB) + (xC*dC);
yG = (yA*dA) + (yB*dB) + (yC*dC);
xG = (zA*dA) + (zB*dB) + (zC*dC);
Basic, and not really smart but will do the job for some simple tasks.
EDIT
You can take any confidence coef you want in [0,inf[, but IMHO, restraining at [0,1] is a good idea to keep a realistic result.
Sorry about the vague title. I'm not sure how to concisely word what I'm about to ask. This is more of a math/algorithms question than a programming question.
In an app that I'm developing, we have a value that can fluctuate anywhere between 0 and a predetermined maximum (in testing it's usually hovered around 100, so let's just say 100). This range of data is continuous, meaning there are an infinite number of possible values- as long as it's between 0 and 100, it's possible.
Right now, any value returned from this is mapped to a different range that is also continuous- from 1000 to 200. So if the value from the first set is 100, I map it to 200, and if the value from the first set is 0, it gets mapped to 1000. And of course everything in between. This is what the code looks like:
-(float)mapToRange:(float)val withMax:(float)maxVal{
// Establish range constants.
const int upperBound = 1000;
const int lowerBound = 200;
const int bandwidth = upperBound - lowerBound;
// Make sure we don't go above the calibrated maximum.
if(val > maxVal)
val = maxVal;
// Scale the original value to our new boundaries.
float scaled = val/maxVal;
float ret = upperBound - scaled*bandwidth;
return ret;
}
Now, what I want to do is make it so that the higher original values (closer to 100) increase in larger increments than the lower original values (closer to 0). Meaning if I slowly start decreasing from 100 to 0 at a steady rate, the new values starting at 200 move quickly toward 1000 at first but go in smaller increments the closer they get to 1000. What would be the best way to go about doing this?
Your value scaled is basically the 0-100 value represented in the range 0-1 so it's good to work with. Try raising this to an integer power, and the result will increase faster near 1 and slower near 0. The higher the power, the larger the effect. So something like:
float scaled = val/maxVal;
float bent = scaled*scaled*scaled*scaled; // or however you want to write x^4
float ret = upperBound - bent*bandwidth;
Here's a sketch of the idea:
That is, the span A to B, maps to the smaller span a to b, while the span C to D maps to the larger span c to d. The larger the power of the polynomial, the more the curve will be bent into the lower right corner.
The advantage of using the 0 to 1 range is that the endpoints stay fixed since x^n=x when x is 0 or 1, but this, of course, isn't necessary as anything could be compensated for by the appropriate shifting and scaling.
Note also that this map isn't symmetric (though my drawing sort of looks that way), though course a symmetric curve could be chosen. If you want to curve to bend the other way, choose a power less than 1.
I'm making a little game. It's a 2D game, and the main feature is to change the direction of gravity. I managed to change the direction, so now the player "falls" to the direction fo the gravity. But now i want the player to "stabilize" in eg. 2 seconds. I implemented basic rotation but that instantly changes the angle of the player, and i want it to "slice" the steps to smaller pieces so the rotation will be "smoother". eg. i want to change from 180° to 0° in small steps calculated from the delta time, in relation with a number I input which will be the "duration"
Im not quite familiar with radians and thats why i cant use it.
The gravity direction can be set using world.gravitydir variable, it can be 1,2,3,4. 1 is normal gravity "down" 2,4 is "left" and "right", and 3 is "up"
I also have some "dev commands" to change the gravity direction manually using arrow keys
This is my attempt on rotating the player from upside down to normal smoothly.
function rotatePlayer(dt)
deg1 = player.rot -- player's current rotation
step = 0
deg2 = math.rad(0) -- desired rotation
step = (math.deg(deg1) - math.deg(deg2))*dt
for i = deg1, deg2 do
player.rot = player.rot - math.rad(step)
step = step - dt
end
end
playerrotation function is in gravity.lua , and the dev controller, and the player drawing function is in player.lua
Source: http://www.mediafire.com/download/3xto995yz638n0n/notitle.love
I've noticed a couple issues with your code.
deg2 = math.rad(0) -- desired rotation
0 radians is equivalent to 0 degrees, so it would seem deg2 is always zero, thus
for i = deg1, deg2 do
would only run when deg1 is equal to or less than zero, which likely means it isn't running as you intended.
Secondly, any variables that don't need to leave their scope should be localized. This is a Lua best practice. Your function could be rewritten with locals, for example:
function rotatePlayer(dt)
local deg1 = player.rot -- player's current rotation
local step = 0 -- ! Any reference to a "step" variable within the scope of this function will always refer to this particular variable.
local deg2 = 0 -- desired rotation
step = (math.deg(deg1) - math.deg(deg2))*dt
for i = deg1, deg2 do
player.rot = player.rot - math.rad(step)
step = step - dt
end
end
The following line is equivalent to multiplying the degrees of the player's rotation by the delta dt, due to the previously established fact that deg2 is always zero.
step = (math.deg(deg1) - math.deg(deg2))*dt
The following lines are equivalent to taking the player's original rotation in degrees multiplied by the delta (step) and subtracting the radians version of that off of the player's current rotation, then subtracting the delta dt from the step value, inside of a loop which is executed within a single game frame I might add. I wasn't sure if you were aware that loop is run within one frame.
player.rot = player.rot - math.rad(step)
step = step - dt
I'm not sure what your intention was with those operations, but maybe you can tell me more.
As for achieving a smoother animation, you'll need to scale down your rate and adjust how the rotation is carried out. I've rewritten your function as follows and hope that it, as an example, clarifies how this could be written better:
function rotatePlayer(dt) -- dt is seconds since last update
local current = player.rot -- player's current rotation in radians
local target = 0 -- desired angle in radians
local difference = target - current
if difference == 0 then -- nothing to be done here
return
end
local rate = math.pi / 4 -- radians turned per second (adjust as necessary)
local change = rate * dt -- r/s * delta(change in time)
if difference < 0 then
-- make change negative, since difference is as well
change = change * -1
-- If (current + change > target), settle for the lesser difference.
-- This keeps us from "overshooting" the player's rotation
-- towards a particular target.
change = math.max(change, difference)
else
change = math.min(change, difference)
end
player.rot = current + change
end
Please let me know if this resolves your problem and if you have any more questions.
I've put a change to player.lua on pastebin Stackoverflow Love2d game .
It rotates the player at a fixed rate rather than a fixed time. To do the latter just make rottime constant.
Here's the problem: I have a number of binary images composed by traces of different thickness. Below there are two images to illustrate the problem:
First Image - size: 711 x 643 px
Second Image - size: 930 x 951 px
What I need is to measure the average thickness (in pixels) of the traces in the images. In fact, the average thickness of traces in an image is a somewhat subjective measure. So, what I need is a measure that have some correlation with the radius of the trace, as indicated in the figure below:
Notes
Since the measure doesn't need to be very precise, I am willing to trade precision for speed. In other words, speed is an important factor to the solution of this problem.
There might be intersections in the traces.
The trace thickness might not be constant, but an average measure is OK (even the maximum trace thickness is acceptable).
The trace will always be much longer than it is wide.
I'd suggest this algorithm:
Apply a distance transformation to the image, so that all background pixels are set to 0, all foreground pixels are set to the distance from the background
Find the local maxima in the distance transformed image. These are points in the middle of the lines. Put their pixel values (i.e. distances from the background) image into a list
Calculate the median or average of that list
I was impressed by #nikie's answer, and gave it a try ...
I simplified the algorithm for just getting the maximum value, not the mean, so evading the local maxima detection algorithm. I think this is enough if the stroke is well-behaved (although for self intersecting lines it may not be accurate).
The program in Mathematica is:
m = Import["http://imgur.com/3Zs7m.png"] (* Get image from web*)
s = Abs[ImageData[m] - 1]; (* Invert colors to detect background *)
k = DistanceTransform[Image[s]] (* White Pxs converted to distance to black*)
k // ImageAdjust (* Show the image *)
Max[ImageData[k]] (* Get the max stroke width *)
The generated result is
The numerical value (28.46 px X 2) fits pretty well my measurement of 56 px (Although your value is 100px :* )
Edit - Implemented the full algorithm
Well ... sort of ... instead of searching the local maxima, finding the fixed point of the distance transformation. Almost, but not quite completely unlike the same thing :)
m = Import["http://imgur.com/3Zs7m.png"]; (*Get image from web*)
s = Abs[ImageData[m] - 1]; (*Invert colors to detect background*)
k = DistanceTransform[Image[s]]; (*White Pxs converted to distance to black*)
Print["Distance to Background*"]
k // ImageAdjust (*Show the image*)
Print["Local Maxima"]
weights =
Binarize[FixedPoint[ImageAdjust#DistanceTransform[Image[#], .4] &,s]]
Print["Stroke Width =",
2 Mean[Select[Flatten[ImageData[k]] Flatten[ImageData[weights]], # != 0 &]]]
As you may see, the result is very similar to the previous one, obtained with the simplified algorithm.
From Here. A simple method!
3.1 Estimating Pen Width
The pen thickness may be readily estimated from the area A and perimeter length L of the foreground
T = A/(L/2)
In essence, we have reshaped the foreground into a rectangle and measured the length of the longest side. Stronger modelling of the pen, for instance, as a disc yielding circular ends, might allow greater precision, but rasterisation error would compromise the signicance.
While precision is not a major issue, we do need to consider bias and singularities.
We should therefore calculate area A and perimeter length L using functions which take into account "roundedness".
In MATLAB
A = bwarea(.)
L = bwarea(bwperim(.; 8))
Since I don't have MATLAB at hand, I made a small program in Mathematica:
m = Binarize[Import["http://imgur.com/3Zs7m.png"]] (* Get Image *)
k = Binarize[MorphologicalPerimeter[m]] (* Get Perimeter *)
p = N[2 Count[ImageData[m], Except[1], 2]/
Count[ImageData[k], Except[0], 2]] (* Calculate *)
The output is 36 Px ...
Perimeter image follows
HTH!
Its been a 3 years since the question was asked :)
following the procedure of #nikie, here is a matlab implementation of the stroke width.
clc;
clear;
close all;
I = imread('3Zs7m.png');
X = im2bw(I,0.8);
subplottight(2,2,1);
imshow(X);
Dist=bwdist(X);
subplottight(2,2,2);
imshow(Dist,[]);
RegionMax=imregionalmax(Dist);
[x, y] = find(RegionMax ~= 0);
subplottight(2,2,3);
imshow(RegionMax);
List(1:size(x))=0;
for i = 1:size(x)
List(i)=Dist(x(i),y(i));
end
fprintf('Stroke Width = %u \n',mean(List));
Assuming that the trace has constant thickness, is much longer than it is wide, is not too strongly curved and has no intersections / crossings, I suggest an edge detection algorithm which also determines the direction of the edge, then a rise/fall detector with some trigonometry and a minimization algorithm. This gives you the minimal thickness across a relatively straight part of the curve.
I guess the error to be up to 25%.
First use an edge detector that gives us the information where an edge is and which direction (in 45° or PI/4 steps) it has. This is done by filtering with 4 different 3x3 matrices (Example).
Usually I'd say it's enough to scan the image horizontally, though you could also scan vertically or diagonally.
Assuming line-by-line (horizontal) scanning, once we find an edge, we check if it's a rise (going from background to trace color) or a fall (to background). If the edge's direction is at a right angle to the direction of scanning, skip it.
If you found one rise and one fall with the correct directions and without any disturbance in between, measure the distance from the rise to the fall. If the direction is diagonal, multiply by squareroot of 2. Store this measure together with the coordinate data.
The algorithm must then search along an edge (can't find a web resource on that right now) for neighboring (by their coordinates) measurements. If there is a local minimum with a padding of maybe 4 to 5 size units to each side (a value to play with - larger: less information, smaller: more noise), this measure qualifies as a candidate. This is to ensure that the ends of the trail or a section bent too much are not taken into account.
The minimum of that would be the measurement. Plausibility check: If the trace is not too tangled, there should be a lot of values in that area.
Please comment if there are more questions. :-)
Here is an answer that works in any computer language without the need of special functions...
Basic idea: Try to fit a circle into the black areas of the image. If you can, try with a bigger circle.
Algorithm:
set image background = 0 and trace = 1
initialize array result[]
set minimalExpectedWidth
set w = minimalExpectedWidth
loop
set counter = 0
create a matrix of zeros size w x w
within a circle of diameter w in that matrix, put ones
calculate area of the circle (= PI * w)
loop through all pixels of the image
optimization: if current pixel is of background color -> continue loop
multiply the matrix with the image at each pixel (e.g. filtering the image with that matrix)
(you can do this using the current x and y position and a double for loop from 0 to w)
take the sum of the result of each multiplication
if the sum equals the calculated circle's area, increment counter by one
store in result[w - minimalExpectedWidth]
increment w by one
optimization: include algorithm from further down here
while counter is greater zero
Now the result array contains the number of matches for each tested width.
Graph it to have a look at it.
For a width of one this will be equal to the number of pixels of trace color. For a greater width value less circle areas will fit into the trace. The result array will thus steadily decrease until there is a sudden drop. This is because the filter matrix with the circular area of that width now only fits into intersections.
Right before the drop is the width of your trace. If the width is not constant, the drop will not be that sudden.
I don't have MATLAB here for testing and don't know for sure about a function to detect this sudden drop, but we do know that the decrease is continuous, so I'd take the maximum of the second derivative of the (zero-based) result array like this
Algorithm:
set maximum = 0
set widthFound = 0
set minimalExpectedWidth as above
set prevvalue = result[0]
set index = 1
set prevFirstDerivative = result[1] - prevvalue
loop until index is greater result length
firstDerivative = result[index] - prevvalue
set secondDerivative = firstDerivative - prevFirstDerivative
if secondDerivative > maximum or secondDerivative < maximum * -1
maximum = secondDerivative
widthFound = index + minimalExpectedWidth
prevFirstDerivative = firstDerivative
prevvalue = result[index]
increment index by one
return widthFound
Now widthFound is the trace width for which (in relation to width + 1) many more matches were found.
I know that this is in part covered in some of the other answers, but my description is pretty much straightforward and you don't have to have learned image processing to do it.
I have interesting solution:
Do edge detection, for edge pixels extraction.
Do physical simulation - consider edge pixels as positively charged particles.
Now put some number of free positively charged particles in the stroke area.
Calculate electrical force equations for determining movement of these free particles.
Simulate particles movement for some time until particles reach position equilibrium.
(As they will repel from both stoke edges after some time they will stay in the middle line of stoke)
Now stroke thickness/2 would be average distance from edge particle to nearest free particle.
What's a good algorithm for "bouncing cards" like the ones you see in solitaire games?
What's the coolest card animation you've seen?
Edit - Any besides the Windows game?
The x-axis velocity is constant. The y-velocity is incremented by some value every frame. Each frame, the current x and y positions are incremented by the respective velocities. If the card would end up below the window, y-velocity is multiplied by something like -0.9. (negative number > -1) This produces the series of descending bounces.
Two parts:
motion in the vertical direction is
governed by a second order equation,
like d=1/2at². For Earth, of
course, a= 32 ft/sec² but
you'll have to twiddle the
constants.
When the card hits the edge, as
"recursive" says, the velocity
vector is multiplied by -1 times the
component normal to the surface. If
you want it to bounce nicely to a
stop, make the -1 some slightly
smaller value, like -0.9.
Animate it by updating and redrawing the card some number of times a second, changing the position of the card each time. The easy way is to compute something like (pseudo-Python):
vel_x = # some value, units/sec
vel_y = # some value, units/sec
acc_x = # some value in units/sec^2
acc_y = # some value in units/sec^2
while not_stopped():
x = x+vel_x
y = y+vel_y
# redraw the card here at new position
if card_collided():
# do the bounce calculation
vel_x = x + (0.5 * acc_x) # 1st derivative, gives units/sec
vel_y = y + (0.5 * acc_y)
As long as the cards are staying four-square with the sides, then you collide with the sides when the distance between the card center and the wall is 1/2 the width or hieght as appropriate.
After struggling with the code Charlie provided for an hour or so, I came up with the proper algorithm (after reading recursive's response thoroughly). In real Python:
def bouncing_cards():
x = 0.0
y = 0.0
vel_x = 3.0
vel_y = 4.0
while x < windowWidth:
drawImage(img, x, y)
x += vel_x
y += vel_y
vel_y += 1.0
if y + cardHeight >= windowHeight:
y = windowHeight - cardHeight
vel_y *= -0.9
Gives the following using wxPython: http://i.imgur.com/t51SXVC.png :)