计算机视觉:人眼看到的东西转换成计算机能识别的数据
inline 内联函数,编译的时候,直接将代码copy到调用的函数中去。
非内联函数 每个函数出栈入栈,会有空间消耗。
1.创建和清理mat空间,处理图像类型用unsigned char来处理,不要用char,负数会溢出
*通过构造函数直接创建:
Mat mat(3000,4000,CV_8UC3);
param1:高 param2:宽 param3:数据类型,UC3->unsinged char 3个字节
*create会把之前的垃圾清理掉
mat.create(rows, cols, CV_8UC1);
*release或者析构,手动清理。
引用计数为1时释放
内存中实际上是BGR存放的
isContinuous
*判断存储空间是否连续
*如果不连续,通过step记录 获取每一行的数据到下一行的数据间隔是多少
直接地址访问连续空间
{
int size = mat.rows*mat.cols*mat.elemSize(); //连续空间的大小 mat.elemSize() 元素大小
//连续空间遍历访问 data-》mat的成员参数
for(int i = 0; i < size(); i+=3)
{
mat.data[i] = 0; //B
mat.data[i+1] = 0; //G
mat.data[i+2] = 0; //R
}
//优化编码后效率高13ms(4000*3000)
}
直接地址访问不连续空间
{
for(int i = 0; i < mat.rows; i++)
{
for(int j = 0; j < mat.cols; j++)
{
(&mat.data[i*mat.step])[j*3] = 255; //B
(&mat.data[i*mat.step])[j*3 + 1] = 255; //G
(&mat.data[i*mat.step])[j*3 + 2] = 255; //R
}
}
//优化编码后效率高12ms(4000*3000)
}
通过ptr接口遍历Mat(模板函数) 好处:抛出异常
{
*性能基本等同有地址访问(17ms)
*mat.ptr<Vec3b>(row); //返回的指针,返回某一行的数据
*mat.ptr<Vec3b>(row,col); //返回某一行某一列的数据
}
通过at接口遍历Mat(模板函数) 好处:越界,排除异常
{
*接口最简单的遍历方法(29ms)
mat.at<Vec3b>(row, col)[0] = 255;
mat.at<Vec3b>(row, col)[0] = 255;
mat.at<Vec3b>(row, col)[0] = 255;
}
通过迭代器遍历Mat
{
*可以不用管mat的行列
auto it = mr.begin<Vec3b>();
auto it_end = mr.end<Vec3b>();
for(;it != it_end; ++it)
{
(*it).val[0] = 0;
(*it).val[1] = 222;
(*it).val[2] = 0;
}
}
#include <opencv2\core.hpp>
#include <opencv2\imgcodecs.hpp>
#include <opencv2\highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;
void PrintMs(const char *text = "")
{
static long long last = 0;
long long cur = getTickCount(); //opencv提供的 int64
if (last == 0)
{
last = cur;
return;
}
long long ms = 0;
ms = (double)(cur - last) / getTickFrequency() * 1000; //getTickFrequency 频率 *1000为ms
if (*text != 0) //取第一字节
{
printf("%s = %dms\n", text, ms);
}
last = getTickCount();
}
int main(int argc, char *argv)
{
Mat mat(3000, 4000, CV_8UC3);
//mat.create(3000, 4000, CV_8UC3);
//元素大小 字节数
int es = mat.elemSize(); //es = 3
int size = mat.rows * mat.cols * es;
PrintMs();
for (int i = 0; i < size; i += es)
{
mat.data[i] = 255; //B
mat.data[i+1] = 0; //G
mat.data[i+2] = 0; //R
}
PrintMs("mat.data ms");
//地址遍历不一定连续的Mat
//PrintMs();
for (int row = 0; row < mat.rows; row++)
{
for (int col = 0; col < mat.cols; col++)
{
(&mat.data[row*mat.step])[col * es] = 0; //B
(&mat.data[row*mat.step])[col * es + 1] = 0; //G
(&mat.data[row*mat.step])[col * es + 2] = 255; //R
}
}
PrintMs("mat.step ms");
//使用ptr遍历Mat
//PrintMs();
for (int row = 0; row < mat.rows; row++)
{
for (int col = 0; col < mat.cols; col++)
{
Vec3b *c = mat.ptr<Vec3b>(row, col);
c->val[0] = 0; //B
c->val[1] = 255; //G
c->val[2] = 0; //R
}
}
PrintMs("mat.ptr ms");
try{
//使用at来遍历 代码简洁,不需要指针
for (int row = 0; row < mat.rows; row++)
{
for (int col = 0; col < mat.cols; col++)
{
Vec3b &m = mat.at<Vec3b>(row, col); //引用是否占内存空间,跟编辑器有关
m[0] = 100;
m[1] = 100;
m[2] = 100;
}
}
PrintMs("mat.at ms");
}
catch (Exception &ex)
{
cout << ex.what() << endl;
}
//迭代器遍历
auto it = mat.begin<Vec3b>();
auto it_end = mat.end<Vec3b>();
for (; it != it_end; it++)
{
(*it).val[0] = 0;
(*it).val[1] = 0;
(*it).val[2] = 255;
}
PrintMs("mat.itr ms");
namedWindow("mat");
imshow("mat", mat);
waitKey(0);
return 0;
}