基本的opencv模块
cv---核心函数库
cvaux--辅助函数库
cxcore-数据结构与线性代数库
highgui-gui函数库(graphical user interface)
ml-机器学习函数库
Linux opencv编译
g++ hello-world.cpp -o hello-world \
-I /usr/local/include/opencv -L /usr/local/lib \
-lm -lcv -lhighgui -lcvaux
其中
/usr/local/include/opencv 为opencv头文件目录.
/usr/local/lib为库文件目录
-lcv -lhighgui -lcvaux为链接库文件参数.
在不同的linux版本下,头文件可能包含不一样
--------------------------------------------------------------
Mat img = imread(filename,0); //直接创建灰度图像
在函数中传递图像是家常便饭,为了不降低程序速度,opencv使用引用计数机制,其思路是让每个Mat对象有自己的信息头,但共享同一个矩阵。这通过让矩阵指针指向同一地址而实现。而拷贝构造函数则只拷贝信息头和矩阵指针,而不拷贝矩阵。
示例1:
Mat A,C;
A = imread(argv[1], CV_LOAD_IMAGE_COLOR);
Mat B(A);
C = A; // A,B,C统统指向同一个数据矩阵。
负责清理这个数据矩阵的对象,根据引用计数机制,找到最后一个使用它的对象。
如果想拷贝矩阵本身,可以使用函数clone()或者copyTo()。
Mat F = A.clone();
Mat G;
A.copyTo(G);
Mat() 构造函数
Mat M(2,2, CV_8UC3, Scalar(0,0,255));
cout << "M = " << endl << " " << M << endl << endl;
比如 CV_8UC3 表示使用8位的 unsigned char 型,每个像素由三个元素组成三通道。预先定义的通道数可以多达四个。 Scalar 是个short型vector。指定这个能够使用指定的定制化值来初始化矩阵。当然,如果你需要更多通道数,你可以使用大写的宏并把通道数放在小括号中。
解释一下,为什么2*2矩阵,会是上图中绿色部分,因为3通道的原因,默认是1通道。
int sz[3] = {2,2,2};
Mat L(3,sz, CV_8UC(1), Scalar::all(0));
上面的例子演示了如何创建一个超过两维的矩阵:指定维数,然后传递一个指向一个数组的指针,这个数组包含每个维度的尺寸;其余的相同
***为已存在IplImage指针创建信息头:
IplImage* img = cvLoadImage("greatwave.png", 1);
Mat mtx(img); // convert IplImage* -> Mat
***使用 clone() 或者 copyTo() 为一个存在的 Mat 对象创建一个新的信息头。
Mat RowClone = C.row(1).clone();
cout << "RowClone = " << endl << " " << RowClone << endl << endl;
***基于cv::Mat的std::vector
vector<float> v;
v.push_back( (float)CV_PI); v.push_back(2); v.push_back(3.01f);
cout << "Vector of floats via Mat = " << Mat(v) << endl << endl;
Vector 也是矩阵。
如何遍历图像中的每一个像素?
Opencv的矩阵值是如何存储的?
如何测试我们所实现算法的性能?
查找表是什么?为什么要用它?
颜色空间缩减算法(为了使得颜色空间缩小),步骤:
遍历每一个像素;
对像素应用固定公式(向下取整,颜色值0到9可取为新值0,10到19可取为10,以此类推。),如下图。
根据上式可以建立查找表,从而得到两种颜色空间的映射空间,通过查找表是一种聪明的方法,省去了每次都来计算。
代码如下:
int divideWith; // convert our input string to number - C++ style
stringstream s;
s << argv[2];
s >> divideWith;
if (!s)
{
cout << "Invalid number entered for dividing. " << endl;
return -1;
}
uchar table[256];
for (int i = 0; i < 256; ++i)
table[i] = divideWith* (i/divideWith);
OpenCV提供了两个简便的可用于计时的函数 getTickCount() 和 getTickFrequency() 。第一个函数返回你的CPU自某个事件(如启动电脑)以来走过的时钟周期数,第二个函数返回你的CPU一秒钟所走的时钟周期数。这样,我们就能轻松地以秒为单位对某运算计时:
double t = (double)getTickCount();
// 做点什么 ...
t = ((double)getTickCount() - t)/getTickFrequency();
cout << "Times passed in seconds: " << t << endl;
图像矩阵如何存储在内存之中?
连续存储或非连续存储,可以使用 isContinuous() 来去判断矩阵是否是连续存储的.
R,G,B,b存在最前面,g其次,r最后。
图像访问?
1 经典c风格运算符[](指针)访问
Mat& ScanImageAndReduceC(Mat& I, const uchar* const table)
{
// accept only char type matrices
CV_Assert(I.depth() != sizeof(uchar));
int channels = I.channels();
int nCols = I.cols* channels; //因为三个通道的原因,我们需要遍历//的元素数目也是3倍
int nRows = I.rows;
if (I.isContinuous()) //如果矩阵是以连续方式存储的,我们只需请求一// 次指针、然后一路遍历下去就行
{
nCols *= nRows;
nRows = 1;
}
int i,j;
uchar* p;
for( i = 0; i < nRows; ++i)
{
p = I.ptr<uchar>(i);
for ( j = 0; j < nCols; ++j)
{
p[j] = table[p[j]];
}
}
return I;
}
2 迭代法
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; //对于彩色图像中的一行,每列// 中有3个uchar元素,这可以被认为是一个小的包含uchar元素的vector,// 在OpenCV中用 Vec3b 来命名。
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;
}
4. 核心函数LUT(The Core Function)
这是最被推荐的用于实现批量图像元素查找和更该操作图像方法。在图像处理中,对于一个给定的值,将其替换成其他的值是一个很常见的操作,OpenCV 提供里一个函数直接实现该操作,并不需要你自己扫描图像,就是:operationsOnArrays:LUT() <lut> ,一个包含于core module的函数. 首先我们建立一个mat型用于查表:
Mat lookUpTable(1, 256, CV_8U);
uchar* p = lookUpTable.data;
for( int i = 0; i < 256; ++i)
p[i] = table[i];
然后我们调用函数 (I 是输入 J 是输出):
LUT(I, lookUpTable, J);
我们得出一些结论: 尽量使用 OpenCV 内置函数. 调用LUT 函数可以获得最快的速度. 这是因为OpenCV库可以通过英特尔线程架构启用多线程. 当然,如果你喜欢使用指针的方法来扫描图像,迭代法是一个不错的选择,不过速度上较慢。在debug模式下使用on-the-fly方法扫描全图是一个最 浪费资源的方法,在release模式下它的表现和迭代法相差无几,但是从安全性角度来考虑,迭代法是更佳的选择。
Onthefly就是使用at函数。