You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

117 lines
3.8 KiB

/** @file */
/* The MIT License
*
* Copyright (c) 2008, Naotoshi Seo <sonots(at)sonots.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CV_ANGLEMEAN_INCLUDED
#define CV_ANGLEMEAN_INCLUDED
#include "cv.h"
#include "cvaux.h"
#include "cxcore.h"
#include <float.h>
#define _USE_MATH_DEFINES
#include <math.h>
/**
* Compute mean of angle elements of an array (each channel independently).
*
* There is a fact that 0 degrees and 360 degrees are identical angles,
* so that for example 180 degrees is not a sensible mean of 2 degrees and
* 358 degrees, but 0 degree is the mean.
* Algorithm works as 1. compute means of cosine and sine
* 2. take arc tangent of the mean consine and sine.
*
* @param arr array
* @param weight Weight to compute mean. The deafult is 1/num (uniform).
* The size must be same with arr.
* @param wrap The unit of wrapping around.
* The defeault is 360 as angle.
* @return angle mean for each channel
*/
CVAPI(CvScalar) cvAngleMean( const CvArr *arr,
const CvArr *weight CV_DEFAULT(NULL),
double wrap CV_DEFAULT(360) )
{
CvMat* mat, matstub;
CvMat* wmat = NULL, wmatstub;
CvScalar mean = cvScalar(0,0,0,0);
int row, col, ch;
int nChannels;
CvScalar elem;
CvScalar mean_cos = cvScalar(0,0,0,0);
CvScalar mean_sin = cvScalar(0,0,0,0);
CvScalar welem;
CV_FUNCNAME( "cvAngleMean" );
__CV_BEGIN__;
mat = (CvMat*)arr;
if( !CV_IS_MAT(mat) )
{
CV_CALL( mat = cvGetMat( mat, &matstub ) );
}
if( weight != NULL )
{
wmat = (CvMat*)weight;
if( !CV_IS_MAT(wmat) )
{
CV_CALL( wmat = cvGetMat( wmat, &wmatstub ) );
}
CV_ASSERT(
mat->rows == wmat->rows &&
mat->cols == wmat->cols &&
CV_MAT_CN(mat->type) == CV_MAT_CN(wmat->type)
);
}
nChannels = CV_MAT_CN(mat->type);
if( wmat == NULL ) // uniform
{
double w = 1.0 / (double)mat->rows * (double)mat->cols;
welem = cvScalar( w, w, w, w );
}
for( row = 0; row < mat->rows; row++ )
{
for( col = 0; col < mat->cols; col++ )
{
elem = cvGet2D( mat, row, col );
if( wmat != NULL ) welem = cvGet2D( wmat, row, col );
for( ch = 0; ch < nChannels; ch++ )
{
mean_cos.val[ch] +=
cos( elem.val[ch] * 2*M_PI / wrap ) * welem.val[ch];
mean_sin.val[ch] +=
sin( elem.val[ch] * 2*M_PI / wrap ) * welem.val[ch];
}
}
}
for( ch = 0; ch < nChannels; ch++ )
{
mean.val[ch] =
atan( mean_sin.val[ch] / mean_cos.val[ch] ) * wrap / (2*M_PI);
}
__CV_END__;
return mean;
}
#endif