Calculate distance between colors in HSV space - colors

I intend to find a distance metric between two colours in HSV space.
Suppose that each colour element has 3 components: hue, saturation, and value. Hue is ranged between 0 to 360, saturation is ranged between 0 to 1, and value is ranged between 0 to 255.
Also hue has a circular property, for example, 359 in hue is closer to 0 in hue value than 10 in hue.
Can anyone provide a good metric to calculate the distance between 2 colour element in HSV space here?

First a short warning: Computing the distance of colors does not make sense (in most cases). Without considering the results of 50 years of research in Colorimetry, things like the CIECAM02 Color Space or perceptual linearity of distance measures, the result of such a distance measure will be counterintuitive. Colors that are "similar" according to your distance measure will appear "very different" to a viewer, and other colors, that have a large "distance" will be undistinguishable by viewers. However...
The actual question seems to aim mainly at the "Hue" part, which is a value between 0 and 360. And in fact, the values of 0 and 360 are the same - they both represent "red", as shown in this image:
Now, computing the difference of two of these values boils down to computing the distance of two points on a circle with a circumference of 360. You already know that the values are strictly in the range [0,360). If you did not know that, you would have to use the Floating-Point Modulo Operation to bring them into this range.
Then, you can compute the distance between these hue values, h0 and h1, as
hueDistance = min(abs(h1-h0), 360-abs(h1-h0));
Imagine this as painting both points on a circle, and picking the smaller "piece of the cake" that they describe - that is, the distance between them either in clockwise or in counterclockwise order.
EDIT Extended for the comment:
The "Hue" elements are in the range [0,360]. With the above formula, you can compute a distance between two hues. This distance is in the range [0,180]. Dividing the distance by 180.0 will result in a value in [0,1]
The "Saturation" elements are in the range [0,1]. The (absolute) difference between two saturations will also be in the range [0,1].
The "Value" elements are in the range [0,255]. The absolute difference between two values will thus be in the range [0,255] as well. Dividing this difference by 255.0 will result in a value in [0,1].
So imagine you have two HSV tuples. Call them (h0,s0,v0) and (h1,s1,v1). Then you can compute the distances as follows:
dh = min(abs(h1-h0), 360-abs(h1-h0)) / 180.0
ds = abs(s1-s0)
dv = abs(v1-v0) / 255.0
Each of these values will be in the range [0,1]. You can compute the length of this tuple:
distance = sqrt(dh*dh+ds*ds+dv*dv)
and this distance will be a metric for the HSV space.

Given hsv values, normalized to be in the ranges [0, 2pi), [0, 1], [0, 1], this formula will project the colors into the HSV cone and give you the squared (cartesian) distance in that cone:
( sin(h1)*s1*v1 - sin(h2)*s2*v2 )^2
+ ( cos(h1)*s1*v1 - cos(h2)*s2*v2 )^2
+ ( v1 - v2 )^2

In case you are looking for checking just the hue, Marco's answer will do it. However, for a more accurate comparison considering hue, saturation and value, Sean's answer is the right one.
You can't simply check the distance from hue, saturation and value equally, because hue is a circle, not a normal vector. It's not like RGB where red, green and blue are vectors
PS: I know I am not giving any new solutions with this post, but Sean's answer really saved me and I wanted to acknowledge it besides upvoting since it is not the top answer here.

Lets start with:
c0 = HSV( h0, s0, v0 )
c1 = HSV( h1, s1, v1 )
Here are two more solutions:
(Helix Length)Find the length of curve in euclidean space:
x = ( s0+t*(s1-s0) ) * cos( h0+t*( h1-h0 ) )
y = ( s0+t*(s1-s0) ) * sin( h0+t*( h1-h0 ) )
z = ( v0+t*(v1-v0) )
t goes from 0 to 1.
Note: h1-h0 is not just subtraction it is modulus subtraction.
This can be optimized by rotation and then use: h0=0, and h1 = min(abs(h1-h0), 360-abs(h1-h0))
(Helix Length over RGB)Same as above but convert above curve in to RGB instead to euclidean space then calculate arc length.
And again convex combination by coordinate of HSV colors, each point on HSV-line convert to RGB.
Calculate the length of that line in RGB space with euclidean norm.
helix_rgb( t ) = RGB( HSV( h0+t*( h1-h0 ), s0+t*(s1-s0), v0+t*(v1-v0) ) )
t goes from 0 to 1.
Note: h1-h0 is not just subtraction it is (more than) modulus subtraction e.g.
D(HSV(300,50,50),HSV(10,50,50)) = D(HSV(300,50,50),HSV( 0,50,50)) + D(HSV( 0,50,50), HSV(10,50,50))
Comparison of metrics:
RGB(0,1,0) is referent point and calculate distance to color in right-down corner image.
Color image is generated by rule HSL([0-360], 100, [1-100] ).
EM is short from Euclid with Modulo as Marco13 propose with Sean Gerrish's scale.
Comparison of solutions over HSI, HSL and HSV, there are also distance in RGB and CIE76(LAB).
Comparing EM to other solutions like Helix len, RGB2RGB, CIE76 appears that EM give acceptable result at very low cost.
In https://github.com/dmilos/color.git it is implemented EM with arbitrary scaling.
Example:
typedef ::color::hsv<double> color_t; // or HSI, HSL
color_t A = ::color::constant::orange_t{}; \
color_t B = ::color::constant::lime_t{}; \
auto distance = ::color::operation::distance<::color::constant::distance::hue_euclid_entity>( A, B, 3.1415926/* pi is default */ );

Related

Ellipse Overlap Area

I am working on an Eye Tracking application, and when I detect the pupil and enveloping it with an ellipse I have to compare it to a ground-truth (exact ellipse around the pupil).
There are always 3 cases of course:
No Overlap >> overlap = intersection = 0
Partial to Perfect Overlap >> overlap = intersection area / ground-truth area
Enclosing >> overlap = intersection area / ground truth
My problem is the 3rd case where e.g. found ellipse is much bigger than the ground-truth hence enclosing it inside so the total overlap is given as 1.0 which is mathematically right but detection-wise not really as the found ellipse doesn't only contain the pupil inside it but other non-pupil parts.
The question is:
What would be the best approach to measure and calculate the overlap percentage between the found and ground-truth ellipses? would be just mere division of the areas?
Please give some insights.
P.S.: I am coding with python and tried to use shapely library for the task as mentioned in the answer to this question as supposedly it does the transform to position the ellipses correctly regarding their rotational angle.
Let R be the reference ellipse, E the calculated ellipse.
We define score := area(E ∩ R) / area(E ∪ R). The larger the score the better the match.
As ∅ ⊆ E ∩ R ⊆ E ∪ R, we have 0 ≤ score ≤ 1, score=0 ⇔ (E ∩ R = ∅) and
score=1 ⇔ E=R.
Consider an ellipse that is completely enclosed by R and has half the area, as well as an ellipse that completely encloses R and has twice the area. Both would have a score of 0.5 . If they were closer to R, for example if the first had 4/5 the area and the second 5/4 the area both would have a score of 0.8 .

Estimate torsion for a discrete curve using four points

The curvature of a discrete space curve can be calculated using 3 successive points can be calculated using the Menger curvature (see https://en.wikipedia.org/wiki/Menger_curvature and Calculate curvature for 3 Points (x,y)).
My question is: is there a similar explicit formula for the torsion (https://en.wikipedia.org/wiki/Torsion_of_a_curve or ) using four 4 successive points?
If not an explicit formula, does someone know of an algorithm/package for calculating it? I work in python, but anything will do.
I can imagine the basic steps. Two successive vectors define a plane, and thus 3 successive vectors define two planes. The change in angle between the plane normals is proportional to the torsion. But I need an exact formula, with the calculated torsion having the proper dimension of 1/length^2.
Having some parametrization of curve r(t) (for example, by length of polyline chain) you can calculate three derivatives using 4 points: r', r'', r'''.
Then torsion is:
v = r' x r'' //(vector product)
torsion = (r''' .dot. v) / (v.dot.v) //.dot. is scalar product

Formula for calculating Euclidian direction in Excel

I am calculating Euclidian distance between points in an Excel application, and also need to be able to specify the direction of the difference in two-dimensional location for each pair of points.
Does anyone know how to implement this in Excel?
Below is a simplified illustration of my current Euclidian distance calculation. I have two points, and calculate how far apart Point1 is from Point2. But I would also like to find the direction (in degrees preferably) between Point1 and Point2.
For direction, you could use the angle that the vector from point one to point two makes with respect to the positive x axis:
=DEGREES(ATAN2(B3-B2,C3-C2))
this will return a number between -180 and +180 degrees. The ATAN2 function is given by ATAN2(x,y) = arctan(y/x) with the refinement that it returns pi/2 rather than a division by 0 error if x = 0 and also gives an answer in the appropriate quadrant.

Calculating the fraction of the area of multiple squares overlapped by a circle

This is a geometrical question based on a programming problem I have. Basically, I have a MySQL database full of latitude and longitude points, spaced out to be 1km from each other, corresponding to a population of people who live within the square kilometer around each point. I then want to know the relative fraction of each of those grids taken up by a circle of arbitrary size that overlaps them, so I can figure out how many people roughly live within a given circle.
Here is a practical example of one form of the problem (distances not to scale):
I am interested in knowing the population of people who live within a radius of point X. My database figures out that its entries for points A and B are close enough to point X to be relevant. Point A in this example is something like 40.7458, -74.0375, and point B is something like 40.7458, -74.0292. Each of those green lines from A and B to its grid edge represents 0.5 km, so that the gray circle around A and B each represent 1 km^2 respectively.
Point X is at around 40.744, -74.032, and has a radius (in purple) of 0.05 km.
Now I can easily calculate the red lines shown using geographic trig functions. So I know that the line AX is about .504 km, and the distance line BX is about .309 km, for whatever that gets me.
So my question is thus: what's a solid way for calculating the fraction of grid A and the fraction of grid B taken up by the purple circle inscribed around X?
Ultimately I will be taking the population totals and multiplying them by this fraction. So in this case, the 1 km^2 grid around corresponds to 9561 people, and the grid around B is 10763 people. So if I knew (just hypothetically) that the radius around X covered 1% of the area of A and 3% of the area of B, I could make a reasonable back-of-the-envelope estimate of the total population covered by that circle by multiplying the A and B populations by their respective fractions and just summing them.
I've only done it with two squares above, but depending on the size of the radius (which can be arbitrary), there may be a whole host of possible squares, like so, making it a more general problem:
In some cases, where it is easy to figure out that the square grid in question is 100% encompassed by the radius, it is in principle pretty easy (e.g. if the distance between AX was smaller than the radius around X, I know I don't have to do any further math).
Now, it's easy enough to figure out which points are within the range of the circle. But I'm a little stuck on figuring out what fractions of their corresponding areas are.
Thank you for your help.
I ended up coming up with what worked out to be a pretty good approximate solution, I think. Here is how it looks in PHP:
//$p is an array of latitude, longitude, value, and distance from the centerpoint
//$cx,$cy are the lat/lon of the center point, $cr is the radius of the circle
//$pdist is the distance from each node to its edge (in this case, .5 km, since it is a 1km x 1km grid)
function sum_circle($p, $cx, $cy, $cr, $pdist) {
$total = 0; //initialize the total
$hyp = sqrt(($pdist*$pdist)+($pdist*$pdist)); //hypotenuse of distance
for($i=0; $i<count($p); $i++) { //cycle over all points
$px = $p[$i][0]; //x value of point
$py = $p[$i][1]; //y value of point
$pv = $p[$i][2]; //associated value of point (e.g. population)
$dist = $p[$i][3]; //calculated distance of point coordinate to centerpoint
//first, the easy case — items that are well outside the maximum distance
if($dist>$cr+$hyp) { //if the distance is greater than circle radius plus the hypoteneuse
$per = 0; //then use 0% of its associated value
} else if($dist+$hyp<=$cr) { //other easy case - completely inside circle (distance + hypotenuse <= radius)
$per = 1; //then use 100% of its associated value
} else { //the edge cases
$mx = ($cx-$px); $my = ($cy-$py); //calculate the angle of the difference
$theta = abs(rad2deg(atan2($my,$mx)));
$theta = abs((($theta + 89) % 90 + 90) % 90 - 89); //reduce it to a positive degree between 0 and 90
$tf = abs(1-($theta/45)); //this basically makes it so that if the angle is close to 45, it returns 0,
//if it is close to 0 or 90, it returns 1
$hyp_adjust = ($hyp*(1-$tf)+($pdist*$tf)); //now we create a mixed value that is weighted by whether the
//hypotenuse or the distance between cells should be used
$per = ($cr-$dist+$hyp_adjust)/100; //lastly, we use the above numbers to estimate what percentage of
//the square associated with the centerpoint is covered
if($per>1) $per = 1; //normalize for over 100% or under 0%
if($per<0) $per = 0;
}
$total+=$per*$pv; //add the value multiplied by the percentage to the total
}
return $total;
}
This seems to work and is pretty fast (even though it does use some trig on the edge cases). The basic logic is that when calculating edge cases, the two extreme possibilities is that the circle radius is either exactly perpendicular to the grid, or exactly at 45 degree angles from it. So it figures out roughly where between those extremes it falls and then uses that to figure out roughly what percentage of the grid square is covered. It gives plausible results in my testing.
For the size of the squares and circles I am using, this seems to be adequate?
I wrote a little application in Processing.js to try and help me work this out. Without explaining all of it, you can see how the algorithm is "thinking" by looking at this screenshot:
Basically, if the circle is yellow it means it has already figured out it is 100% in, and if it is red it is already quickly screened as 100% out. The other cases are the edge cases. The number (ranging from 0 to 1) under the dot is the (rounded) percentage of coverage calculated using the above method, while the number under that is the calculated theta value used in the above code.
For my purposes I think this approximation is workable.
With enough classification (sketched below) all computations can be reduced to a primitive calculation, the one that provides the angular area of the orange region depicted in the image
When y0 > 0, as illustrated above, and regardless of whether x0 is positive or negative, the orange area can be calculated accurately as the integral from x0 to x1 of sqrt(r^2 - y^2) minus the rectangular area (x1 - x0) * (y1 - y0). The integral has a well known closed expression and therefore there is no need to use any numerical algorithm for calculating it.
Other intersections between a circle and a square can be reduced to a combination of rectangles and right-angular shapes as the one painted in orange above. For instance, an intersection delimited by the horizontal and vertical orange rays in the following picture can be expressed by summing the area of the red rectangle plus two angular shapes: the blue and the green.
The blue area results from a direct application of the primitive case identified above (where the inferior rectangle collapses to nothing.) The green one can also be measured in the same way, once the negative y coordinate is replaced by its absolute value (the other y being 0).
Applying these ideas one could enumerate all cases. Basically, one should consider the case where just one, two, three or four corners of the square lie inside the circle, while the remaining (if any) fall outside. The enumeration is a problem in itself, but it can be solved, at least in theory, by considering a relatively small number of "typical" configurations.
For each of the cases enumerated as described a decomposition on some few rectangles and angular areas has to be calculated and the parts added up (or subtracted) as shown in the three-color example above. The area of every part would reduce to rectangular or primitive angular areas.
A considerably amount of work has to be done to turn this line of attack into a working algorithm. A deeper analysis could shed some light on how to minimize the number of "typical" configurations to consider. If not, I think that the amount of combinations to consider, however large, should be manageable.
In case your problem admits an approximate answer there is another technique you could use which is much simpler to program. The whole idea of this problem reduces to calculate the area of the intersection of a square and a circle. I didn't explain this in my other answer, but finding the squares that are likely to intercept the circle shouldn't be a problem, otherwise, let us know.
The idea of calculating the approximate area of the intersection is very simple. Generate enough points in the square at random and check how many of them belong in the circle. The ratio between the number of points in the circle and the total number of random points in the square will give you the proportion of the intersection with respect to the square's area.
Now, given that you have to repeat the same routine for all squares surrounding the circle (i.e., squares which center has a distance to the circle's center not very different from the circle's radius) you could re-use the random points by translating them from one square to the other.
I don't want to go into details if this method is not appropriate for your problem, so let me just indicate that generating random points uniformly distributed in the square is fairly easy. You only need to generate random numbers for the x coordinate and, independently, random numbers for y. Then just consider all pairs (x, y). Then, for every (x, y) verify whether (x - a)^2 + (y - b)^2 <= r^2 or not, where (a, b) stands for the circle's center and r for the radius.

How can I find the 3D coordinates of a projected rectangle?

I have the following problem which is mainly algorithmic.
Let ABCD be a rectangle with known dimensions d1, d2 lying somewhere in space.
The rectangle ABCD is projected on a plane P (forming in the general case a trapezium KLMN). I know the projection matrix H.
I can also find the 2D coordinates of the trapezium edge points K,L,M,N.
The Question is the following :
Given the Projection Matrix H, The coordinates of the edges on the trapezium and the knowledge that our object is a rectangle with specified geometry (dimensions d1, d2), could we calculate the 3D coordinates of the points A, B, C, D ?
I am grabbing images of simple rectangles with a single camera and i want to reconstruct the rectangles on space. I could grab more than one image and use triangulation but this is not desired.
The projection Matrix alone isn't enough since a ray is projected to the same point. The fact that the object has known dimensions, makes me believe that the problem is solvable and there are finite solutions.
If I figure out how this reconstruction can be made I know how to program it. So I am asking for an algorithmic/math answer.
Any ideas are welcome
Thanks
You need to calculate the inverse of your projection matrix. (your matrix cannot be singular)
I'm going to give a fairly brief answer here, but I think you'll get my general drift. I'm assuming you have a 3x4 projection matrix (P), so you should be able to get the camera centre by finding the right null vector of P: call it C.
Once you have C, you'll be able to compute rays with the same direction as vectors CK,CL,CM and CN (i.e. the cross product of C and K,L,M or N, e.g. CxK)
Now all you have to do is compute 3 points (u1,u2,u3) which satisfies the following 6 constraints (arbitrarily assuming KL and KN are adjacent and ||KL|| >= ||KN|| if d1 >= d2):
u1 lies on CK, i.e. u1.CK = 0
u2 lies on CL
u3 lies on CN
||u1-u2|| = d1
||u1-u3|| = d2
(u1xu2).(u1xu3) = 0 (orthogonality)
where, A.B = dot product of vectors A and B
||A|| = euclidean norm of A
AxB = cross product of A and B
I think this problem will generate a set of possible solutions, at least in 2D it does. For the 2D case:
|
-----------+-----------
/|\
/ | \
/ | \
/---+---\VP
/ | \
/ | \
/ | \
/ | \
/ | -- \
/ | | \
/ | | \
In the above diagram, the vertical segment and the horizontal segment would project to the same line on the view plane (VP). If you drew this out to scale you'd see that there are two rays from the eye passing through each end point of the unprojected line. This line can be in many positions and rotations - imagine dropping a stick into a cone, it can get stuck in any number of positions.
So, in 2D space there are an infinite number of solutions within a well defined set.
Does this apply to 3D?
The algorithm would be along the lines of:
Invert the projection matrix
Calculate the four rays that pass through the vertices of the rectangle, effectively creating a skewed pyramid
Try and fit your rectangle into the pyramid. This is the tricky bit and I'm trying to mentally visualise rectangles in pyramids to see if they can fit in more than one way.
EDIT: If you knew the distance to the object it would become trivial.
EDIT V2:
OK, let Rn be the four rays in world space, i.e. transformed via the inverse matrix, expressed in terms of m.Rn, where |Rn| is one. The four points of the rectange are therefore:
P1 = aR1
P2 = bR2
P3 = cR3
P4 = dR4
where P1..P4 are the points around the circumference of the rectangle. From this, using a bit of vector maths, we can derive four equations:
|aR1 - bR2| = d1
|cR3 - dR4| = d1
|aR1 - cR3| = d2
|bR2 - dR4| = d2
where d1 and d2 are the lengths of the sides of the rectangle and a, b, c and d are the unknowns.
Now, there may be no solution to the above in which case you'd need to swap d1 with d2. You can expand each line to:
(a.R1x - b.R2x)2 + (a.R1y - b.R2y)2 + (a.R1z - b.R2z)2 = d12
where R1? and R2? are the x/y/z components of rays 1 and 2. Note that you're solving for a and b in the above, not x,y,z.
m_oLogin is right. If I understand your goal, the image the camera snaps is the plane P, right? If so, you're measuring K,L,M,N off the 2D image. You need the inverse of the projection matrix to reconstruct A,B,C, and D.
Now I've never done this before, but it ocurrs to me that you might run into the same problem GPS does with only 3 satellite fixes - there are two possible solutions, one 'behind' P and one 'in front' of it, right?
The projection matrix encapsulates both the perspective and scale, so the inverse will give you the solution you are after. I think you are assuming that it only encapsulates the perspective, and you need something else to choose the correct scale.

Resources