自己实现的矩阵类QQ::Mat

版权声明:本文为博主原创文章,转载需注明出处。 https://blog.csdn.net/qianqing13579/article/details/54316245

为什么想写这个矩阵类Mat

用OpenCV两年半的时间了,期间也看过OpenCV的一些源码,比如Mat的实现,对OpenCV还是有一定的了解的,自己现在也在cv这个领域工作,觉得图像处理是非常有意思的一个领域,自己一直都有一一个梦想:建立自己的图像处理库,实现常用的图像处理算法,而建立图像处理库的一个基础就是需要有一个高效的矩阵类,这会大大提高图像处理算法的开发效率,最近实现了一下矩阵类,后期还会对他进行优化,大家有什么建议的,欢迎留言,不胜感激!


主要思想

这个矩阵类主要用到了下面的一些思想:
1. 模板,兼容多种类型的矩阵
2. 通过引用计数自动释放内存
3. 内存地址对齐,便于图像处理算法的指令集优化

注:
QQ::Mat除了命名规则与cv::Mat不同(QQ::Mat中的函数名使用帕斯卡命名规则),提供的接口基本与OpenCV提供的接口一致,所以,基于cv::Mat写的程序很容易改写为QQ::Mat的版本。
前面写过的几篇博客
图像旋转的原理,实现和优化
直方图均衡化算法原理与实现
Canny边缘检测算法的实现
虽然都是基于cv::Mat写的,但都非常容易改写成QQ::Mat的版本,有兴趣的读者可以自己实现一下,后面的博客中的图像处理算法都会使用QQ::Mat实现(对于需要兼容OpenCV的还是使用cv::Mat实现)。


实现

Mat.h

//////////////////////////////////////////////////////////////////////////
// 矩阵类 Mat.h 
// 2016-12-24,by QQ
//
// Please contact me if you find any bugs, or have any suggestions.
// Contact:
//      Telephone:15366105857
//      Email:[email protected]
//      Blog: http://blog.csdn.net/qianqing13579
//////////////////////////////////////////////////////////////////////////

#ifndef __MAT_H__
#define __MAT_H__
#include "CommonDefinition.h"
#include"Alloc.h"

namespace QQ
{


template <typename T>
class  DLL_EXPORTS Mat
{
public:
    //构造函数
    Mat();
    Mat(int _rows, int _cols, int _numberOfChannels);
    Mat(int _rows, int _cols, int _numberOfChannels, Scalar scalar); 
    Mat(int _rows, int _cols, int _numberOfChannels, void *_data, bool needCopyData = false);// 外部数据_data需要外部释放

    //析构函数
    virtual ~Mat();//调用Release()
    void Release();//引用计数减1
    void Deallocate();//释放数据

    //自动分配内存
    void Create(int _rows, int _cols, int _numberOfChannels);
    void Create(Size _size, int _numberOfChannels);

    //重载赋值操作符
    inline Mat& operator = (const Mat &dstMat);//共享数据

    void SetTo(const Scalar &scalar);

    // 获取指定位置的元素
    template<typename _Tp>
    inline _Tp& At(int y, int x)
    {
        return ((_Tp*)(data + step*y))[x];
    }

protected:
    void InitEmpty();

public:
    int rows;
    int cols;
    int numberOfChannels;//通道数
    int step;// 步长(每行字节数)

    uchar *data;    

    //引用计数
    int *refCount;

};// Mat


//////////////////////////////Mat的实现////////////////////////////////////////////

template <typename T>
inline Mat<T>::Mat()
{
    InitEmpty();

}

template <typename T>
inline void Mat<T>::InitEmpty()
{
    rows = cols = numberOfChannels = 0;
    data = 0;
    refCount = 0;

}

template <typename T>
inline Mat<T>::Mat(int _rows, int _cols, int _numberOfChannels)
{
    InitEmpty();
    Create(_rows, _cols, _numberOfChannels);
}

template <typename T>
inline Mat<T>::Mat(int _cols, int _rows, int _numberOfChannels, Scalar scalar)
{
    InitEmpty();
    Create(_cols, _rows, _numberOfChannels);

    SetTo(scalar);

}

//BYTE->Image,IplImage->Image
//默认不拷贝数据,外部数据_data需要外部释放
template <typename T>
inline Mat<T>::Mat(int _rows, int _cols, int _numberOfChannels, void *_data, bool needCopyData)
{
    rows = _rows;
    cols = _cols;
    numberOfChannels = _numberOfChannels;
    step = cols*numberOfChannels*sizeof(T);

    if (needCopyData == false)
    {
        data=(uchar *)_data;

        refCount = 0;
    }
    else
    {
        data = (uchar *)AlignedMalloc((step*rows + (int)sizeof(int)), 16);

        refCount = (int*)(data + step*rows);
        *refCount = 1;

        memcpy(data, _data, step*rows);//拷贝
    }


}
template <typename T>
Mat<T>::~Mat()
{
    Release();//释放
}

// 引用计数减1,如果引用计数为0了,调用Deallocate()
template <typename T>
void Mat<T>::Release()
{

    //引用计数减1,如果引用计数为0,说明没有引用,释放数据
    if (refCount && (*refCount)-- == 1)
    {
        Deallocate();
    }

    InitEmpty();

}
//释放数据
template <typename T>
void Mat<T>::Deallocate()
{

    AlignedFree(data);


}

template <typename T>
void Mat<T>::Create(int _rows, int _cols, int _numberOfChannels)
{
    if (rows == _rows&&cols == _cols&&numberOfChannels == _numberOfChannels)
    {
        return;
    }
    else
    {
        //如果不一致,引用计数减1,此时引用计数为0,释放数据和引用计数
        Release();

        rows = _rows;
        cols = _cols;
        numberOfChannels = _numberOfChannels;
        step = cols*numberOfChannels*sizeof(T);

        // 内存地址16字节对齐(指令集优化)
        data = (uchar *)AlignedMalloc((step*rows + (int)sizeof(int)), 16);

        refCount = (int*)(data + step*rows);
        *refCount = 1;

    }
}

template <typename T>
inline void Mat<T>::Create(Size _size, int _numberOfChannels)
{
    int _rows = _size.height;
    int _cols = _size.width;

    Create(_rows, _cols, _numberOfChannels);
}

//重载操作符
// 注意返回值为Image&(如果返回void,A=(B=C),那么A就没有值了)
template <typename T>
inline Mat<T>& Mat<T>::operator = (const Mat<T> &dstMat)
{
    if (this != &dstMat)
    {
        // 调用this的release
        Release();

        rows = dstMat.rows;
        cols = dstMat.cols;
        numberOfChannels = dstMat.numberOfChannels;
        step = dstMat.step;

        data = dstMat.data;

        //引用计数
        refCount = dstMat.refCount;
        (*refCount)++;
    }

    return *this;

}

template <typename T>
void Mat<T>::SetTo(const Scalar &scalar)
{
    T *dataOfSrc = (T *)data;
    int numberOfElement = rows*cols;
    for (int i = 0; i <= numberOfElement - 1; ++i, dataOfSrc += numberOfChannels)
    {
        for (int k = 0; k <= numberOfChannels - 1; ++k)
            dataOfSrc[k] = scalar.val[k];
    }

}

}// namespace QQ
#endif

其中AlignedMalloc()函数和AlignedFree()函数见博客: 实现任意字节对齐的内存分配和释放

CommonDefinition.h

//////////////////////////////////////////////////////////////////////////
// 通用定义 CommonDefinition.h
// 2014-11-13,by QQ
//
// Please contact me if you find any bugs, or have any suggestions.
// Contact:
//      Telephone:15366105857
//      Email:[email protected]
//      Blog: http://blog.csdn.net/qianqing13579
//////////////////////////////////////////////////////////////////////////


#ifndef __COMMON_DEFINITION_H__
#define __COMMON_DEFINITION_H__
#include<assert.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>

//////////////////////////////Common macros////////////////////////////////////////////
//WIN32,_WIN32:判断是否 Windows平台
//DLLAPI_EXPORTS:条件宏
//DLL_EXPORTS:DLL导出符号
#if (defined WIN32 || defined _WIN32 || defined WINCE) && defined DLLAPI_EXPORTS
#define DLL_EXPORTS __declspec(dllexport)
#else
#define DLL_EXPORTS
#endif

#ifndef MAX
#define MAX(a,b)  ((a) > (b) ? (a) : (b))
#endif

#ifndef MIN
#define MIN(a,b)  ((a) > (b) ? (b) : (a))
#endif

#define PI   3.1415926535897932384626433832795
#define LOG2 0.69314718055994530941723212145818


//角度转换
#define DEGREE2RADIAN(x) (x*PI/180)//角度转弧度
#define RADIAN2DEGREE(x) (x*180/PI)//弧度转角度

#define  DESCALE(x,n)  (((x)+(1 << ((n)-1))) >> (n))
//#define  DESCALE(x,n)  ((x) >> (n)) 

// 饱和运算
#define  saturate(x)   (uchar)(((x) & ~255) == 0 ? (x) : ~((x)>>31))

// memory deallocation
#define SAFE_DELETE(p)  { if ((p)) { delete (p); (p) = NULL; } }
#define SAFE_DELETE_ARRAY(p)  { if ((p)) { delete[] (p); (p) = NULL; } }


///////////////////////////////Common type definitions///////////////////////////////////////////////

typedef unsigned char uchar;
typedef unsigned short ushort; // 2 uchars
typedef unsigned int uint;  // 4 uchars

//Resize:interpolation methods差值方式
enum
{
    NEAREST   =0,//最近邻差值
    LINEAR    =1,//双线性插值,图像缩小时候,容易出现波纹
    AREA      =2//像素关系重采样
};


////////////////////////////namespace QQ//////////////////////////////////////////////
namespace QQ
{



/////////////////////////////Scalar/////////////////////////////////////////////
// 表示像素值
class Scalar
{
public:
    //成员函数
    //构造函数
    Scalar(double val0=0, double val1=0,double val2=0, double val3=0);//默认都为0
    Scalar(const Scalar &scalar);

    //成员变量
    double val[4];
};
inline Scalar::Scalar(double val0, double val1,double val2, double val3)
{
    val[0]=val0;
    val[1]=val1;
    val[2]=val2;
    val[3]=val3;
}
inline Scalar::Scalar(const Scalar &scalar)
{
    val[0]=scalar.val[0];
    val[1]=scalar.val[1];
    val[2]=scalar.val[2];
    val[3]=scalar.val[3];
}

///////////////////////////Size///////////////////////////////////////////////
class Size
{
public:
    //成员函数
    //构造函数
    Size();
    Size(int _width,int _height);
    Size(const Size &size);

    //成员变量
    int width;
    int height;

};
inline Size::Size():width(0),height(0){}
inline Size::Size(int _width,int _height):width(_width),height(_height){}
inline Size::Size(const Size &size):width(size.width),height(size.height){}


///////////////////////////Vec3b///////////////////////////////////////////////
class Vec3b
{
public:
    //构造函数
    Vec3b(uchar val0 = 0, uchar val1 = 0, uchar val2 = 0);//默认都为0
    Vec3b(const Vec3b &vec3b);

    inline uchar& operator[](int i);

    //成员变量
    uchar val[3];
};
inline Vec3b::Vec3b(uchar val0, uchar val1, uchar val2)
{
    val[0] = val0;
    val[1] = val1;
    val[2] = val2;
}
inline Vec3b::Vec3b(const Vec3b &vec3b)
{
    val[0] = vec3b.val[0];
    val[1] = vec3b.val[1];
    val[2] = vec3b.val[2];
}

inline uchar& Vec3b::operator[](int i)
{
    return val[i];
}

///////////////////////////Point///////////////////////////////////////////////
class Point
{
public:
    //构造函数
    Point() :x(0), y(0){}
    Point(int _x, int _y) :x(_x), y(_y){}
    //Point(const Point &point);

    //成员变量
    int x, y;
};




}//namespace QQ

#endif

结束语

重复造轮子对程序员能力的提高还是很大的,希望通过构建自己的图像处理库不断提高自己的能力,也希望自己能够在这个领域越走越远,实现自己的人生价值。

2017-1-10 17:59:32

非常感谢您的阅读,如果您觉得这篇文章对您有帮助,欢迎扫码进行赞赏。
这里写图片描述

猜你喜欢

转载自blog.csdn.net/qianqing13579/article/details/54316245