OpenCV用C++语言编写,它的主要接口也是C++语言,但是依然保留了大量的C语言接口。该库也有大量的Python, Java and MATLAB/OCTAVE (版本2.5)的接口。这些语言的API接口函数可以通过在线文档获得。如今也提供对于C#,Ch, Ruby的支持。
这次我们主要学习使用opencv的图片读取。
Opencv 提供了imread 函数能够很快的读取图片,你可以用Mat类型的对象进行接收,imread函数的原型是:
Mat imread(const string& filename, int flags);
第一个参数是文件名称第二个是读取的方式,Imread函数使用是:
如果你读入一个jpg文件,缺省情况下将创建一个3通道图像。如果你需要灰度(单通道)图像,使用如下语句:
如果你读入一个jpg文件,缺省情况下将创建一个3通道图像。如果你需要灰度(单通道)图像,使用如下语句:
Mat img = imread(filename,0);
现在你会读入图像了,那么下一步必定想知道如何对图像进行处理,要进行处理就必须先知道如何遍历图像,会遍历图像的话那么你就会将复杂的算法和逻辑运用到你要处理的图像上去了,然后你就可以完成你要实现的功能。
回归到正题,如果你要对图像进行操作那你就先必须用一个指针指向你要遍历的图像地址。然后对图像的每一个像素进行遍历(在此我们进行行遍历,也就是一行行的扫描每一个像素),然而我们又知道图片的每一个像素都是由三个通道(对应自然界的三原色
RGB)构成的,在opencv中这三个通道的顺序并不是RGB而是BGR,至于为什么,额~,我也不知道,以后知道了补上。然后计算机会通过RGB(R,G,B)这个函数求出一个值这就是RGB颜色空间的值,也就是这个点像素的值。所以我们遍历像素时如果需要对某
一个通道进行操作的话,那必须把列的数量*3。如果不需要对通道进行操作,那么图像的列和行就是你用鼠标在windows资源管理器中所看到的值(xxx*xxx)。
好了,说了这么多关于图像的基础知识,我们实现一个例子,这个例子网上都是有的,功能是,用颜色空间缩减的方法来提高对图像操作的效率。做法是:将现有颜色空间值除以某个输入值,以获得较少的颜色数。例如,颜色值0到9可取为新值0,10到19可取为10,以此类推。
我们的例子提供了两种做法,一种就是直接自己读取,一种则是用opencv的函数库进行处理。两两正好可以用来对比。先看例子:
#includeusing namespace std; using namespace cv; #define divideWith 50 Mat& ScanImageAndReduceIterator(Mat& I, const uchar* table); int main(int argc, char* argv[]) { Mat I, J; const char* imagename = "../test.jpg"; //! read a image I = imread(imagename, CV_LOAD_IMAGE_COLOR); //! read image fail if (I.empty()) { fprintf(stderr, "Can not load image %s\n", imagename); return -1; } //! show image imshow("image", I); waitKey(); //! define a table to store the preprocessed data uchar table[256]; for (int i = 0; i < 256; ++i) table[i] = divideWith* (i / divideWith);//example:Iold=14; Inew=(Iold/10)*10=(14/10)*10=1*10=10; double t; t = (double)getTickCount(); //! use The iterator (safe) method to realize this function J = ScanImageAndReduceIterator(I.clone(), table); t = 1000 * ((double)getTickCount() - t) / getTickFrequency(); cout << "Time of reducing with the iterator :" << t << " milliseconds." << endl; imshow("image1", J); waitKey(); //! use the lookUpTable which provided by opencv to realize this function t = (double)getTickCount(); Mat lookUpTable(1, 256, CV_8U); uchar* p = lookUpTable.data; for (int i = 0; i < 256; ++i) p[i] = table[i]; LUT(I, lookUpTable, J); t = 1000 * ((double)getTickCount() - t) / getTickFrequency(); cout << "Time of use lookUpTable :" << t << " milliseconds." << endl; imshow("image2", J); waitKey(); system("pause"); return 0; } //! The iterator (safe) method 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_ it, end; for (it = I.begin (), end = I.end (); it != end; ++it) *it = table[*it]; break; } case 3: { MatIterator_ it, end; for (it = I.begin (), end = I.end (); it != end; ++it) { (*it)[0] = table[(*it)[0]]; (*it)[1] = table[(*it)[1]]; (*it)[2] = table[(*it)[2]]; } } } return I; }
上面例子中ScanImageAndReduceIterator函数就是遍历图像,channels就是我们上面说的通道数,这加了判断,对不同通道数的图像进行不同的处理,比如单通道数就直接用uchar(0~256)接收,而三通道则用到了向量模板
上面说我们我们程序的功能就是要实现对图像颜色的压缩,压缩公式是:,所以我们把处理好的数据都放到一个table[256]中,然后对每个像素重新进行赋值。大家应该也看到了我们先用Mat的构造函数new出了也Mat对象lookUpTable,然后把我们之前处理好的table[256]直接赋值给到lookUpTable对象的data中,如下:
Mat lookUpTable(1, 256, CV_8U); 2 uchar* p = lookUpTable.data; 3 for (int i = 0; i < 256; ++i) 4 p[i] = table[i]; 5 LUT(I, lookUpTable, J);
然后调用LUT(原图像,查找表,输出图像);直接到达我们的效果,好我们自己遍历的效果一样。我们看看结果~
原图:
1、自己扫描赋值
2、LUT函数处理
OpenCV致力于真实世界的实时应用,通过优化的C代码的编写对其
OpenCV与其它视觉函数库性能对比
OpenCV与其它视觉函数库性能对比
执行速度带来了可观的提升,并且可以通过购买Intel的IPP高性能多媒体函数库(Integrated Performance Primitives)得到更快的处理速度。