文章目录
- 前言
- 一、MAT矩阵
- 二、颜色系统
- 三、计时
- 四、内存模型及访问
- 五、矩阵加权求和
前言
提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
一、MAT矩阵
基本上讲 Mat 是一个类,由两个数据部分组成:矩阵头(包含矩阵尺寸,存储方法,存储地址等信息)和一个指向存储所有像素值的矩阵(根据所选存储方法的不同矩阵可以是不同的维数)的指针。
同时不要忘了我们正在讨论的是计算量很大的图像处理算法,因此,除非万不得已,我们不应该拷贝 大 的图像,因为这会降低程序速度。
OpenCV使用引用计数机制。其思路是让每个 Mat 对象有自己的信息头,但共享同一个矩阵。这通过让矩阵指针指向同一地址而实现。而拷贝构造函数则 只拷贝信息头和矩阵指针 ,而不拷贝矩阵。
你可以创建只引用部分数据的信息头。比如想要创建一个感兴趣区域( ROI ),你只需要创建包含边界信息的信息头:
Mat D (A, Rect(10, 10, 100, 100) ); // using a rectangle
Mat E = A(Range:all(), Range(1,3)); // using row and column boundaries
但某些时候你仍会想拷贝矩阵本身(不只是信息头和矩阵指针),这时可以使用函数 clone() 或者
copyTo() 。
Mat F = A.clone();
Mat G;
A.copyTo(G);
M.create(4,4, CV_8UC(2));
这个创建方法不能为矩阵设初值,它只是在改变尺寸时重新为矩阵数据开辟内存。
二、颜色系统
RGB是最常见的,这是因为人眼采用相似的工作机制,它也被显示设备所采用。
HSV和HLS把颜色分解成色调、饱和度和亮度/明度。这是描述颜色更自然的方式,比如可以通过抛弃最后一个元素,使算法对输入图像的光照条件不敏感。
YCrCb在JPEG图像格式中广泛使用。
CIE Lab*是一种在感知上均匀的颜色空间,它适合用来度量两个颜色之间的 距离 。
“HLS 是Hue(色相)、Luminance(亮度)、Saturation(饱和度)。
HSV 色调(H),饱和度(S),明度(V)。
Scalar 是个short型vector
具体说明HSV/HSB与HLS的区别
首先, HSB 和 HSV 是同一个东西,只是名称不同,本文后面仅使用 HSB,当提到它的时候,也代表 HSV。
HSB 和 HSL 在字面意思上是一样的:
H 指的是色相(Hue),就是颜色名称,例如“红色”、“蓝色”; S 指的是饱和度(Saturation),即颜色的纯度;
L(Lightness) 和 B(Brightness)是明度,颜色的明亮程度 在原理和表现上,HSL 和 HSB 中的 H(色相)
完全一致,但二者的 S(饱和度)不一样, L 和 B (明度 )也不一样:HSB 中的 S 控制纯色中混入白色的量,值越大,白色越少,颜色越纯; HSB 中的 B 控制纯色中混入黑色的量,值越大,黑色越少,明度越高
HSL 中的 S 和黑白没有关系,饱和度不控制颜色中混入黑白的多寡; HSL 中的 L 控制纯色中的混入的黑白两种颜色。
常用的一种方法是 颜色空间缩减 。其做法是:将现有颜色空间值除以某个输入值,以获得较少的颜色数。例如,颜色值0到9可取为新值0,10到19可取为10,以此类推。
uchar (无符号字符,即0到255之间取值的数)类型的值除以 int 值,结果仍是 char 。因为结果是char类型的,所以求出来小数也要向下取整。
三、计时
另外有个问题是如何计时。没错,OpenCV提供了两个简便的可用于计时的函数 getTickCount() 和 getTickFrequency() 。第一个函数返回你的CPU自某个事件(如启动电脑)以来走过的时钟周期数,第二个函数返回你的CPU一秒钟所走的时钟周期数。这样,我们就能轻松地以秒为单位对某运算计时:
double t = (double)getTickCount();
// 做点什么 …
t = ((double)getTickCount() - t)/getTickFrequency();
cout << "Times passed in seconds: " << t << endl;
四、内存模型及访问
对于Mat的ptr函数,返回的是<>中的模板类型指针,指向的是()中的第row行的起点 通常<>中的类型和Mat的元素类型应该一致
然后再用该指针去访问对应col列位置的元素单通道 cv::Mat image = cv::Mat(400, 600, CV_8UC1); //定义了一个Mat变量image。
uchar * data00 = image.ptr(0); //data00是指向image第一行第一个元素的指针。
uchar * data10 = image.ptr(1); //data10是指向image第二行第一个元素的指针。
uchar * data01 = image.ptr(0)[1];//data01是指向image第一行第二个元素的指针。多通道 cv::Mat image = cv::Mat(400, 600, CV_8UC3); //宽400,长600,3通道彩色图片
cv::Vec3b * data000 = image.ptrcv::Vec3b(0); cv::Vec3b * data100 =
image.ptrcv::Vec3b(1); cv::Vec3b * data001 =
image.ptrcv::Vec3b(0)[1]; cv::Vec3b * data
高性能查表法:
Mat& ScanImageAndReduceC(Mat& I, const uchar* const table) {
// accept only char type matrices
CV_Assert(I.depth() != sizeof(uchar));
int channels = I.channels();
int nRows = I.rows;
int nCols = I.cols * channels
//判断此处是否为连续存储
if (I.isContinuous())
{
nCols = nRows;
nRows = 1;
}
int i,j;
uchar p;
for( i = 0; i < nRows; ++i)
{
p = I.ptr(i);
for ( j = 0; j < nCols; ++j)
{
p[j] = table[p[j]];
}
}
return I; }
迭代法:
Mat& ScanImageAndReduceIterator(Mat& I, const uchar* const table) {
// accept only char type matrices
CV_Assert(I.depth() != sizeof(uchar));const int channels = I.channels(); switch(channels) { case 1: { MatIterator_<uchar> it, end; for( it = I.begin<uchar>(), end = I.end<uchar>(); it != end; ++it) *it = table[*it]; break; } case 3: { MatIterator_<Vec3b> it, end; for( it = I.begin<Vec3b>(), end = I.end<Vec3b>(); it != end; ++it) { (*it)[0] = table[(*it)[0]]; (*it)[1] = table[(*it)[1]]; (*it)[2] = table[(*it)[2]]; } } } return I; 最高效的Lut操作: //查找表,数组的下标对应图片里面的灰度值 //例如lutData[20]=0;表示灰度为20的像素其对应的值0. //可能这样说的不清楚仔细看下代码就清楚了。 uchar lutData[256]; for (int i = 0; i<256; i++) { if(i<=100) lutData[i] =0; if (i > 100 && i <= 200) lutData[i] = 100; if (i > 200) lutData[i] = 255; } Mat lut(1, 256, CV_8UC1, lutData);
五、矩阵加权求和
saturate_cast<uchar>主要是为了防止颜色溢出操作
原理大致如下
if(data<0)
data=0;
elseif(data>255)
data=255;
Mat kern = (Mat_<char>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
然后调用 filter2D 函数,参数包括输入、输出图像以及用到的核: filter2D(I, K, I.depth(), kern );