mathematic range - simple question - iphone

I have a float number which represent percentage (0.0 to 100.0) %
float represent = 50.00; // fifty present, or half.
as an example: convert this number to a range from -2 to 2
thus:
represent=0 will be represented as -2
represent=50 will be represented as 0
represent=100 will be represented as 2
EDIT:
good simple answer from Orbling and friends, Still I am looking for something along the lines of : map(value, fromLow, fromHigh, toLow, toHigh)
Is there a function in objective C to map such range for more complex values?

represent = (represent / 25.0f) - 2.0f;

This should do the trick:
define map(v, r1, r2, t1, t2)
{
norm = (v-r1)/(r2-r1);
return (t1*(1-norm) + t2*norm);
}
Explanation:
norm is v scaled to a value between 0 and 1, related to r1 and r2.
Next line is calculates the point between t1 and t2 using norm as percentage factor.
Example usage:
map (0, 0, 100, -2, 2) // 0 mapped to -2..2 in the range 0..100
-2.0
map (50, 0, 100, -2, 2) // 50 mapped to -2..2 in the range 0..100
0
map (100, 0, 100, -2, 2) // 100 mapped to -2..2 in the range 0..100
2.0
map (-90, -100, 20, -4, 2) // -90 mapped to -4..2 in the range -100..20
-3.5

Related

Extrapolate Animation Curve (Endless game balancing curve)

I need a curve editor to make balancing of endless game then I tried to use AnimationCurve.
I need to set a curve to a certain range ex. [0;1] and if I want a value over 1, the result of the Evaluation have to extrapolate the curve. I want to be able to compute Y from X and X from Y.
The problem is AnimationCurve have only 3 WrapMode (Clamp, PingPong, Loop).
How to extrapolate an AnimationCurve ?
Is there a better tool to make curve with extrapolation (post and pre curve) ?
For real extrapolation I think you'd have to implement your own system based on Bézier mathematics. Me at least am not aware of unity providing it out of the box.
A work around for it could be to just define values beyond the 0 to 1 range to cover the extents, animation curves do allow this, I don't think there are to many issues with that.
Another solution, to stay in 0 to 1 range still but achieve the same effect, would be to model the curve from 0 to 1 so that it would cover extreme values within that range and remap the time for curve evaluation given by the object to a 0 to 1 range.
E.g.:
// define range extents
float rangeMin = -5f, rangeMax = 5f;
var range = 10f;
// range could be calculated at runtime if necessary:
// [to] (higher value) - [from] (lower value) = [range]
// 5f - -5f = 10f
var timeRaw = 0; // variable provided value
var time01 = (timeRaw - rangeMin) / range;
// reult by timeRaw = 0: (0 - -5) / 10 = 0.5
// reult by timeRaw = 5: (5 - -5) / 10 = 1.0
// reult by timeRaw = -5: (-5 - -5) / 10 = 0.0
Combining both solutions allow you to cover even more extreme values.

How to create Bezier curves from B-Splines in Sympy?

I need to draw a smooth curve through some points, which I then want to show as an SVG path. So I create a B-Spline with scipy.interpolate, and can access some arrays that I suppose fully define it. Does someone know a reasonably simple way to create Bezier curves from these arrays?
import numpy as np
from scipy import interpolate
x = np.array([-1, 0, 2])
y = np.array([ 0, 2, 0])
x = np.r_[x, x[0]]
y = np.r_[y, y[0]]
tck, u = interpolate.splprep([x, y], s=0, per=True)
cx = tck[1][0]
cy = tck[1][1]
print( 'knots: ', list(tck[0]) )
print( 'coefficients x: ', list(cx) )
print( 'coefficients y: ', list(cy) )
print( 'degree: ', tck[2] )
print( 'parameter: ', list(u) )
The red points are the 3 initial points in x and y. The green points are the 6 coefficients in cx and cy. (Their values repeat after the 3rd, so each green point has two green index numbers.)
Return values tck and u are described scipy.interpolate.splprep documentation
knots: [-1.0, -0.722, -0.372, 0.0, 0.277, 0.627, 1.0, 1.277, 1.627, 2.0]
# 0 1 2 3 4 5
coefficients x: [ 3.719, -2.137, -0.053, 3.719, -2.137, -0.053]
coefficients y: [-0.752, -0.930, 3.336, -0.752, -0.930, 3.336]
degree: 3
parameter: [0.0, 0.277, 0.627, 1.0]
Not sure starting with a B-Spline makes sense: form a catmull-rom curve through the points (with the virtual "before first" and "after last" overlaid on real points) and then convert that to a bezier curve using a relatively trivial transform? E.g. given your points p0, p1, and p2, the first segment would be a catmull-rom curve {p2,p0,p1,p2} for the segment p1--p2, {p0,p1,p2,p0} will yield p2--p0, and {p1, p2, p0, p1} will yield p0--p1. Then you trivially convert those and now you have your SVG path.
As demonstrator, hit up https://editor.p5js.org/ and paste in the following code:
var points = [{x:150, y:100 },{x:50, y:300 },{x:300, y:300 }];
// add virtual points:
points = points.concat(points);
function setup() {
createCanvas(400, 400);
tension = createSlider(1, 200, 100);
}
function draw() {
background(220);
points.forEach(p => ellipse(p.x, p.y, 4));
for (let n=0; n<3; n++) {
let [c1, c2, c3, c4] = points.slice(n,n+4);
let t = 0.06 * tension.value();
bezier(
// on-curve start point
c2.x, c2.y,
// control point 1
c2.x + (c3.x - c1.x)/t,
c2.y + (c3.y - c1.y)/t,
// control point 2
c3.x - (c4.x - c2.x)/t,
c3.y - (c4.y - c2.y)/t,
// on-curve end point
c3.x, c3.y
);
}
}
Which will look like this:
Converting that to Python code should be an almost effortless exercise: there is barely any code for us to write =)
And, of course, now you're left with creating the SVG path, but that's hardly an issue: you know all the Bezier points now, so just start building your <path d=...> string while you iterate.
A B-spline curve is just a collection of Bezier curves joined together. Therefore, it is certainly possible to convert it back to multiple Bezier curves without any loss of shape fidelity. The algorithm involved is called "knot insertion" and there are different ways to do this with the two most famous algorithm being Boehm's algorithm and Oslo algorithm. You can refer this link for more details.
Here is an almost direct answer to your question (but for the non-periodic case):
import aggdraw
import numpy as np
import scipy.interpolate as si
from PIL import Image
# from https://stackoverflow.com/a/35007804/2849934
def scipy_bspline(cv, degree=3):
""" cv: Array of control vertices
degree: Curve degree
"""
count = cv.shape[0]
degree = np.clip(degree, 1, count-1)
kv = np.clip(np.arange(count+degree+1)-degree, 0, count-degree)
max_param = count - (degree * (1-periodic))
spline = si.BSpline(kv, cv, degree)
return spline, max_param
# based on https://math.stackexchange.com/a/421572/396192
def bspline_to_bezier(cv):
cv_len = cv.shape[0]
assert cv_len >= 4, "Provide at least 4 control vertices"
spline, max_param = scipy_bspline(cv, degree=3)
for i in range(1, max_param):
spline = si.insert(i, spline, 2)
return spline.c[:3 * max_param + 1]
def draw_bezier(d, bezier):
path = aggdraw.Path()
path.moveto(*bezier[0])
for i in range(1, len(bezier) - 1, 3):
v1, v2, v = bezier[i:i+3]
path.curveto(*v1, *v2, *v)
d.path(path, aggdraw.Pen("black", 2))
cv = np.array([[ 40., 148.], [ 40., 48.],
[244., 24.], [160., 120.],
[240., 144.], [210., 260.],
[110., 250.]])
im = Image.fromarray(np.ones((400, 400, 3), dtype=np.uint8) * 255)
bezier = bspline_to_bezier(cv)
d = aggdraw.Draw(im)
draw_bezier(d, bezier)
d.flush()
# show/save im
I didn't look much into the periodic case, but hopefully it's not too difficult.

how to properly count the number of vehicles?

I have a circle of radius 10 m. I want to count the number of vehicles entering the circle it (the distance from the center car <= 10m)
I'm right . I can use the toolbar "Minitor" to count the number of vehicles currently in liquidation xe.nhung "minitor" much larger than the actual number of vehicles that pass through the circle. I attached the "minitor" by "total-cars".
how to properly count the number of vehicles?
ask cars
[
if distancexy 0 0 < 10
[
set total-cars (total-cars + 1)
]
]
I am not very sure about your question, but maybe this code could help you:
set total-cars count cars with [distancexy 0 0 <= 10]
You can use the following code in the monitor control directly:
count cars with [distancexy 0 0 <= 10]
import cv2
import time
bgsMOG = cv2.createBackgroundSubtractorMOG2(detectShadows=False)
kernal=cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3))
cap = cv2.VideoCapture(0)
counter =0
time.sleep(2)
if cap:
while True:
ret, frame = cap.read()
if ret:
#fgmask = bgsMOG.apply(frame, None, 0.01)
blur = cv2.GaussianBlur(frame, (5, 5), 0)
fgmask = bgsMOG.apply(blur)
morhpho = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernal)
#line for detection
cv2.line(frame,(20,270),(320,270),(175,175,0),5)
_,contours, hierarchy = cv2.findContours(morhpho,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
ax1=20 #coordinate of line where vehicle will be count if intersect
ay1=270
ax2=320
ay2=270
try: hierarchy = hierarchy[0]
except: hierarchy = []
#for contour, hier in zip(contours, hierarchy):
for (i, contour) in enumerate(contours):
(x,y,w,h) = cv2.boundingRect(contour)
if w > 20 and h > 25:
rec=cv2.rectangle(frame, (x,y), (x+w,y+h), (180, 0, 0), 1)
x1=w/2 #to find centroid
y1=h/2
cx=x+x1
cy=y+y1
centroid=(cx,cy)
M = cv2.moments(contour)
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
# draw the contour and center of the shape on the image
cv2.circle(frame, (cX, cY), 2, (255, 255, 255), -1)
cv2.circle(frame,(int(cx),int(cy)),1,(0,255,0),-1)
dy=cY-270 #my first code to increase counter
print("centroid",cX,":",cY)
if dy==0:
if (cX<=320)and(cX>=20):
counter=counter+1
print("1st ct",counter)
print len(contour)
#FileName = "D:/data/" + str(y) + ".jpg"
#cv2.imshow("cropped",rec)
#cv2.imwrite(FileName,rec)
if cy==270:
if centroid > (27, 268) and centroid < (325, 285):
if (cX <= 320) and (cX >= 20):
counter =counter+1
print "counter=", counter
if cY > 10 and cY < 250:
cv2.putText(frame, str(counter),(10,150),cv2.FONT_HERSHEY_SIMPLEX,2, (255, 0, 0), 1, True)
#cv2.resizeWindow('Output',320,180)
cv2.imshow('Output', frame)
cv2.imshow('mor', morhpho)
cv2.imshow('blur', blur)
#cv2.imshow('FGMASK', morhpho)
key = cv2.waitKey(1)
if key == ord('q'):
break
cap.release()
cv2.destroyAllWindows()

Matlab gradient equivalent in opencv

I am trying to migrate some code from Matlab to Opencv and need an exact replica of the gradient function. I have tried the cv::Sobel function but for some reason the values in the resulting cv::Mat are not the same as the values in the Matlab version. I need the X and Y gradient in separate matrices for further calculations.
Any workaround that could achieve this would be great
Sobel can only compute the second derivative of the image pixel which is not what we want.
(f(i+1,j) + f(i-1,j) - 2f(i,j)) / 2
What we want is
(f(i+i,j)-f(i-1,j)) / 2
So we need to apply
Mat kernelx = (Mat_<float>(1,3)<<-0.5, 0, 0.5);
Mat kernely = (Mat_<float>(3,1)<<-0.5, 0, 0.5);
filter2D(src, fx, -1, kernelx)
filter2D(src, fy, -1, kernely);
Matlab treats border pixels differently from inner pixels. So the code above is wrong at the border values. One can use BORDER_CONSTANT to extent the border value out with a constant number, unfortunately the constant number is -1 by OpenCV and can not be changed to 0 (which is what we want).
So as to border values, I do not have a very neat answer to it. Just try to compute the first derivative by hand...
You have to call Sobel 2 times, with arguments:
xorder = 1, yorder = 0
and
xorder = 0, yorder = 1
You have to select the appropriate kernel size.
See documentation
It might still be that the MatLab implementation was different, ideally you should retrieve which kernel was used there...
Edit:
If you need to specify your own kernel, you can use the more generic filter2D. Your destination depth will be CV_16S (16bit signed).
Matlab computes the gradient differently for interior rows and border rows (the same is true for the columns of course). At the borders, it is a simple forward difference gradY(1) = row(2) - row(1). The gradient for interior rows is computed by the central difference gradY(2) = (row(3) - row(1)) / 2.
I think you cannot achieve the same result with just running a single convolution filter over the whole matrix in OpenCV. Use cv::Sobel() with ksize = 1, then treat the borders (either manually or by applying a [ 1 -1 ] filter).
Pei's answer is partly correct. Matlab uses these calculations for the borders:
G(:,1) = A(:,2) - A(:,1);
G(:,N) = A(:,N) - A(:,N-1);
so used the following opencv code to complete the gradient:
static cv::Mat kernelx = (cv::Mat_<double>(1, 3) << -0.5, 0, 0.5);
static cv::Mat kernely = (cv::Mat_<double>(3, 1) << -0.5, 0, 0.5);
cv::Mat fx, fy;
cv::filter2D(Image, fx, -1, kernelx, cv::Point(-1, -1), 0, cv::BORDER_REPLICATE);
cv::filter2D(Image, fy, -1, kernely, cv::Point(-1, -1), 0, cv::BORDER_REPLICATE);
fx.col(fx.cols - 1) *= 2;
fx.col(0) *= 2;
fy.row(fy.rows - 1) *= 2;
fy.row(0) *= 2;
Jorrit's answer is partly correct.
In some cases, the value of the directional derivative may be negative, and MATLAB will retain these negative numbers, but OpenCV Mat will set the negative number to 0.

Program for specific sequence of Integers

I am solving steady state heat equation with the boundary condition varying like this 10,0,0,10,0,0,10,0,0,10,0,0,10.... and so on depending upon number of points i select.
I want to construct a matrix for these boundary conditions but unable to specify the logic for the sequence in terms of ith element for a matrix.
i am using mathematica for this however i need the formula only like for odd we can specify 2n+1 and for even 2n , something like this for the sequence 10,0,0,10,0,0,10,0,0,10,....
In MATLAB, it would be
M = zeros(1000, 1);
M(1:3:1000) = 10;
to make a 1000 long vector with such structure. 1:3:1000 is 1,4,7,....
Since you specifically want a mathematical formula let me suggest a method:
seq = PadRight[{}, 30, {10, 0, 0}];
func = FindSequenceFunction[seq]
10/3 (1 + Cos[2/3 \[Pi] (-1 + #1)] + Cos[4/3 \[Pi] (-1 + #1)]) &
Test it:
Array[func, 10]
{10, 0, 0, 10, 0, 0, 10, 0, 0, 10}
There are surely simpler programs to generate this sequence, such as:
Array[10 Boole[1 == Mod[#, 3]] &, 10]
{10, 0, 0, 10, 0, 0, 10, 0, 0, 10}
A way to do this in Mathematica:
Take[Flatten[ConstantArray[{10, 0, 0}, Ceiling[1000/3] ], 1],1000]
Another way
Table[Boole[Mod[i,3]==1]*10, {i,1,1000}]