I am working in an application where I need to know the intermediate points between two xy coordinates in CIE 1931 colour space.
In the picture below we can see that a linear transition (straight line) between A and B will go through a series of other colours, and I am struggling to find a mathematical way of describing the transitions between A and B.
Any ideas?
If I got your problem correctly, it's just a matter of finding a parameterization of a point on segment A-B in your illustration. The fact that it is a color is irrelevant.
Let C with coordinates (Xc,Yc) be such a point.
Then C can be written as:
Xc = Xa + a * (Xb-Xa)
Yc = Ya + a * (Yb-Ya)
where a is a fractional number in the range [0 ; 1]
this is my situation: I have a 30x30 image and I want to calculate the radial and tangent component of the gradient of each point (pixel) along the straight line passing through the centre of the image (15,15) and the same (i,j) point.
[dx, dy] = gradient(img);
for i=1:30
for j=1:30
pt = [dx(i, j), dy(i,j)];
line = [i-15, j-15];
costh = dot(line, pt)/(norm(line)*norm(pt));
par(i,j) = norm(costh*line);
tang(i,j) = norm(sin(acos(costh))*line);
end
end
is this code correct?
I think there is a conceptual error in your code, I tried to get your results with a different approach, see how it compares to yours.
[dy, dx] = gradient(img);
I inverted x and y because the usual convention in matlab is to have the first dimension along the rows of a matrix while gradient does the opposite.
I created an array of the same size as img but with each pixel containing the angle of the vector from the center of the image to this point:
[I,J] = ind2sub(size(img), 1:numel(img));
theta=reshape(atan2d(I-ceil(size(img,1)/2), J-ceil(size(img,2)/2)), size(img))+180;
The function atan2d ensures that the 4 quadrants give distinct angle values.
Now the projection of the x and y components can be obtained with trigonometry:
par=dx.*sind(theta)+dy.*cosd(theta);
tang=dx.*cosd(theta)+dy.*sind(theta);
Note the use of the .* to achieve point-by-point multiplication, this is a big advantage of Matlab's matrix computations which saves you a loop.
Here's an example with a well-defined input image (no gradient along the rows and a constant gradient along the columns):
img=repmat(1:30, [30 1]);
The results:
subplot(1,2,1)
imagesc(par)
subplot(1,2,2)
imagesc(tang)
colorbar
I have a free clip art SVG file originally created in Inkscape which I'm making modifications to for use in a Windows 8 JavaScript game. It contains numerous instances of a path with a matrix transform applied on a surrounding group, like this:
<g transform="matrix(0.443,0.896,-0.896,0.443,589.739,-373.223)">
<path d="M486,313s27-9,43-29l26,4,1,23-22,5s-25-6-48-3z" />
</g>
I want to flatten that transform by applying it in advance to the path in Inkscape, to reduce browser work during animation. However when I plug the 6 matrix values into the A B C D E F parameters in Inkscape and apply it, it gives the path a completely different rotation and scaling to what the IE10 engine does.
I have checked numerous times that I have the 6 values mapped correctly. What am I doing wrong?
EDIT: OK, here are before and after screenshots from IE10 and Inkscape. For the IE10 case, the SVG resides directly inside the body of an otherwise empty HTML document (the rendering is exactly the same in Firefox). In Inkscape, I simply opened the "before" SVG file which contains only the path element, selected the path, and plugged in the 6 matrix transform values into Object > Transform > Matrix.
I know very little about matrices, I just want to be able to pre-apply these transformations in the same way the browser does, and ideally to understand why there is a difference in Inkscape. Thanks.
Short answer
When typing the transformation matrix params in Inkscape, make sure you have "Edit current matrix" checked, since if you apply a new transformation matrix to an object, you're actually multiplying this new matrix with the existing transformation matrix of the object, so make sure you edit it instead.
Long Answer
How to recalculate everything yourself.
First let us try and understand the transformation matrices a bit.
A transformation matrix is a quick and clever tool for applying affine transformations ( transformation which preserves straight lines) to a vector.
So, if you have a vector (say, 2d coordinates) and a transformation matrix, and multiply the two together, you will end up with transformed coordinates, with the transformations defined in the transformation matrix, applied.
Calculating x' and y' is done like so:
x' = a*x + c*y + e
y' = b*x + d*y + f
Next, we need to understand the svg format a bit.
According to the w3c svg spec the matrix transform takes exactly those 6 parameters (a,b,c,d,e,f) as arguments.
Therefore, from your example,
<g transform="matrix(0.443,0.896,-0.896,0.443,589.739,-373.223)">
we have the following transformation matrix params:
a=0.443
b=0.896
c=-0.896
d=0.443
e=589.739
f=-373.223
Now, if we have the following example coordinate: x=27, y=-9, we can transform it, by using the previously defined transformation matrix like this:
x' = a*x + c*y + e
x' = 0.443*27 + -0.896*-9 + 589.739
x' = 609.764
y' = b*x + d*y + f
y' = 0.896*27 + 0.443*-9 -373.223
y' = −353.018
Neat, huh? You can get more info here
But that is not all. We also need to understand svg path data.
According to the w3c svg path dspecification each letter in the path data represents an instruction. And each of the number pairs that follow an instruction represent a coordinate value.
From your example, we have the following path:
<path d="M486,313s27-9,43-29l26,4,1,23-22,5s-25-6-48-3z" />
Here we see that this path object uses one absolute moveto instruction (uppercase M), a relative smooth curveto cubic Bézier curve (lowercase s), a relative lineto instruction (lowercase l), and another relative smooth curveto cubic Bézier curve instruction, followed by a closepath instruction (lowercase z).
M486,313 is translated to absolute moveto x=486, y=313
s27-9,43-29 is a bit more complicated to read because some comas are omitted because they're not needed if the negative number is negative, so the minus sign acts as a coma - anyways, it translates to relative smooth bezier curveto x=27, y=-9, x=43, y=-29 (one destination point and one control point)
And so on.
So, how do we apply and remove the transformation matrix from your svg group? Like so:
// we read the transformation matrix params
// <g transform="matrix(0.443,0.896,-0.896,0.443,589.739,-373.223)">
a=0.443
b=0.896
c=-0.896
d=0.443
e=589.739
f=-373.223
// we read the path data, and transform each instruction
// <path d="M486,313s27-9,43-29l26,4,1,23-22,5s-25-6-48-3z" />
M486,313 Absolute move to
x' = a*x + c*y + e = a*486 + c*313 + e = 524.589
y' = b*x + d*y + f = b*486 + d*313 + f = 200.892
Move to instruction is now M524.589,200.892
S27-9,43-29 - smooth curveto, repeat the same process for each coordinate, but set the e and f (translation parameters) to 0, since it's a relative instruction not an absolute.
It is now
s20.025,20.205,45.033,25.680999999999997
l26,4,1,23-22,5
will become
l7.934000000000001,25.067999999999998,-20.165,11.085,-14.226,-17.497
s-25-6-48-3
will become
s-5.698999999999999,-25.058000000000003,-18.576,-44.337
And z will remain z
So the resulting transformed path will be:
<path d="M524.589,200.892s20.025,20.205,45.033,25.680999999999997l7.934000000000001,25.067999999999998,-20.165,11.085,-14.226,-17.497s-5.698999999999999,-25.058000000000003,-18.576,-44.337z" />
I hope this makes sense to you.
You can bake the coords selecting the path then using Path -> Union (CTRL++).
Hope this helps
Paste In Place can help you:
Double click the group in Inkscape, to enter it.
Select all the contents of the group by pressing Ctrl+A, and copy them with Ctrl+C.
Double click outside the group to leave the group.
Edit > Paste In Place (Ctrl+Alt+V) – at this point, group transformations are applied to the obects you paste.
Group the objects again (Ctrl+G)
Move the new group to the same depth as the original, and delete the original group. (This is probably easier with the XML editor, Ctrl+Shift+X.)
Following the answer of #andraaspar, you can also try ungrouping (Ctrl-U) and grouping again (Ctrl-G). It worked for me.
Thanks ArtBIT for all the info ! I had some issues about this on a PHP app, and wrote a library that manipulates font data (from SVG file) and does any sort of transformation on it. Anyone else interested may give it a try from the GitHub :
https://github.com/kartsims/easysvg
Usage example :
require 'easySVG.php';
$svg = new EasySVG();
$svg->setFont("paris-bold-webfont.svg", 100, "#000000");
$svg->addText("Simple text display");
$svg->addAttribute("width", "800px");
$svg->addAttribute("height", "100px");
echo $svg->asXML();
SVG data manipulation example :
$def = 'YOUR SVG DEFINITION HERE';
$easySVG = new EasySVG();
// rotate by 40°
$rotated_def = $easySVG->defRotate($def, 40)
// rotate by 40° with center at (200,100)
$rotated_def2 = $easySVG->defRotate($def, 40, 200, 100)
// scale transform : width*4
$scaled_def = $easySVG->defScale($def, 4)
I'd like to know exactly how this line of code works
corners = (m==n)&(n>threshold);
It's in a piece of code I'm using and I want to understand it. Basically, m and n are both equal-sized images, and "threshold" is a decimal value.
To understand the context, a segment of the code is below.
% compute the m cornerness measure
m = (ix2s.*iy2s - ixys.^2) - 0.04*(ix2s+iy2s).^2;
% perform non-maximal suppression using ordfilt2
n = ordfilt2(m, radius^2, ones([radius radius]));
% display corner spots
corners = (m==n)&(n>threshold);
% superimpose corners
Q = corners+im;
Q(Q>1) = 1;
C = repmat(im,[1 1 3]);
C(:,:,1) = Q;
If I understand correctly, n is the max of m ("cornerness measure") for the vicinity, so the line means - "if m is the local maximum and large enough(larger than threshold), then this is probably a corner", it could have arguably been more readable as:
corners = (m==n)&(m>threshold);
You should read more about Harris corner detector. Taken from Wikipedia:
This line is implementation of the function mentioned above. It is used to detect corners.
I have a quadratic bezier curve described as (startX, startY) to (anchorX, anchorY) and using a control point (controlX, controlY).
I have two questions:
(1) I want to determine y points on that curve based on an x point.
(2) Then, given a line-segment on my bezier (defined by two intermediary points on my bezier curve (startX', startY', anchorX', anchorY')), I want to know the control point for that line-segment so that it overlaps the original bezier exactly.
Why? I want this information for an optimization. I am drawing lots of horizontal beziers. When the beziers are larger than the screen, performance suffers because the rendering engine ends up rendering beyond the extents of what is visible. The answers to this question will let me just render what is visible.
Part 1
The formula for a quadratic Bezier is:
B(t) = a(1-t)2 + 2bt(1-t) + ct2
= a(1-2t+t2) + 2bt - 2bt2 + ct2
= (a-2b+c)t2+2(b-a)t + a
where bold indicates a vector. With Bx(t) given, we have:
x = (ax-2bx+cx)t2+2(bx-ax)t + ax
where vx is the x component of v.
According to the quadratic formula,
-2(bx-ax) ± 2√((bx-ax)2 - ax(ax-2bx+cx))
t = -----------------------------------------
2(ax-2bx+cx)
ax-bx ± √(bx2 - axcx)
= ----------------------
ax-2bx+cx
Assuming a solution exists, plug that t back into the original equation to get the other components of B(t) at a given x.
Part 2
Rather than producing a second Bezier curve that coincides with part of the first (I don't feel like crunching symbols right now), you can simply limit the domain of your parametric parameter to a proper sub-interval of [0,1]. That is, use part 1 to find the values of t for two different values of x; call these t-values i and j. Draw B(t) for t ∈ [i,j]. Equivalently, draw B(t(j-i)+i) for t ∈ [0,1].
The t equation is wrong, you need to use eq(1)
(1) x = (ax-2bx+cx)t2+2(bx-ax)t + ax
and solve it using the the quadratic formula for the roots (2).
-b ± √(b^2 - 4ac)
(2) x = -----------------
2a
Where
a = ax-2bx+cx
b = 2(bx-ax)
c = ax - x