OpenCV的数据结构——大型数组类型

OpenCV中的数据类型可分为三类,而前两类(基础数据类型和辅助对象)在前面已进行详细讲述,下面将对最后一种——大型数组类型进行讲解。

大型数据类型中最重要的当属cv::Mat,这可谓是OpenCV的核心,所有主要函数几乎都和其相关。cv::Mat类用于表示任意维度的稠密数组。所谓“稠密”表示该数组的所有部分都有一个值存储,即使这个值为0。而和其相对的就是稀疏数组cv::SparseMat,稀疏数组中只有非0的数值会被存储,在数组存在很多0的时候,稀疏数组将非常节约内存;但是在数组比较稠密的时候,稀疏数组反而会浪费大量的内存。

cv::Mat类N维稠密矩阵

实际上cv::Mat由一个头部和一个数据块组成,头部包含了数组的相关信息(大小,数据类型,通道数等),数据块包含了图像中所有像素的值。头部还一个指向数据块的指针和一个引用计数器,即data属性和refcount属性。

创建一个数组

不拷贝数据的操作称为“浅拷贝”,只是复制了头部;如果拷贝了数据的操作叫“深拷贝”,这种操作会创建空间并拷贝对方的数据。

type的形式为CV_{8U, 16S, 16U, 32S, 32F, 64F}C{1, 2, 3},其中8,16,32,64指的是位数,U,S,F表示字符、整型和浮点型,1,2,3表示通道数。

cv::Mat的构造函数(非复制构造)
构造描述
cv::Mat;默认构造函数
cv::Mat( int rows, int cols, int type );指定类型的二维数组
cv::Mat(int rows, int cols, int type,const Scalar& s);指定类型的二维数组,并指定初始化值
cv::Mat(int rows, int cols, int type,void* data, size_t step=AUTO_STEP);指定类型的二维数组,并指定预先存储的数据
cv::Mat( cv::Size sz, int type );指定类型的二维数组(大小由sz指定)
cv::Mat(cv::Size sz,int type, const Scalar& s);指定类型的二维数组,并指定初始化值(大小由sz指定)
cv::Mat(cv::Size sz, int type,void* data, size_t step=AUTO_STEP);指定类型的二维数组,并指定预先存储的数据(大小由sz指定)
cv::Mat(int ndims, const int* sizes,int type);指定类型的多维数组
cv::Mat(int ndims, const int* sizes,int type, const Scalar& s);指定类型的多维数组,并指定初始化值
cv::Mat(int ndims, const int* sizes,int type, void* data,size_t step=AUTO_STEP);指定类型的多维数组,并指定预先存储的数据

注:cv::Size传入参数是先cols后rows的。

cv::Mat从其他cv::Mat复制数据的构造函数
构造描述
cv::Mat( const Mat& mat );复制构造函数
cv::Mat(const Mat& mat,const cv::Range& rows,const cv::Range& cols);只从指定的行列中复制数据的复制构造函数(只对二维有效)
cv::Mat(const Mat& mat,const cv::Rect& roi);只从感兴趣的区域中复制数据的复制构造函数(只对二维有效)
cv::Mat(const Mat& mat,const cv::Range* ranges);服务于n维数组的,从泛化的感兴趣的区域中复制数据的复制构造函数
cv::Mat( const cv::MatExpr& expr );从其他矩阵的线性代数表述中生成新矩阵的复制构造函数
cv::Mat模板构造函数和构造cv::Mat的静态方法
构造描述
cv::Mat(const cv::Vec& vec,bool copyData=true);

构造一个如同cv::Vec所指定的数据类型为T、大小为n的一维数组

cv::Mat(const cv::Matx& vec,bool copyData=true);构造一个如同cv::Vec所指定的数据类型为T、大小为 m × n的二维数组
cv::Mat(const std::vector& vec,bool copyData=true);构造STL的vector所指定的数据类型为T、大小为vector元素数的一维数组
cv::Mat::zeros( rows, cols, type );构造一个大小为rows × cols、数据类型为type指定类型的、值全为0的矩阵
cv::Mat::ones( rows, cols, type );构造一个大小为rows × cols、数据类型为type指定类型的、值全为1的矩阵
cv::Mat::eye( rows, cols, type );构造一个大小为rows × cols、数据类型为type指定类型的单位矩阵

注:使用cv::Mat::ones和cv::Mat::eye时,如果要求创建的是一个多维数组,就只有第一通道会被设置为1,其余通道保持为0。

独立获取数组元素

OpenCV有几种不同的访问数组的方法。

① 通过模板函数at<>()实现

例:单通道

cv::Mat m = cv::Mat::eye( 10, 10, CV_32FC1 );
printf("element (3, 3) is %f\n", m.at<float>(3, 3));

 例:多通道(最好使用cv::Vec<>对象)

cv::Mat m = cv::Mat::eye( 10, 10, CV_32FC2 );
printf("element (3, 3) is (%f, %f)\n", m.at<cv::Vec2f>(3, 3)[0], m.at<cv::Vec2f>(3, 3)[1]);

例:复数

cv::Mat m = cv::Mat::eye( 10, 10, cv::DataType<cv::Complexf>::type );
printf("element (3, 3) is %f + %f\n", m.at<cv::Complexf>(3, 3).re, m.at<cv::Complexf>(3, 3).im);
at<>访问器函数的变体
示例描述
M.at<int>( i )整型数组M中的元素 i
M.at<float>( i, j )浮点型数组M中的元素( i, j )
M.at<int>( pt )整型数组M中处于( pt.x, pt.y )的元素
M.at<float>( i, j, k )三维浮点型数组M中处于( i, j, k )位置的元素
M.at<uchar>( idx )无符号字符数组M中位于idx[]所索引的n维位置的元素

② 通过模板函数ptr<>()实现

ptr<>()函数接收一个整型参数来指示希望指针指向的行,并返回一个和矩阵原始数据类型相同的数据指针。例如:给定一个类型为float三通道的矩阵mtx,结构体mtx.ptr<Vec3f>(3)将会返回mtx的第三行指向第一个元素第一个(浮点)通道的指针。这通常是访问数组最快的一种方式。

③ 使用cv::Mat内嵌的迭代机制

OpenCV提供了一对迭代器模板,cv::MatConstIterator<>用于只读数组,cv::MatIterator<>用于非只读数组。所有的迭代器都必须在数组建立的时候声明并指定一个对象的类型,这样可以调用cv::Mat的成员函数begin()和end()会返回这种类型的对象。因为迭代器具有足够的智能来处理连续和非连续的内存区域,所以这种方法非常方便,不管在哪一种维度的数组中都非常有效。

// 使用迭代器来计算三通道三维数组中“最长”元素的例子
int sz[3] = { 4, 4, 4 };
cv::Mat m( 3, sz, CV_32FC3 );
cv::randu( m, -1.0f, 1.0f );
float max = 0.0f;
cv::MatConstIterator<cv::Vec3f> it = m.begin();
while( it != m.end() ){len2 = (*it)[0]*(*it)[0] + (*it)[1]*(*it)[1] + (*it)[2]*(*it)[2];if( len2 > max) max = len2;it++;
}

数组迭代器NAryMatIterator

cv::NAryMatIterator只要求被迭代的数组有相同的几何结构,结果将返回一堆数组来进行N-ary迭代器操作。这些数组也被称为“面”(plane),一个面表示输入数组有连续内存的部分。

示例一:按面进行多维数组相加

#include "stdafx.h"
#include <iostream>
#include <opencv2/opencv.hpp>int main()
{// 声明一个Matconst int n_mat_size = 5;const int n_mat_sz[] = { n_mat_size, n_mat_size, n_mat_size };cv::Mat n_mat(3, n_mat_sz, CV_32FC1);// 为Mat随机填充0.0-1.0之间的数cv::RNG rng;rng.fill(n_mat, cv::RNG::UNIFORM, 0.f, 1.f);// 生成包含指向所有我们想要迭代的Mat的指针的C风格的指针数组,这个数组必须以0或NULL终止const cv::Mat* arrays[] = { &n_mat, 0 };// 作为面的参考的C风格的Mat数组,通过其进行迭代,这里数组长度为1.cv::Mat my_planes[1];// 创建N-ary迭代器cv::NAryMatIterator it(arrays, my_planes);// 初始化和为0float s = 0.f;// 统计面数int n = 0;for (int p = 0; p < it.nplanes; p++, ++it){// it.planes中保存着每个输入数组当前平面的头s += cv::sum(it.planes[0])[0];n++;}// 输出结果std::cout << s << "\n" << n << std::endl;return 0;
}
// 运行结果:62.6319 和 1

示例二:使用N-ary将两个数组相加

#include "stdafx.h"
#include <iostream>
#include <opencv2/opencv.hpp>int main()
{// 声明两个Matconst int n_mat_size = 5;const int n_mat_sz[] = { n_mat_size, n_mat_size, n_mat_size };cv::Mat n_mat0(3, n_mat_sz, CV_32FC1);cv::Mat n_mat1(3, n_mat_sz, CV_32FC1);// 为Mat随机填充0.0-1.0之间的数cv::RNG rng;rng.fill(n_mat0, cv::RNG::UNIFORM, 0.f, 1.f);rng.fill(n_mat1, cv::RNG::UNIFORM, 0.f, 1.f);// 生成包含指向所有我们想要迭代的Mat的指针的C风格的指针数组,这个数组必须以0或NULL终止const cv::Mat* arrays[] = { &n_mat0, &n_mat1, 0 };// 作为面的参考的C风格的Mat数组,通过其进行迭代,这里数组长度为1.cv::Mat my_planes[2];// 创建N-ary迭代器cv::NAryMatIterator it(arrays, my_planes);// 初始化和为0float s = 0.f;// 统计面数int n = 0;for (int p = 0; p < it.nplanes; p++, ++it){// it.planes中保存着每个输入数组当前平面的头s += cv::sum(it.planes[0])[0];s += cv::sum(it.planes[1])[0];n++;}// 输出结果std::cout << s << "\n" << n << std::endl;return 0;
}
// 运行结果:126.34和1

示例三:两个面求和并将结果放入第三个平面的对应位置

#include "stdafx.h"
#include <iostream>
#include <opencv2/opencv.hpp>int main()
{// 声明一个Matconst int n_mat_size = 5;const int n_mat_sz[] = { n_mat_size, n_mat_size, n_mat_size };cv::Mat n_mat0(3, n_mat_sz, CV_32FC1);cv::Mat n_mat1(3, n_mat_sz, CV_32FC1);cv::Mat dst(3, n_mat_sz, CV_32FC1);// 为Mat随机填充0.0-1.0之间的数cv::RNG rng;rng.fill(n_mat0, cv::RNG::UNIFORM, 0.f, 1.f);rng.fill(n_mat1, cv::RNG::UNIFORM, 0.f, 1.f);// 生成包含指向所有我们想要迭代的Mat的指针的C风格的指针数组,这个数组必须以0或NULL终止const cv::Mat* arrays[] = { &n_mat0, &n_mat1, &dst, 0 };float* ptrs[3];// 创建N-ary迭代器cv::NAryMatIterator it(arrays, (uchar**)ptrs);for (size_t i = 0; i < it.nplanes; i++, ++it) {for (size_t j = 0; j < it.nplanes; j++) {ptrs[3][j] = std::pow(ptrs[0][j], ptrs[1][j]);}}return 0;
}

通过块访问数组元素

cv::Mat区块访问
示例描述(浅复制)
m.row( i );m中第 i 行数组
m.col( j );m中第 j 列数组
m.rowRange( i0, i1 );m中第 i0 行到第 i1-1 行所构成的数组
m.rowRange( cv::Range( i0, i1 ) );m中第 i0 行到第 i1-1 行所构成的数组
m.colRange( j0, j1 );m中第 j0 列到第 j1-1 列所构成的数组
m.colRange( cv::Range( j0, j1 ) );m中第 j0 列到第 j1-1 列所构成的数组
m.diag( d );m中偏移量为d的主对角线所组成的数组
m( cv::Range(i0,i1), cv::Range(j0,j1) );m中从点( i0, j0 )到点 ( i1-1,  j1-1 ) 所包含数据构成的数组
m( cv::Rect(i0,i1,w,h) );m中从点( i0, j0 )到点 (i0+w-1, j0+h-1) 所包含数据构成的数组
m( ranges );m中依据 ranges[0] 到 ranges[ndim-1] 所索引区域构成的数组

矩阵表达式:代数和cv::Mat

矩阵表达式可用的运算操作
示例描述
m0 + m1, m0 – m1;矩阵的加法和减法
m0 + s; m0 – s; s + m0; s – m1;矩阵和单个元素相加减
-m0;矩阵取负
s * m0; m0 * s;通过单个数进行缩放
m0.mul( m1 ); m0/m1;按元素将m0和m1相乘或相除
m0 * m1;m0和m1做矩阵相乘
m0.inv( method );对m0求逆(默认使用DECONP_LU)
m0.t();对m0求转置
m0>m1; m0>=m1; m0==m1; m0<=m1; m0按元素进行比较,返回元素只有0和255的uchar类型矩阵

m0&m1; m0|m1; m0^m1; ~m0; m0&s;

s&m0; m0|s; s|m0; m0^s; s^m0;

矩阵和矩阵之间或矩阵和单个元素之间按位进行逻辑操作

min(m0,m1); max(m0,m1); min(m0,s);

min(s,m0); max(m0,s); max(s,m0);

矩阵和矩阵之间或矩阵和单个元素之间按元素取最大值和最小值
cv::abs( m0 );对m0按元素取绝对值
m0.cross( m1 ); m0.dot( m1 );向量叉乘和点乘操作(叉乘只适用于3×1矩阵)

cv::Mat::eye( Nr, Nc, type );

cv::Mat::zeros( Nr, Nc, type );

cv::Mat::ones( Nr, Nc, type );

用于返回规定类型的 Nr × Nc 矩阵的静态方法

饱和转换

cv::saturate_cast<>()会自动检测是否有上溢出或下溢出,如果存在这种情况,这个库函数会将结果值转换为相对最小或相对最大的可行值。

其他操作

cv::Mat类的更多函数成员
示例描述
m1 = m0.clone();从m0进行完全复制,该复制将复制所有的数据元素
m0.copyTo( m1 );将m0复制给m1,若有必要,将给m1重分配内存空间
m0.copyTo( m1, mask );和m0.copyTo( m1 )一样,但只复制mask所指示的区域
m0.convertTo(m1, type, scale, offset);转换m0中元素的类型并且在尺度变换(默认为1)和增加偏置(默认为0)之后赋值给m1
m0.assignTo( m1, type );只在内部使用(集成在convertTo中)
m0.setTo( s, mask );设置m0所有元素为s,如果存在mask,那么只对mask指示区域进行操作
m0.reshape( chan, rows );改变二维数组的有效形状,chan和rows变量可能为0,表示不改变
m0.push_back( s );在末尾增加一个m×1大小的数组
m0.push_back( m1 );向m×n大小的矩阵m0增加k行并将m1复制到这些行中,m1大小必须是k×n
m0.pop_back( n );从矩阵移除n行(默认为1)
m0.locateROI( size, offset );将m0的全尺寸写入cv::size变量size,如果m0只是一个大矩阵的一小块区域,还会写入一个Point类型的offset
m0.adjustROI( t, b, l, r );通过上、下、左、右四个值调整ROI范围
m0.total();计算数组序列的元素的数目(不包括通道)
m0.isContinuous();如果m0的行之间没有空隙,则返回true
m0.elemSize();返回m0的位长度(比如三通道浮点型矩阵返回12)
m0.elemSize1();返回m0最基本元素的位长度(比如三通道浮点型矩阵返回4)
m0.type();返回m0元素的类型(比如CV_32FC3)
m0.depth();返回m0通道中的元素类型(比如CV_32F)
m0.channels();返回m0的通道数目
m0.size();以cv::Size返回m0的大小
m0.empty();如果数组没有元素,将返回true

 

稀疏数据类cv::SparseMat

cv::SparseMat类在数组非0元素非常少的情况下使用,只存储有数据的部分,可以节约大量的内存。稀疏表示的缺点是计算速度更慢(基于每个元素),但从整体来看,会节约很多计算时间。

访问稀疏数组中的元素

① cv::SparseMat::ptr()

最简单的变体为:uchar* cv::SparseMat::ptr( int i0, bool createMissing, size_t* hashval = 0)

这个特定的版本用于访问一维数组。第一个参数i0是请求元素的索引;第二个参数createMissing表示该元素不存在时是否创建;最后一个参数hashval 是哈希key,默认为NULL/0,需先计算得到哈希key。返回值是一个指向无符号字符型的指针(uchar*),一般需要再次转换为正确的类型。

cv::SparseMat::ptr()的变体还允许使用两个或三个索引,也有第一个参数是一个整型数组指针的版本,它要求这个索引的元素数量和被访问的数组的维度一样多。

补充:cv::SparseMat的数据存储格式为哈希表。查询在哈希表中的对象需要两步:一是计算哈希key(根据索引进行计算),二是在key所指向的列表(很短,理想状态下只有一个元素)中进行查找。所以基础运算时间主要耗费在查找和计算哈希key,若key已计算出来,耗费的时间就会大大减少。

② cv::SparseMat::ref()

模板函数cv::SparseMat::ref()用于返回一个指向数组中特定元素的引用,索引参数和hashval 参数和cv::SparseMat::ptr()类似。因为这是一个模板函数,所以必须指定对象的类别。

③ cv::SparseMat::value()

模板函数cv::SparseMat::value()返回的是一个值,而不是一个引用,所以这个方法也叫“只读方法”。

④ cv::SparseMat::find()

cv::SparseMat::find()返回一个请求对象的只读指针,指针类型由模板指定,所以不需要再次转换。

⑤ 迭代器

迭代器
 只读非只读
模板化cv::SparseMatConstIterator_<>cv::SparseMatIterator_<>
非模板化cv::SparseMatConstIterator<>cv::SparseMatIterator<>

示例:打印一个稀疏矩阵中的所有非0元素

#include "stdafx.h"
#include <opencv2/opencv.hpp>int main()
{// 创建一个10 × 10的稀疏矩阵int size[] = { 10, 10 };cv::SparseMat sm( 2, size, CV_32F );// 给矩阵填充值for (int i=0; i < 10; i++){int idx[2];// 生成0-327670范围的数idx[0] = size[0] * rand();idx[1] = size[1] * rand();// 添加元素或修改元素sm.ref<float>(idx) += 1.0f;}// 创建迭代器cv::SparseMatConstIterator_<float> it = sm.begin<float>();cv::SparseMatConstIterator_<float> it_end = sm.end<float>();for (; it != it_end; ++it) {// 返回一个指向被迭代器索引指向的稀疏矩阵的实际数据区域const cv::SparseMat::Node* node = it.node();printf(" (%3d, %3d) %f\n", node->idx[0], node->idx[1], *it);}return 0;
}

运行结果:

 (99610,   4910)   1.000000(232810,  168270) 1.000000(114780,  293580) 1.000000(410,     184670) 1.000000(29950,   119420) 1.000000(191690,  157240) 1.000000(57050,   281450) 1.000000(269620,  244640) 1.000000(63340,   265000) 1.000000(48270,   54360)  1.000000

稀疏数组中的特有函数

cv::SparseMat中额外的类成员函数
示例描述
cv::SparseMat sm;跳过初始化,创建一个稀疏矩阵
cv::SparseMat sm( 3, sz, CV_32F );创建一个由sz指定维度大小的三维稀疏浮点型矩阵
cv::SparseMat sm( sm0 );从系数矩阵sm0复制一个系数矩阵
cv::SparseMat( m0, try1d );从已有的稠密矩阵m0创建一个稀疏矩阵。若try1d为true,那么将m0转换成一维稀疏矩阵
cv::SparseMat( &old_sparse_mat );从一个2.1版本之前的C风格稀疏矩阵CVSparseMat创建一个新的稀疏矩阵
CvSparseMat* old_sm =(cv::SparseMat*) sm;转换操作将创建一个2.1版本之前的C风格稀疏矩阵CVSparseMat对象并且所有的数据都会被复制到新的对象中,最后返回对象的指针
size_t n = sm.nzcount();返回sm中非0元素数量

size_t h = sm.hash( i0 );

size_t h = sm.hash( i0, i1 );

size_t h = sm.hash( i0, i1, i2 );

size_t h = sm.hash( idx );

返回一维稀疏矩阵中索引 i0 所指向数据的哈希值;

返回二维稀疏矩阵中索引 i0,i1 所指向数据的哈希值;

返回三维稀疏矩阵中索引 i0,i1,i2 所指向数据的哈希值;

返回多维稀疏矩阵中索引 idx 所指向数据的哈希值;

sm.ref( i0 ) = f0;

sm.ref( i0, i1 ) = f0;

sm.ref( i0, i1, i2 ) = f0;

sm.ref( idx ) = f0;

设置一维稀疏矩阵中索引 i0的所指向元素的值为 f0;

设置二维稀疏矩阵中索引 i0, i1的所指向元素的值为 f0;

设置三维稀疏矩阵中索引 i0,i1,i2 的所指向元素的值为 f0;

设置多维稀疏矩阵中索引 idx 的所指向元素的值为 f0;

f0 = sm.value( i0 );

f0 = sm.value( i0, i1 );

f0 = sm.value( i0, i1, i2 );

f0 = sm.value( idx );

将一维稀疏矩阵中索引 i0 的所指向元素的值赋给 f0;

将二维稀疏矩阵中索引 i0, i1的所指向元素的值赋给 f0;

将三维稀疏矩阵中索引 i0,i1,i2 的所指向元素的值赋给 f0;

将多维稀疏矩阵中索引 idx 的所指向元素的值赋给 f0;

p0 = sm.find( i0 );

p0 = sm.find( i0, i1 );

p0 = sm.find( i0, i1, i2 );

p0 = sm.find( idx );

将一维稀疏矩阵中索引 i0 的所指向元素赋给 f0;

将二维稀疏矩阵中索引 i0, i1的所指向元素赋给 f0;

将三维稀疏矩阵中索引 i0,i1,i2 的所指向元素赋给 f0;

将多维稀疏矩阵中索引 idx 的所指向元素赋给 f0;

sm.erase( i0, i1, &hashval );

sm.erase( i0, i1, i2, &hashval );

sm.erase( idx, &hashval );

移除二维稀疏矩阵中索引为 i0, i1 的元素;

移除三维稀疏矩阵中索引为 i0, i1, i2 的元素;

移除多维稀疏矩阵中索引为数组 idx 的元素;

cv::SparseMatIterator it= sm.begin();创建一个浮点型稀疏矩阵迭代器it并指向其第一个元素
cv::SparseMatIterator it_end= sm.end();创建一个无符号字符型稀疏矩阵迭代器it_end并将其初始化指向数组sm的最后一个元素的后一个元素

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/491378.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MIT对话马斯克:关于自动驾驶、爱和未来世界|厚势汽车

来源&#xff1a;价值中国编译不论是在新能源汽车、私人航空航天、共通交通、还是在人工智能领域&#xff0c;埃隆马斯克天马行空的创想和脚踏实地的奋斗让人震惊不已。简直就是一个活着得的非物质文化遗产。马斯克在全球范围内收割了无数粉丝。不论是企业家、工程师、科技研究…

编写高质量代码:Web前端开发修炼之道(三)

第五章:高质量的Javascript 这章的内容我看的最久,这是跟我js基础没打好有着莫大的关系&#xff0c;但是还是耐着性子看完了&#xff0c; 不懂的东西都是百度上搜索&#xff0c;理解后再继续。下面是记录下来的笔记。 1&#xff09;如何避免JS冲突 A:匿名函数 在多人合作一个网…

OpenCV矩阵操作

矩阵类的成员函数可以进行很多基本的矩阵操作&#xff0c;在之前已经介绍过。除此之外&#xff0c;也有很多操作被表示为“友元”函数&#xff0c;它们的输入为矩阵类型&#xff0c;或者输出为矩阵类型&#xff0c;或者输入输出同为矩阵类型。下面将对这些函数及其参数进行详细…

LaTeX Error: Unknown graphics extension: .eps.解决办法

只要加一个包就行了&#xff01; \usepackage{epstopdf}

Android Studio中获取SHA1或MD5的方法

原来在Eclipse中获取SHA1或者MD5&#xff0c;在IDE界面上就可以查找到。 切换到Android Studio后&#xff0c;如何查看呢&#xff1f;找了半天没找到。那就老办法命令行。 第一步、打开Android Studio的Tools->Open Terminal... 第二步、输入命令&#xff1a;keytool -v -li…

关于机器意识的对话

来源&#xff1a; 人机与认知实验室S教授德高望重&#xff0c;建立了一个关于人工智能的微信群&#xff0c;吸引了很多关心人工智能的专业人士参与讨论。群中常有热烈的讨论。前些天恰好有一场关于机器意识的对话。感觉比较有意思&#xff0c;觉得放任这些讨论在微信群里被遗忘…

OpenCV绘图和注释

OpenCV的绘图函数可以在任意深度的图像上工作&#xff0c;但在大多数情况下&#xff0c;它们只对图像的前三个通道有影响BGR&#xff0c;如果是单通道图像&#xff0c;则默认只影响第一个通道。大多数绘图函数都支持操作对象的颜色、宽度、线型和亚像素对齐等参数。 艺术线条 …

012.对netmap API的解读

一.简要说明&#xff1a; 1.netmap API主要为两个头文件netmap.h 和netmap_user.h &#xff0c;当解压下载好的netmap程序后&#xff0c;在./netmap/sys/net/目录下&#xff0c;本文主要对这两个头文件进行分析。 2.我们从netmap_user.h头文件开始看起。 二.likely()和unlikely…

如何查看图片的长和宽(尺寸)

用PS打开该图片——>图像——>图像大小

【学术笔记】探索大脑静息态活动中的动态信息

来源&#xff1a;脑科学2019年6月18日下午&#xff0c;来自加州大学河滨分校(The University of California, Riverside) Bourns工程学院的生物工程系主任Xiaoping Hu (胡小平)教授应北京大学麦戈文脑研究所方方老师的邀请来到北京大学&#xff0c;在王克桢楼1113室为老师和同学…

OpenCV中的函数子

随着OpenCV的发展&#xff0c;封装了越来越多的功能&#xff0c;而往往这些功能不是一个函数就能完成的&#xff0c;实现为一组函数又会导致整个库的函数变得杂乱无章&#xff0c;因此常常使用一个新的对象类型来实现这个新功能。通过重载operator()来生成对象或函数子。下面主…

查找会议论文的会议地址

有时候会议论文conference proceedings引用格式中要求出现会议地址&#xff0c;如下所示 查找会议地址的方法为直接搜索该会议论文&#xff0c;以ieee为例&#xff0c;会议地址信息在该论文的首页信息中&#xff1a; Conference Location: Arlington, VA, USA中的三项就分别对应…

jqGrid API 全

JQGrid是一个在jquery基础上做的一个表格控件&#xff0c;以ajax的方式和服务器端通信。 JQGrid Demo 是一个在线的演示项目。在这里&#xff0c;可以知道jqgrid可以做什么事情。下面是转自其他人blog的一个学习资料&#xff0c;与其说是学习资料&#xff0c;说成查询帮助文档更…

OpenCV可移植图形工具HighGUI实现图像和视频操作

OpenCV把用于操作系统、文件系统以及摄像机等硬件设备交换的函数纳入了HighGUI&#xff08;High-level Graphical User Interface&#xff09;模块中。有了HighGUI模块&#xff0c;我们可以方便地打开窗口、显示图像、读出或写入图像相关的文件、鼠标事件和键盘事件。下面将对三…

华为内部深度解读,关于5G发展的28个核心问题

来源 | 腾讯深网关于5G技术动态与商用进展业界最关心的核心问题&#xff0c;华为5G产品线相关负责人近日对《深网》等进行了详细解读&#xff0c;以下是《深网》整理的问答实录&#xff1a;一、5G先进性与行业应用1. 5G到底是什么&#xff1f;和4G比有什么不一样&#xff1f;从…

福昕阅读器截屏

菜单栏中的照相机按钮即为截屏工具

OpenCV鼠标事件和滑动条事件

鼠标事件 ① 鼠标事件是通过传统的回调函数机制来完成。 void your_mouse_callback(int event, int x, int y, int flags, void* param) 其中&#xff0c;第一个参数要指明事件&#xff0c;第二个和第三个参数是鼠标事件的位置&#xff0c;第四个参数是标志位&#xff0c;第…

《需求分析与系统设计》第三篇

规则和描述性引用完整性约束允许在数据库中定义简单的业务规则&#xff0c;触发器是一个小程序&#xff0c;当定义了触发器的表发生修改操作是自动执行&#xff08;触发&#xff09;。数据库就像程序设计语言一样&#xff0c;为建模和程序设计提供了固有数据类型作为基本构造块…

GSMA:中国有望成为全球领先的5G市场之一

来源&#xff1a;GSMA移动智库近日&#xff0c;GSMA&#xff08;全球移动通信协会&#xff09;发布首个《中国移动经济发展报告2019》。报告称&#xff0c;中国的移动生态系统在2018年为中国经济创造了5.2万亿元 (7,500亿美元) 的附加值&#xff0c;相当于2018年中国GDP的5.5%。…

查期刊名缩写网站

http://cassi.cas.org/search.jsp