OpenCV Q&A Forum - RSS feedhttp://answers.opencv.org/questions/OpenCV answersenCopyright <a href="http://www.opencv.org">OpenCV foundation</a>, 2012-2018.Sun, 24 Jun 2018 22:01:13 -0500Sine or Cosine of every element in Mat (c++)http://answers.opencv.org/question/55602/sine-or-cosine-of-every-element-in-mat-c/I was wondering if there is any way to take the sine or cosine of every element in a matrix?
Thanks!
EDIT: For future reference, I did the Taylor expansion of Sine. For pretty good accuracy, I only had to calculate up to the fourth term. However, keep note that if you are trying to estimate sin(pi) or sin(-pi) you have to calculate additional terms (probably 8 total terms).
This link will be useful for those who want to do this:
http://en.wikipedia.org/wiki/Taylor_series#Approximation_and_convergence
Wed, 18 Feb 2015 09:53:49 -0600http://answers.opencv.org/question/55602/sine-or-cosine-of-every-element-in-mat-c/Comment by Guyygarty for <p>I was wondering if there is any way to take the sine or cosine of every element in a matrix? </p>
<p>Thanks!</p>
<p>EDIT: For future reference, I did the Taylor expansion of Sine. For pretty good accuracy, I only had to calculate up to the fourth term. However, keep note that if you are trying to estimate sin(pi) or sin(-pi) you have to calculate additional terms (probably 8 total terms).</p>
<p>This link will be useful for those who want to do this:
<a href="http://en.wikipedia.org/wiki/Taylor_series#Approximation_and_convergence">http://en.wikipedia.org/wiki/Taylor_s...</a></p>
http://answers.opencv.org/question/55602/sine-or-cosine-of-every-element-in-mat-c/?comment=55756#post-id-55756Actually, you only need to go from -pi/4 to pi/4. For angles between pi/4 and pi/2, you can use the series for cos, substituting (pi/2-x) for your angle. Angles outside this range can be translated into it.Fri, 20 Feb 2015 05:52:23 -0600http://answers.opencv.org/question/55602/sine-or-cosine-of-every-element-in-mat-c/?comment=55756#post-id-55756Answer by Guyygarty for <p>I was wondering if there is any way to take the sine or cosine of every element in a matrix? </p>
<p>Thanks!</p>
<p>EDIT: For future reference, I did the Taylor expansion of Sine. For pretty good accuracy, I only had to calculate up to the fourth term. However, keep note that if you are trying to estimate sin(pi) or sin(-pi) you have to calculate additional terms (probably 8 total terms).</p>
<p>This link will be useful for those who want to do this:
<a href="http://en.wikipedia.org/wiki/Taylor_series#Approximation_and_convergence">http://en.wikipedia.org/wiki/Taylor_s...</a></p>
http://answers.opencv.org/question/55602/sine-or-cosine-of-every-element-in-mat-c/?answer=55679#post-id-55679How precise do you need it?
You can get within a few percent with a third order polynomial.
You need to:
1) transfer all matrix values to the range -pi/2 to pi/2 by adding whole multiples of pi. (I assume matrix values are in radians, if they are in degrees multiply by pi/180).
2) calculate Sin(x)=x-(x^3)/6
3) for Cosine calculate Sin(pi/2-x)
if you want better precision you can use higher order polynomials:
sin(x) is exactly the infinite polynomial x-(x^3/3!)+(x^5/5!)-(x^7/7!) +.... (look up "Taylor series" for more info)
but the accuracy increases pretty fast as you add terms.
I have not tried it, but I guarantee that this would be faster than an element by element sin function (which is probably implemented by a polynomial approximation anyway).
guy Thu, 19 Feb 2015 08:11:15 -0600http://answers.opencv.org/question/55602/sine-or-cosine-of-every-element-in-mat-c/?answer=55679#post-id-55679Comment by houmengmeng for <p>How precise do you need it?</p>
<p>You can get within a few percent with a third order polynomial.
You need to:</p>
<p>1) transfer all matrix values to the range -pi/2 to pi/2 by adding whole multiples of pi. (I assume matrix values are in radians, if they are in degrees multiply by pi/180).</p>
<p>2) calculate Sin(x)=x-(x^3)/6 </p>
<p>3) for Cosine calculate Sin(pi/2-x)</p>
<p>if you want better precision you can use higher order polynomials:
sin(x) is exactly the infinite polynomial x-(x^3/3!)+(x^5/5!)-(x^7/7!) +.... (look up "Taylor series" for more info)
but the accuracy increases pretty fast as you add terms. </p>
<p>I have not tried it, but I guarantee that this would be faster than an element by element sin function (which is probably implemented by a polynomial approximation anyway).</p>
<p>guy </p>
http://answers.opencv.org/question/55602/sine-or-cosine-of-every-element-in-mat-c/?comment=194450#post-id-194450Excuse me . Can I know how to do the first step without any for loop (element by element)?Sun, 24 Jun 2018 22:01:13 -0500http://answers.opencv.org/question/55602/sine-or-cosine-of-every-element-in-mat-c/?comment=194450#post-id-194450Comment by StevenPuttemans for <p>How precise do you need it?</p>
<p>You can get within a few percent with a third order polynomial.
You need to:</p>
<p>1) transfer all matrix values to the range -pi/2 to pi/2 by adding whole multiples of pi. (I assume matrix values are in radians, if they are in degrees multiply by pi/180).</p>
<p>2) calculate Sin(x)=x-(x^3)/6 </p>
<p>3) for Cosine calculate Sin(pi/2-x)</p>
<p>if you want better precision you can use higher order polynomials:
sin(x) is exactly the infinite polynomial x-(x^3/3!)+(x^5/5!)-(x^7/7!) +.... (look up "Taylor series" for more info)
but the accuracy increases pretty fast as you add terms. </p>
<p>I have not tried it, but I guarantee that this would be faster than an element by element sin function (which is probably implemented by a polynomial approximation anyway).</p>
<p>guy </p>
http://answers.opencv.org/question/55602/sine-or-cosine-of-every-element-in-mat-c/?comment=55729#post-id-55729Could you simply except the question instead of closing it down? We do not close quality solved questions :)Fri, 20 Feb 2015 02:08:34 -0600http://answers.opencv.org/question/55602/sine-or-cosine-of-every-element-in-mat-c/?comment=55729#post-id-55729Comment by TrustMeImAnEngineer for <p>How precise do you need it?</p>
<p>You can get within a few percent with a third order polynomial.
You need to:</p>
<p>1) transfer all matrix values to the range -pi/2 to pi/2 by adding whole multiples of pi. (I assume matrix values are in radians, if they are in degrees multiply by pi/180).</p>
<p>2) calculate Sin(x)=x-(x^3)/6 </p>
<p>3) for Cosine calculate Sin(pi/2-x)</p>
<p>if you want better precision you can use higher order polynomials:
sin(x) is exactly the infinite polynomial x-(x^3/3!)+(x^5/5!)-(x^7/7!) +.... (look up "Taylor series" for more info)
but the accuracy increases pretty fast as you add terms. </p>
<p>I have not tried it, but I guarantee that this would be faster than an element by element sin function (which is probably implemented by a polynomial approximation anyway).</p>
<p>guy </p>
http://answers.opencv.org/question/55602/sine-or-cosine-of-every-element-in-mat-c/?comment=55789#post-id-55789^^Sorry, I didn't know -.- I will make sure to keep it open!Fri, 20 Feb 2015 11:35:31 -0600http://answers.opencv.org/question/55602/sine-or-cosine-of-every-element-in-mat-c/?comment=55789#post-id-55789Comment by TrustMeImAnEngineer for <p>How precise do you need it?</p>
<p>You can get within a few percent with a third order polynomial.
You need to:</p>
<p>1) transfer all matrix values to the range -pi/2 to pi/2 by adding whole multiples of pi. (I assume matrix values are in radians, if they are in degrees multiply by pi/180).</p>
<p>2) calculate Sin(x)=x-(x^3)/6 </p>
<p>3) for Cosine calculate Sin(pi/2-x)</p>
<p>if you want better precision you can use higher order polynomials:
sin(x) is exactly the infinite polynomial x-(x^3/3!)+(x^5/5!)-(x^7/7!) +.... (look up "Taylor series" for more info)
but the accuracy increases pretty fast as you add terms. </p>
<p>I have not tried it, but I guarantee that this would be faster than an element by element sin function (which is probably implemented by a polynomial approximation anyway).</p>
<p>guy </p>
http://answers.opencv.org/question/55602/sine-or-cosine-of-every-element-in-mat-c/?comment=55697#post-id-55697That's exactly what I ended up doing! Thanks (: +1Thu, 19 Feb 2015 09:58:50 -0600http://answers.opencv.org/question/55602/sine-or-cosine-of-every-element-in-mat-c/?comment=55697#post-id-55697Answer by StevenPuttemans for <p>I was wondering if there is any way to take the sine or cosine of every element in a matrix? </p>
<p>Thanks!</p>
<p>EDIT: For future reference, I did the Taylor expansion of Sine. For pretty good accuracy, I only had to calculate up to the fourth term. However, keep note that if you are trying to estimate sin(pi) or sin(-pi) you have to calculate additional terms (probably 8 total terms).</p>
<p>This link will be useful for those who want to do this:
<a href="http://en.wikipedia.org/wiki/Taylor_series#Approximation_and_convergence">http://en.wikipedia.org/wiki/Taylor_s...</a></p>
http://answers.opencv.org/question/55602/sine-or-cosine-of-every-element-in-mat-c/?answer=55678#post-id-55678This should be the fastest way of retrieving Mat elements
Size contSize = mat.size();
if (mat.isContinous())
{
contSize.width *= contSize.height;
contSize.height = 1;
}
for (int i = 0; i < contSize.height; ++i)
{
T* ptr = mat.ptr<T>(y);
for (int j = 0; j < contSize.width; ++j)
{
ptr[j] = ...;
}
}
according to one of the core developers of OpenCV posted in [this topic](http://answers.opencv.org/question/22115/best-way-to-apply-a-function-to-each-element-of-mat/). Then inside the loop, do apply a sine or cosine on the value based on standard C++ functionality.Thu, 19 Feb 2015 07:59:16 -0600http://answers.opencv.org/question/55602/sine-or-cosine-of-every-element-in-mat-c/?answer=55678#post-id-55678Answer by Guanta for <p>I was wondering if there is any way to take the sine or cosine of every element in a matrix? </p>
<p>Thanks!</p>
<p>EDIT: For future reference, I did the Taylor expansion of Sine. For pretty good accuracy, I only had to calculate up to the fourth term. However, keep note that if you are trying to estimate sin(pi) or sin(-pi) you have to calculate additional terms (probably 8 total terms).</p>
<p>This link will be useful for those who want to do this:
<a href="http://en.wikipedia.org/wiki/Taylor_series#Approximation_and_convergence">http://en.wikipedia.org/wiki/Taylor_s...</a></p>
http://answers.opencv.org/question/55602/sine-or-cosine-of-every-element-in-mat-c/?answer=55632#post-id-55632I haven't found such a function in the API, so I guess you need to loop over the Matrix yourself.Thu, 19 Feb 2015 03:00:38 -0600http://answers.opencv.org/question/55602/sine-or-cosine-of-every-element-in-mat-c/?answer=55632#post-id-55632Answer by berak for <p>I was wondering if there is any way to take the sine or cosine of every element in a matrix? </p>
<p>Thanks!</p>
<p>EDIT: For future reference, I did the Taylor expansion of Sine. For pretty good accuracy, I only had to calculate up to the fourth term. However, keep note that if you are trying to estimate sin(pi) or sin(-pi) you have to calculate additional terms (probably 8 total terms).</p>
<p>This link will be useful for those who want to do this:
<a href="http://en.wikipedia.org/wiki/Taylor_series#Approximation_and_convergence">http://en.wikipedia.org/wiki/Taylor_s...</a></p>
http://answers.opencv.org/question/55602/sine-or-cosine-of-every-element-in-mat-c/?answer=55699#post-id-55699late to the party, but found this on my box (basically stolen/slaughtered from sse_mathfun.h):
#define HAVE_SSE2
#ifdef HAVE_SSE2
void sincos_ps(__m128 x, __m128 *s, __m128 *c)
{
static const __m128i _1i = _mm_set1_epi32(1);
static const __m128i _2i = _mm_set1_epi32(2);
static const __m128i _4i = _mm_set1_epi32(4);
static const __m128i _inv1i = _mm_set1_epi32(0xFFFFFFFE);
static const __m128 _1 = _mm_set_ps1(1.0f);
static const __m128 _0p5 = _mm_set_ps1(0.5f);
static const __m128 _DP1 = _mm_set_ps1(-0.78515625f);
static const __m128 _DP2 = _mm_set_ps1(-2.4187564849853515625e-4f);
static const __m128 _DP3 = _mm_set_ps1(-3.77489497744594108e-8f);
static const __m128 _sincof_p0 = _mm_set_ps1(-1.9515295891E-4f);
static const __m128 _sincof_p1 = _mm_set_ps1( 8.3321608736E-3f);
static const __m128 _sincof_p2 = _mm_set_ps1( -1.6666654611E-1f);
static const __m128 _coscof_p0 = _mm_set_ps1( 2.443315711809948E-005f);
static const __m128 _coscof_p1 = _mm_set_ps1(-1.388731625493765E-003f);
static const __m128 _coscof_p2 = _mm_set_ps1( 4.166664568298827E-002f);
static const __m128 _FOPI = _mm_set_ps1( 1.27323954473516f); // 4 / M_PI
static const __m128 _sign_mask = _mm_castsi128_ps(_mm_set1_epi32(0x80000000));
static const __m128 _inv_sign_mask = _mm_castsi128_ps(_mm_set1_epi32(~0x80000000));
__m128 sign_bit_sin = x;
// take the absolute value
x = _mm_and_ps(x, _inv_sign_mask);
// extract the sign bit (upper one)
sign_bit_sin = _mm_and_ps(sign_bit_sin, _sign_mask);
// scale by 4/Pi
__m128 y = _mm_mul_ps(x, _FOPI);
// store the integer part of y in emm2
__m128i emm2 = _mm_cvttps_epi32(y);
// j=(j+1) & (~1) (see the cephes sources)
emm2 = _mm_add_epi32(emm2, _1i);
emm2 = _mm_and_si128(emm2, _inv1i);
y = _mm_cvtepi32_ps(emm2);
__m128i emm4 = emm2;
// get the swap sign flag for the sine
__m128i emm0 = _mm_and_si128(emm2, _4i);
emm0 = _mm_slli_epi32(emm0, 29);
__m128 swap_sign_bit_sin = _mm_castsi128_ps(emm0);
// get the polynom selection mask for the sine
emm2 = _mm_and_si128(emm2, _2i);
emm2 = _mm_cmpeq_epi32(emm2, _mm_setzero_si128());
__m128 poly_mask = _mm_castsi128_ps(emm2);
// The magic pass: "Extended precision modular arithmetic"
// x = ((x - y * DP1) - y * DP2) - y * DP3;
__m128 xmm1 = _DP1;
__m128 xmm2 = _DP2;
__m128 xmm3 = _DP3;
xmm1 = _mm_mul_ps(y, xmm1);
xmm2 = _mm_mul_ps(y, xmm2);
xmm3 = _mm_mul_ps(y, xmm3);
x = _mm_add_ps(x, xmm1);
x = _mm_add_ps(x, xmm2);
x = _mm_add_ps(x, xmm3);
emm4 = _mm_sub_epi32(emm4, _2i);
emm4 = _mm_andnot_si128(emm4, _4i);
emm4 = _mm_slli_epi32(emm4, 29);
__m128 sign_bit_cos = _mm_castsi128_ps(emm4);
sign_bit_sin = _mm_xor_ps(sign_bit_sin, swap_sign_bit_sin);
// Evaluate the first polynom (0 <= x <= Pi/4)
__m128 z = _mm_mul_ps(x,x);
y = _coscof_p0;
y = _mm_mul_ps(y, z);
y = _mm_add_ps(y, _coscof_p1);
y = _mm_mul_ps(y, z);
y = _mm_add_ps(y, _coscof_p2);
y = _mm_mul_ps(y, z);
y = _mm_mul_ps(y, z);
__m128 tmp = _mm_mul_ps(z, _0p5);
y = _mm_sub_ps(y, tmp);
y = _mm_add_ps(y, _1);
// Evaluate the second polynom (Pi/4 <= x <= 0)
__m128 y2 = _sincof_p0;
y2 = _mm_mul_ps(y2, z);
y2 = _mm_add_ps(y2, _sincof_p1);
y2 = _mm_mul_ps(y2, z);
y2 = _mm_add_ps(y2, _sincof_p2);
y2 = _mm_mul_ps(y2, z);
y2 = _mm_mul_ps(y2, x);
y2 = _mm_add_ps(y2, x);
// select the correct result from the two polynoms
xmm3 = poly_mask;
__m128 ysin2 = _mm_and_ps(xmm3, y2);
__m128 ysin1 = _mm_andnot_ps(xmm3, y);
y2 = _mm_sub_ps(y2,ysin2);
y = _mm_sub_ps(y, ysin1);
xmm1 = _mm_add_ps(ysin1,ysin2);
xmm2 = _mm_add_ps(y,y2);
// update the sign
*s = _mm_xor_ps(xmm1, sign_bit_sin);
*c = _mm_xor_ps(xmm2, sign_bit_cos);
}
#endif // HAVE_SSE2
void sin(const Mat &in, Mat &out)
{
CV_Assert(in.depth()==CV_32F);
if ( out.empty() ) out.create(in.size(),in.type());
int len = in.total() * in.channels();
const float * pi = in.ptr<float>();
float * po = out.ptr<float>();
#ifdef HAVE_SSE2
__m128* mpi = (__m128*)pi;
__m128* mpo = (__m128*)po;
__m128 dummy;
#endif
int i=0;
for ( ; i<len-4; i+=4)
{
#ifdef HAVE_SSE2
sincos_ps(*mpi, mpo, &dummy);
mpi++; mpo++;
#else
po[i] = sin(pi[i]);
po[i+1] = sin(pi[i+1]);
po[i+2] = sin(pi[i+2]);
po[i+3] = sin(pi[i+3]);
#endif
}
for (; i<len; i++)
{
po[i] = sin(pi[i]);
}
}
void cos(const Mat &in, Mat &out)
{
CV_Assert(in.depth()==CV_32F);
if ( out.empty() ) out.create(in.size(),in.type());
int len = in.total() * in.channels();
const float * pi = in.ptr<float>();
float * po = out.ptr<float>();
#ifdef HAVE_SSE2
__m128* mpi = (__m128*)pi;
__m128* mpo = (__m128*)po;
__m128 dummy;
#endif
int i=0;
for ( ; i<len-4; i+=4)
{
#ifdef HAVE_SSE2
sincos_ps(*mpi, &dummy, mpo);
mpi++; mpo++;
#else
po[i] = cos(pi[i]);
po[i+1] = cos(pi[i+1]);
po[i+2] = cos(pi[i+2]);
po[i+3] = cos(pi[i+3]);
#endif
}
for (; i<len; i++)
{
po[i] = cos(pi[i]);
}
}
int main()
{
Mat m(100,100,CV_32FC3);
randu(m,Scalar::all(0),Scalar::all(1));
Mat m2;
uint64 t0 = getTickCount();
for (int i=0; i<10000; i++)
sin(m,m2);
uint64 t1 = getTickCount();
cerr << m2(Rect(0,0,4,4)) << endl;;
cerr << (t1-t0) << endl;
return 0;
}
-----------------------------------
sse on:
-----------------------------------
[0.5057773, 0.19794324, 0.39039394, 0.72730374, 0.42334378, 0.24623111, 0.698361
04, 0.69043756, 0.3029575, 0.64607561, 0.4604013, 0.71189302;
0.48940334, 0.032730069, 0.73478019, 0.2095844, 0.20382607, 0.14666511, 0.67213
07, 0.0021929722, 0.77308828, 0.48874435, 0.82448798, 0.022602571;
0.77302516, 0.70447648, 0.66355276, 0.3589724, 0.33083773, 0.46593088, 0.445949
79, 0.79249609, 0.26550364, 0.37933317, 0.76124775, 0.49633944;
0.2248047, 0.68306774, 0.27347186, 0.027689315, 0.74556303, 0.63638783, 0.70247
662, 0.3486445, 0.81542665, 0.709728, 0.82924271, 0.44006035]
12165392878
-----------------------------------
sse off:
-----------------------------------
[0.5057773, 0.19794324, 0.39039394, 0.72730368, 0.42334378, 0.24623111, 0.698361
04, 0.69043756, 0.3029575, 0.64607561, 0.4604013, 0.71189302;
0.48940334, 0.032730069, 0.73478019, 0.2095844, 0.20382607, 0.14666511, 0.67213
07, 0.0021929722, 0.77308828, 0.48874435, 0.82448798, 0.022602571;
0.77302516, 0.70447648, 0.66355276, 0.3589724, 0.33083773, 0.46593088, 0.445949
82, 0.79249603, 0.26550364, 0.37933317, 0.76124775, 0.49633944;
0.2248047, 0.68306774, 0.27347186, 0.027689315, 0.74556297, 0.63638788, 0.70247
662, 0.3486445, 0.81542665, 0.70972794, 0.82924277, 0.44006035]
27841527621
Thu, 19 Feb 2015 10:54:12 -0600http://answers.opencv.org/question/55602/sine-or-cosine-of-every-element-in-mat-c/?answer=55699#post-id-55699