OpenCV reduce 函数

44 篇文章 33 订阅

OpenCV reduce 函数

微信公众号:幼儿园的学霸
个人的学习笔记,关于OpenCV,关于机器学习, …。问题或建议,请公众号留言;

最近在对矩阵的每一列进行求和时,发现了一个函数cv::reduce(),该函数将我原本的的循环遍历操作代码量减少至了一行函数调用,故特此记录,望可对他人有一定启发作用。

目录

函数说明

函数原型(声明位于头文件:opencv2/core.hpp):

/** @brief Reduces a matrix to a vector.

The function #reduce reduces the matrix to a vector by treating the matrix rows/columns as a set of
1D vectors and performing the specified operation on the vectors until a single row/column is
obtained. For example, the function can be used to compute horizontal and vertical projections of a
raster image. In case of #REDUCE_MAX and #REDUCE_MIN , the output image should have the same type as the source one.
In case of #REDUCE_SUM and #REDUCE_AVG , the output may have a larger element bit-depth to preserve accuracy.
And multi-channel arrays are also supported in these two reduction modes.

The following code demonstrates its usage for a single channel matrix.
@snippet snippets/core_reduce.cpp example

And the following code demonstrates its usage for a two-channel matrix.
@snippet snippets/core_reduce.cpp example2

@param src input 2D matrix.
@param dst output vector. Its size and type is defined by dim and dtype parameters.
@param dim dimension index along which the matrix is reduced. 0 means that the matrix is reduced to
a single row. 1 means that the matrix is reduced to a single column.
@param rtype reduction operation that could be one of #ReduceTypes
@param dtype when negative, the output vector will have the same type as the input matrix,
otherwise, its type will be CV_MAKE_TYPE(CV_MAT_DEPTH(dtype), src.channels()).
@sa repeat
*/
CV_EXPORTS_W void reduce(InputArray src, OutputArray dst, int dim, int rtype, int dtype = -1);

该函数的作用是将二维数组转化为向量。
参数说明:
src:输入矩阵
dst:通过处理输入矩阵的所有行/列而得到的单行/列向量
dim:矩阵被简化后的维数索引.0意味着矩阵被处理成一行,1意味着矩阵被处理成为一列,-1时维数将根据输出向量的大小自动选择.
op:简化操作的方式,可以有以下几种取值:

op 取值输出操作结果
cv::REDUCE_SUM(or CV_REDUCE_SUM)输出是矩阵的所有行/列的和
cv::REDUCE_AVG(or CV_REDUCE_AVG)输出是矩阵的所有行/列的平均向量
cv::REDUCE_MAX(or CV_REDUCE_MAX)输出是矩阵的所有行/列的最大值
cv::REDUCE_MIN(or CV_REDUCE_MIN)输出是矩阵的所有行/列的最小值

注意reduce的输入与输出关系:

cv::reduce for SUM and 8U input can return only 32S, 32F or 64F types.

就是说输入如果是8U那么输出一定是32S, 32F or 64F其中一个。如果不在dtype设置,那么就默认输出的数据类型与输入类型一致。所以如果要输出32S类型的数据,就要在dtype进行设置!

换句话说,当输出矩阵所有行/列的和时,对该行/列数据进行累加,可能会超出矩阵类型的数据类型所表示的范围,因此此时需要指定输出矩阵的类型

代码示例

下面是一个简单的例子,可以理解cv::reduce()函数的作用。

//====================================================================//
// Created by liheng on 19-7-2.
//Program:reduce()函数
//Data:2019.7.2
//Author:liheng
//Version:V1.0
//====================================================================//

#include <opencv2/opencv.hpp>
#include <iostream>

int main()
{
    cv::Mat srcMat = (cv::Mat_<uchar >(3,3) <<
            225, 38, 22,
            67, 44, 12,
            89, 65, 63);

    std::cout<<"srcMat="<<std::endl;
    std::cout << srcMat << std::endl;

    cv::Mat output;

    //输出每列的最大值
    cv::reduce(srcMat, output, 0, cv::REDUCE_MAX);
    std::cout<<"Maximum value of each col:"<<std::endl;
    std::cout << output << std::endl;

    //输出每行的最小值
    cv::reduce(srcMat, output, 1, cv::REDUCE_MIN);
    std::cout<<"Minimum value of each row:"<<std::endl;
    std::cout << output << std::endl;

    //输出每列的均值
    cv::reduce(srcMat, output, 0, cv::REDUCE_AVG);
    std::cout<<"Average value of each col:"<<std::endl;
    std::cout << output << std::endl;

    //输出每列的和
    //Note:此时需要指定输出矩阵的类型,求和时,uchar值的和可能会超过其表示范围,所以需要显式指定类型
    cv::reduce(srcMat, output, 0, cv::REDUCE_SUM,CV_32SC1);
    std::cout<<"Summation value of each col:"<<std::endl;
    std::cout << output << std::endl;

    return 0;
}

代码输出:

srcMat=
[225,  38,  22;
  67,  44,  12;
  89,  65,  63]
Maximum value of each col:
[225,  65,  63]
Minimum value of each row:
[ 22;
  12;
  63]
Average value of each col:
[127,  49,  32]
Summation value of each col:
[381, 147, 97]

reduce()函数来说,在求矩阵每行每列的最大值时,也许minMaxLoc()函数更实用一些,该函数不仅返回函数的最值,同时也返回函数最值的位置。
另外一方面,该函数实现的功能,自己也可以通过简单的代码实现,但是这又何必呢,一行代码能够解决的问题,何必重复造轮子呢。

应用示例

以一幅二值化的图像为例,需要在其中检测车道线,其中的一个思路便是:车道线在图像中像素值为255,非车道线位置处的像素值为0,车道线所在的列,其和或者均值一定是最大的。因此可以统计图像每一列的和或者均值,判断车道线的大概位置所在。
代码如下:

int main()
{
    cv::Mat srcImage = cv::imread("../pictures/123.bmp",cv::IMREAD_GRAYSCALE);
    cv::Mat histImage;
    cv::reduce(srcImage,histImage,0,cv::REDUCE_AVG);

    cv::Mat histShowImage(srcImage.size(),CV_8UC3,cv::Scalar(0,0,0));
    for(int i=0; i<histShowImage.cols-1;++i)
    {
        cv::line(histShowImage,cv::Point(i,histImage.at<uchar >(0,i)),\
        cv::Point(i+1,histImage.at<uchar >(0,i+1)),cv::Scalar(0,0,255),2);
    }

    cv::flip(histShowImage,histShowImage,0);

    cv::cvtColor(srcImage,srcImage,cv::COLOR_GRAY2BGR);
    cv::addWeighted(srcImage,0.5,histShowImage,0.8,0,histShowImage);
    cv::imshow("histLine",histShowImage);
    cv::waitKey(0);



    return 0;
}

原始图像和显示图像如下所示:
原始二值化图像

求车道线所在位置

可以看到波峰所在的位置即为车道线大概所处区域,可以以此进行车道线检测。当然,这种思路有一定的缺陷,比如,波峰所在的位置可能是车道线的边缘(内边缘或者外边缘),也有可能是车道线的中间某部位,这都是不确定的,那么在计算车道偏离量时,这个偏离量的计算基准在每一帧时都不同,对车道偏离预警将会造成一定困扰。因此,检测出波峰之后,建议寻找更精确的车道线内边缘或者外边缘



下面的是我的公众号二维码图片,欢迎关注。
图注:幼儿园的学霸

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值