为什么想写这个矩阵类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
非常感谢您的阅读,如果您觉得这篇文章对您有帮助,欢迎扫码进行赞赏。