/**
* @file core_reduce.cpp
* @brief It demonstrates the usage of cv::reduce .
*
* It shows how to compute the row sum, column sum, row average,
* column average, row minimum, column minimum, row maximum
* and column maximum of a cv::Mat.
*
* @author KUANG Fangjun
* @date August 2017
*/
#include <iostream>
#include <opencv2/core.hpp>
using namespace std;
using namespace cv;
int main()
{
{
//! [example]
Mat m = (Mat_<uchar>(3,2) << 1,2,3,4,5,6);
Mat col_sum, row_sum;
reduce(m, col_sum, 0, REDUCE_SUM, CV_32F);
reduce(m, row_sum, 1, REDUCE_SUM, CV_32F);
/*
m =
[ 1, 2;
3, 4;
5, 6]
col_sum =
[9, 12]
row_sum =
[3;
7;
11]
*/
//! [example]
Mat col_average, row_average, col_min, col_max, row_min, row_max;
reduce(m, col_average, 0, REDUCE_AVG, CV_32F);
cout << "col_average =\n" << col_average << endl;
reduce(m, row_average, 1, REDUCE_AVG, CV_32F);
cout << "row_average =\n" << row_average << endl;
reduce(m, col_min, 0, REDUCE_MIN, CV_8U);
cout << "col_min =\n" << col_min << endl;
reduce(m, row_min, 1, REDUCE_MIN, CV_8U);
cout << "row_min =\n" << row_min << endl;
reduce(m, col_max, 0, REDUCE_MAX, CV_8U);
cout << "col_max =\n" << col_max << endl;
reduce(m, row_max, 1, REDUCE_MAX, CV_8U);
cout << "row_max =\n" << row_max << endl;
}
{
char d[] = {1,2,3,4,5,6};
Mat m(3, 1, CV_8UC2, d);
Mat col_sum_per_channel;
reduce(m, col_sum_per_channel, 0, REDUCE_SUM, CV_32F);
}
return 0;
}
matrix_operations.cpp文件
#define reduceSumR8u32s reduceR_<uchar, int, OpAdd<int> >
#define reduceSumR8u32f reduceR_<uchar, float, OpAdd<int> >
#define reduceSumR8u64f reduceR_<uchar, double,OpAdd<int> >
#define reduceSumR16u32f reduceR_<ushort,float, OpAdd<float> >
#define reduceSumR16u64f reduceR_<ushort,double,OpAdd<double> >
#define reduceSumR16s32f reduceR_<short, float, OpAdd<float> >
#define reduceSumR16s64f reduceR_<short, double,OpAdd<double> >
#define reduceSumR32f32f reduceR_<float, float, OpAdd<float> >
#define reduceSumR32f64f reduceR_<float, double,OpAdd<double> >
#define reduceSumR64f64f reduceR_<double,double,OpAdd<double> >
#define reduceSumC8u32s reduceC_<uchar, int, OpAdd<int> >
#define reduceSumC8u32f reduceC_<uchar, float, OpAdd<int> >
#define reduceSumC16u32f reduceC_<ushort,float, OpAdd<float> >
#define reduceSumC16s32f reduceC_<short, float, OpAdd<float> >
#define reduceSumC32f32f reduceC_<float, float, OpAdd<float> >
#define reduceSumC64f64f reduceC_<double,double,OpAdd<double> >
//reduce rows
template<typename T, typename ST, class Op> static void
reduceR_( const Mat& srcmat, Mat& dstmat )
{
typedef typename Op::rtype WT;
Size size = srcmat.size();
size.width *= srcmat.channels();
AutoBuffer<WT> buffer(size.width);
WT* buf = buffer.data();
ST* dst = dstmat.ptr<ST>();
const T* src = srcmat.ptr<T>();
size_t srcstep = srcmat.step/sizeof(src[0]);
int i;
Op op;
for( i = 0; i < size.width; i++ )
buf[i] = src[i];
for( ; --size.height; )
{
src += srcstep;
i = 0;
#if CV_ENABLE_UNROLLED
for(; i <= size.width - 4; i += 4 )
{
WT s0, s1;
s0 = op(buf[i], (WT)src[i]);
s1 = op(buf[i+1], (WT)src[i+1]);
buf[i] = s0; buf[i+1] = s1;
s0 = op(buf[i+2], (WT)src[i+2]);
s1 = op(buf[i+3], (WT)src[i+3]);
buf[i+2] = s0; buf[i+3] = s1;
}
#endif
for( ; i < size.width; i++ )
buf[i] = op(buf[i], (WT)src[i]);
}
for( i = 0; i < size.width; i++ )
dst[i] = (ST)buf[i];
}
//reduce cols
template<typename T, typename ST, class Op> static void
reduceC_( const Mat& srcmat, Mat& dstmat )
{
typedef typename Op::rtype WT;
Size size = srcmat.size();
int cn = srcmat.channels();
size.width *= cn;
Op op;
for( int y = 0; y < size.height; y++ )
{
const T* src = srcmat.ptr<T>(y);
ST* dst = dstmat.ptr<ST>(y);
if( size.width == cn )
for( int k = 0; k < cn; k++ )
dst[k] = src[k];
else
{
for( int k = 0; k < cn; k++ )
{
WT a0 = src[k], a1 = src[k+cn];
int i;
for( i = 2*cn; i <= size.width - 4*cn; i += 4*cn )
{
a0 = op(a0, (WT)src[i+k]);
a1 = op(a1, (WT)src[i+k+cn]);
a0 = op(a0, (WT)src[i+k+cn*2]);
a1 = op(a1, (WT)src[i+k+cn*3]);
}
for( ; i < size.width; i += cn )
{
a0 = op(a0, (WT)src[i+k]);
}
a0 = op(a0, a1);
dst[k] = (ST)a0;
}
}
}
}
void cv::reduce(InputArray _src, OutputArray _dst, int dim, int op, int dtype)
{
CV_INSTRUMENT_REGION();
CV_Assert( _src.dims() <= 2 );
int op0 = op;
int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype);
if( dtype < 0 )
dtype = _dst.fixedType() ? _dst.type() : stype;
dtype = CV_MAKETYPE(dtype >= 0 ? dtype : stype, cn);
int ddepth = CV_MAT_DEPTH(dtype);
CV_Assert( cn == CV_MAT_CN(dtype) );
CV_Assert( op == CV_REDUCE_SUM || op == CV_REDUCE_MAX ||
op == CV_REDUCE_MIN || op == CV_REDUCE_AVG );
CV_OCL_RUN(_dst.isUMat(),
ocl_reduce(_src, _dst, dim, op, op0, stype, dtype))
// Fake reference to source. Resolves issue 8693 in case of src == dst.
UMat srcUMat;
if (_src.isUMat())
srcUMat = _src.getUMat();
Mat src = _src.getMat();
_dst.create(dim == 0 ? 1 : src.rows, dim == 0 ? src.cols : 1, dtype);
Mat dst = _dst.getMat(), temp = dst;
if( op == CV_REDUCE_AVG )
{
op = CV_REDUCE_SUM;
if( sdepth < CV_32S && ddepth < CV_32S )
{
temp.create(dst.rows, dst.cols, CV_32SC(cn));
ddepth = CV_32S;
}
}
ReduceFunc func = 0;
if( dim == 0 )
{
if( op == CV_REDUCE_SUM )
{
if(sdepth == CV_8U && ddepth == CV_32S)
func = GET_OPTIMIZED(reduceSumR8u32s);
else if(sdepth == CV_8U && ddepth == CV_32F)
func = reduceSumR8u32f;
else if(sdepth == CV_8U && ddepth == CV_64F)
func = reduceSumR8u64f;
else if(sdepth == CV_16U && ddepth == CV_32F)
func = reduceSumR16u32f;
else if(sdepth == CV_16U && ddepth == CV_64F)
func = reduceSumR16u64f;
else if(sdepth == CV_16S && ddepth == CV_32F)
func = reduceSumR16s32f;
else if(sdepth == CV_16S && ddepth == CV_64F)
func = reduceSumR16s64f;
else if(sdepth == CV_32F && ddepth == CV_32F)
func = GET_OPTIMIZED(reduceSumR32f32f);
else if(sdepth == CV_32F && ddepth == CV_64F)
func = reduceSumR32f64f;
else if(sdepth == CV_64F && ddepth == CV_64F)
func = reduceSumR64f64f;
}
else if(op == CV_REDUCE_MAX)
{
if(sdepth == CV_8U && ddepth == CV_8U)
func = GET_OPTIMIZED(reduceMaxR8u);
else if(sdepth == CV_16U && ddepth == CV_16U)
func = reduceMaxR16u;
else if(sdepth == CV_16S && ddepth == CV_16S)
func = reduceMaxR16s;
else if(sdepth == CV_32F && ddepth == CV_32F)
func = GET_OPTIMIZED(reduceMaxR32f);
else if(sdepth == CV_64F && ddepth == CV_64F)
func = reduceMaxR64f;
}
else if(op == CV_REDUCE_MIN)
{
if(sdepth == CV_8U && ddepth == CV_8U)
func = GET_OPTIMIZED(reduceMinR8u);
else if(sdepth == CV_16U && ddepth == CV_16U)
func = reduceMinR16u;
else if(sdepth == CV_16S && ddepth == CV_16S)
func = reduceMinR16s;
else if(sdepth == CV_32F && ddepth == CV_32F)
func = GET_OPTIMIZED(reduceMinR32f);
else if(sdepth == CV_64F && ddepth == CV_64F)
func = reduceMinR64f;
}
}
else
{
if(op == CV_REDUCE_SUM)
{
if(sdepth == CV_8U && ddepth == CV_32S)
func = GET_OPTIMIZED(reduceSumC8u32s);
else if(sdepth == CV_8U && ddepth == CV_32F)
func = reduceSumC8u32f;
else if(sdepth == CV_8U && ddepth == CV_64F)
func = reduceSumC8u64f;
else if(sdepth == CV_16U && ddepth == CV_32F)
func = reduceSumC16u32f;
else if(sdepth == CV_16U && ddepth == CV_64F)
func = reduceSumC16u64f;
else if(sdepth == CV_16S && ddepth == CV_32F)
func = reduceSumC16s32f;
else if(sdepth == CV_16S && ddepth == CV_64F)
func = reduceSumC16s64f;
else if(sdepth == CV_32F && ddepth == CV_32F)
func = GET_OPTIMIZED(reduceSumC32f32f);
else if(sdepth == CV_32F && ddepth == CV_64F)
func = reduceSumC32f64f;
else if(sdepth == CV_64F && ddepth == CV_64F)
func = reduceSumC64f64f;
}
else if(op == CV_REDUCE_MAX)
{
if(sdepth == CV_8U && ddepth == CV_8U)
func = GET_OPTIMIZED(reduceMaxC8u);
else if(sdepth == CV_16U && ddepth == CV_16U)
func = reduceMaxC16u;
else if(sdepth == CV_16S && ddepth == CV_16S)
func = reduceMaxC16s;
else if(sdepth == CV_32F && ddepth == CV_32F)
func = GET_OPTIMIZED(reduceMaxC32f);
else if(sdepth == CV_64F && ddepth == CV_64F)
func = reduceMaxC64f;
}
else if(op == CV_REDUCE_MIN)
{
if(sdepth == CV_8U && ddepth == CV_8U)
func = GET_OPTIMIZED(reduceMinC8u);
else if(sdepth == CV_16U && ddepth == CV_16U)
func = reduceMinC16u;
else if(sdepth == CV_16S && ddepth == CV_16S)
func = reduceMinC16s;
else if(sdepth == CV_32F && ddepth == CV_32F)
func = GET_OPTIMIZED(reduceMinC32f);
else if(sdepth == CV_64F && ddepth == CV_64F)
func = reduceMinC64f;
}
}
if( !func )
CV_Error( CV_StsUnsupportedFormat,
"Unsupported combination of input and output array formats" );
func( src, temp );
if( op0 == CV_REDUCE_AVG )
temp.convertTo(dst, dst.type(), 1./(dim == 0 ? src.rows : src.cols));
}
https://github.com/opencv/opencv/blob/b39cd06249213220e802bb64260727711d9fc98c/samples/cpp/tutorial_code/snippets/core_reduce.cpp
https://github.com/opencv/opencv/blob/b39cd06249213220e802bb64260727711d9fc98c/modules/core/src/matrix_operations.cpp