接口OpenCV';用于矩阵乘法的带blas的s Mat容器

接口OpenCV';用于矩阵乘法的带blas的s Mat容器,opencv,matrix-multiplication,openblas,Opencv,Matrix Multiplication,Openblas,我正在处理UHD(2160 x 3840)图像。 其中一个处理是在X轴和Y轴上处理Sobel滤波,然后我必须将每个输出矩阵乘以它的转置,然后我将梯度图像处理为梯度和的平方根 所以:S=sqrt(S_x*S_x^t+S_y*S_y^t) 由于图像的尺寸,OpenCV在不使用多线程的情况下最多需要20秒来处理,而使用多线程的情况下则需要10秒 我知道OpenCV调用OpenCL是为了加快过滤操作,所以我认为要想从过滤步骤中获得性能,可能需要很长时间 对于矩阵乘法,我从OpenCV的OpenCLGEM

我正在处理UHD(2160 x 3840)图像。 其中一个处理是在X轴和Y轴上处理Sobel滤波,然后我必须将每个输出矩阵乘以它的转置,然后我将梯度图像处理为梯度和的平方根

所以:S=sqrt(S_x*S_x^t+S_y*S_y^t)

由于图像的尺寸,OpenCV在不使用多线程的情况下最多需要20秒来处理,而使用多线程的情况下则需要10秒

我知道OpenCV调用OpenCL是为了加快过滤操作,所以我认为要想从过滤步骤中获得性能,可能需要很长时间

对于矩阵乘法,我从OpenCV的OpenCLGEMM内核实现中体验到一种不稳定性

所以我想尝试使用OpenBLAS insted

我的问题是:

1.)

我编写了以下代码,但接口OpenCV的Mat对象面临一些问题:

template<class _Ty>
void mm(cv::Mat& A,cv::Mat& B,cv::Mat& C)
{
    static_assert(true,"support matrix_multiply is only defined for floating precision numbers.");
}

template<>
inline void mm<float>(cv::Mat& A,cv::Mat& B,cv::Mat& C)
{
    const int M = A.rows;
    const int N = B.cols;
    const int K = A.cols;

    cblas_sgemm( CblasRowMajor ,// 1
                 CblasNoTrans, // 2 TRANSA
                 CblasNoTrans, // 3 TRANSB
                 M,       // 4 M
                 N,       // 5 N
                 K,       // 6 K
                 1.,           // 7 ALPHA
                 A.ptr<float>(),//8 A
                 A.rows,        //9 LDA
                 B.ptr<float>(),//10 B
                 B.rows,        //11 LDB
                 0.,            //12 BETA
                 C.ptr<float>(),//13 C
                 C.rows);       //14 LDC

}

template<>
inline void mm<double>(cv::Mat& A,cv::Mat& B,cv::Mat& C)
{
    cblas_dgemm(CblasRowMajor,CblasNoTrans,CblasNoTrans,A.rows,B.cols,A.cols,1.,A.ptr<double>(),A.rows,B.ptr<double>(),B.cols,0.,C.ptr<double>(),C.rows);
}
    void matrix_multiply(cv::InputArray _src1, cv::InputArray _src2, cv::OutputArray _dst)
    {

        CV_DbgAssert(  (_src1.isMat() || _src1.isUMat()) && (_src1.kind() == _src2.kind()) &&
                      (_src1.depth() == _src2.depth()) && (_src1.depth() == CV_32F) && (_src1.depth() == _src1.type()) &&
                      (_src1.rows() == _src2.cols())
                       );


        cv::Mat src1 = _src1.getMat();
        cv::Mat src2 = _src2.getMat();
        cv::Mat dst;

        bool cpy(false);

        if(_dst.rows() == _src1.rows() && _dst.cols() == _src2.cols() && _dst.type() == _src1.type())
            dst = _dst.getMat();
        else
        {
            dst = cv::Mat::zeros(src1.rows,src2.cols,src1.type());
            cpy = true;
        }

        if(cpy)
            dst.copyTo(_dst);
    }
模板
空隙mm(cv:Mat&A、cv:Mat&B、cv:Mat&C)
{
静态_断言(true,“支持矩阵_乘法仅定义为浮点数”);
}
模板
内联空隙mm(cv::Mat&A、cv::Mat&B、cv::Mat&C)
{
const int M=A.行;
常数int N=B.cols;
常数int K=A.cols;
cblas_sgemm(CBLASROWMARGE,//1
CblasNoTrans,//2交易
CblasNoTrans,//3 TRANSB
M、 //4米
N、 //5 N
K、 //6K
1.,//7α
A.ptr(),//8 A
A.rows,//9 LDA
B.ptr(),//10 B
B.rows,//11 LDB
0.,//12贝塔
C.ptr(),//13 C
C.rows);//14 LDC
}
模板
内联空隙mm(cv::Mat&A、cv::Mat&B、cv::Mat&C)
{
cblas_dgemm(CblasRowMajor,CblasNoTrans,CblasNoTrans,A.rows,B.cols,A.cols,1.,A.ptr(),A.rows,B.ptr(),B.cols,0.,C.ptr(),C.rows);
}
空矩阵乘法(cv::InputArray src1,cv::InputArray src2,cv::OutputArray dst)
{
CV_DbgAssert((_src1.isMat()| | u src1.isUMat())&&(_src1.kind()==_src2.kind())&&
(\u src1.depth()&&
(_src1.rows()==_src2.cols())
);
cv::Mat src1=_src1.getMat();
cv::Mat src2=_src2.getMat();
cv::Mat dst;
boolcpy(假);
如果(_dst.rows()
dst=_dst.getMat();
其他的
{
dst=cv::Mat::zeros(src1.rows、src2.cols、src1.type());
cpy=真;
}
if(cpy)
dst.copyTo(_dst);
}
我尝试按照此处指定的方式组织数据:

没有成功。 这是我的主要问题

(二) 我在考虑如何加快我的实现速度,以应用此处所示的分而治之方法:

但只有四个子矩阵。 是否有人尝试过类似的方法或获得了更好的方法来提高矩阵乘法的性能(不使用GPU)


提前感谢您的帮助。

我找到了问题1)的解决方案。 我的第一个实现基于BLAS库的文档。 BLAS已经用FORTRAN语言编写,在这个语言中索引开始于1,而不是在C或C++中的0。 另一件事是许多图书馆用FORTRAN语言编写的存储在列顺序(例如BLAS,LAPACK)的存储器,而不是大多数C或C++库(例如OpenCV)按顺序排列存储器。 将这两个属性计入计数后,我将代码修改为:

template<class _Ty>
void mm(cv::Mat& A,cv::Mat& B,cv::Mat& C)
{
    static_assert(true,"The function gemm is only defined for floating precision numbers.");
}

template<>
void mm<float>(cv::Mat& A,cv::Mat& B,cv::Mat& C)
{
    const int M = A.cols+1;
    const int N = B.rows;
    const int K = A.cols;

    cblas_sgemm( CblasRowMajor ,// 1
                 CblasNoTrans, // 2 TRANSA
                 CblasNoTrans, // 3 TRANSB
                 M,       // 4 M
                 N,       // 5 N
                 K,       // 6 K
                 1.,           // 7 ALPHA
                 A.ptr<float>(),//8 A
                 A.step1(),        //9 LDA
                 B.ptr<float>(),//10 B
                 B.step1(),        //11 LDB
                 0.,            //12 BETA
                 C.ptr<float>(),//13 C
                 C.step1());       //14 LDC
}

template<>
void mm<double>(cv::Mat& A,cv::Mat& B,cv::Mat& C)
{
    const int M = A.cols+1;
    const int N = B.rows;
    const int K = A.cols;

    cblas_dgemm( CblasRowMajor ,// 1
                 CblasNoTrans, // 2 TRANSA
                 CblasNoTrans, // 3 TRANSB
                 M,       // 4 M
                 N,       // 5 N
                 K,       // 6 K
                 1.,           // 7 ALPHA
                 A.ptr<double>(),//8 A
                 A.step1(),        //9 LDA
                 B.ptr<double>(),//10 B
                 B.step1(),        //11 LDB
                 0.,            //12 BETA
                 C.ptr<double>(),//13 C
                 C.step1());       //14 LDC
}
模板
空隙mm(cv:Mat&A、cv:Mat&B、cv:Mat&C)
{
static_assert(true,“函数gemm仅为浮点数定义”);
}
模板
空隙mm(cv:Mat&A、cv:Mat&B、cv:Mat&C)
{
常数int M=A.cols+1;
常量int N=B行;
常数int K=A.cols;
cblas_sgemm(CBLASROWMARGE,//1
CblasNoTrans,//2交易
CblasNoTrans,//3 TRANSB
M、 //4米
N、 //5 N
K、 //6K
1.,//7α
A.ptr(),//8 A
A.step1(),//9 LDA
B.ptr(),//10 B
B.step1(),//11 LDB
0.,//12贝塔
C.ptr(),//13 C
C.step1());//14 LDC
}
模板
空隙mm(cv:Mat&A、cv:Mat&B、cv:Mat&C)
{
常数int M=A.cols+1;
常量int N=B行;
常数int K=A.cols;
cblas_dgemm(CblasRowMajor,//1
CblasNoTrans,//2交易
CblasNoTrans,//3 TRANSB
M、 //4米
N、 //5 N
K、 //6K
1.,//7α
A.ptr(),//8 A
A.step1(),//9 LDA
B.ptr(),//10 B
B.step1(),//11 LDB
0.,//12贝塔
C.ptr(),//13 C
C.step1());//14 LDC
}
每件事都很顺利。 没有额外的多线程或分治方法,我能够将代码一步的处理时间从150ms减少到500us。 所以它为我解决了一切:)