Installation in Windows
Build applications with OpenCV inside the “Microsoft Visual Studio”
环境变量
C:\Program Files\opencv\build\x64\vc15\bin
C:\Program Files\opencv\build\include
C:\Program Files\opencv\build\include\opencv # 如果不用可以不添加
C:\Program Files\opencv\build\include\opencv2
C:\Program Files\opencv\build\x64\vc15\lib # vc15对应vs2017
opencv_world343.lib # release
opencv_world343d.lib # debug
[compiler] sudo apt install build-essential
[required] sudo apt install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev
[optional] sudo apt install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev
git clone https://github.com/opencv/opencv.git
cd opencv
mkdir build
cd build
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D OPENCV_GENERATE_PKGCONFIG=ON ..
make -j8
sudo make install
sudo vim /etc/ld.so.conf.d/opencv.conf
/usr/local/lib
sudo ldconfig
sudo vim /etc/bash.bashrc
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig
export PKG_CONFIG_PATH
g++ test.cpp $(pkg-config --cflags --libs opencv4)
- “IMREAD_UNCHANGED”: 不改变图像格式打开
- “IMREAD_GRAYSCALE”: 以灰度图像打开
- “IMREAD_COLOR”: 以彩色图像打开
// C
FILE *f = fopen("file name", "xx");
fclose(f);
key word | what mean |
---|---|
w | 写 |
r | 读 |
wb | 二进制写 |
rb | 二进制读 |
// C++
// 1
fstream f;
f.open("file name"; ios::xx);
// 2
fstream f("file name", ios::xx);
f.close();
key word | what mean |
---|---|
in | 读;文件不存在则创建(ifstream) |
out | 写;文件不存在则创建(ofstream) |
ate | 文件打开时,指针在文件最后;或改变指针位置,常和in、out联合使用 |
app | 写;文件不存在则创建;若存在则在原文件内容后写入写的内容 |
trunc | 在读写前先将文件长度截断为0 |
nocreate | 文件不存在时产生错误,常和in或app联合使用 |
noreplace | 文件存在时产生错误,常和out联合使用 |
binary | 二进制格式文件 |
open | fopen |
---|---|
缓冲文件系统(受内存缓冲区大小的影响)无缓冲 | 非缓冲文件系统(借助文件结构指针对文件进行管理)有缓冲 |
低级IO,系统指令,不可移植 | 高级IO,封装函数,可移植 |
一般打开设备文件 | 一般打开普通文件 |
Keyword | 类型 | 长度 | 取值 |
---|---|---|---|
bool | 布尔型 | 一个字节 | false和true;0和1 |
BOOL | int型 | 实际环境而定,一般可认为四个字节 | FALSE和TRUE;0和非0 |
iostream:输入输出流。库的基础是istream和ostream类型。
#include
std::cout<< <> ;
声明可以多次,定义只能一次
声明
- 仅仅告诉编译器,有个某类型的变量会被使用,但编译器并不会为它分配任何内存
- 一般在头文件中,对编译器说:我这里有一个函数叫f(),让编译器知道这个函数的存在
- 不需要函数体
定义
- 编译器会为它分配内存
- 一般在源文件中,具体就是函数的实现过程,写明函数体
- 需要函数体
函数的声明extern关键词可有可无,因为函数本身不加修饰的话就是extern。但在引用的时候一样是需要声明的。
全局变量在外部使用声明时,extern关键词是必须的,如果变量无extern修饰且没有显式的初始化,同样成为变量的定义
extern int a; //声明一个全局变量a
int a; //定义一个全局变量a
extern int a = 0; //定义一个全局变量a,并给初值
int a = 0; //定义一个全局变量a,并给初值
类型修饰符,常类型/是指/使用/类型修饰符/修饰const说明的类型,常类型的变量或对象的值是不能被更新的(constant)。
const int Max = 100;
- const常量有数据类型,编译器可以对const进行安全检查。
- 宏常量没有数据类型,只进行字符替换,没有类型安全检查,并且在字符串替换时可能会产生意想不到的错误。
防止意外的修改
void f(const int i){i = 10; //error!} //如果在函数体内修改i,编译器就会报错
class A{
void f(int i) {...} //一个函数
void f(int i) const {...} //上一个函数的重载}
编译器不为不同const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得效率更高
const定义常量从汇编角度来看,只能给出对应的内存地址,而不是像#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝
#define PI 3.14 //常量宏
const double pi = 3.14 //此时并未将Pi放入ROM中
double i = pi //此时为pi分配内存,以后不再分配
double j = pi //没有分配内存
double I = PI //编译期间进行宏替换,分配内存
double j = PI //再进行宏替换,又一次分配内存
- const修饰变量
TYPE const ValueName = value;
const TYPE valueName = value;
两种本质一样。const修饰的/类型为TYPE/变量value/是不可变的
- 将const改为外部连接,作用扩大至全局,编译时会分配内存,并且可以不进行初始化,仅仅作为声明,编译器认为在程序其他地方进行定义。
extend const int ValueName = value;
- 指针本身是常量不可变
char * const pContent;
- 指针所指向的内容是常量不可变
const char *pContent;
- 两者都不变
const char* const pContent;
- 区别
*cosnt,const修饰指针所指向的变量,指针指向为常量
const *,const修饰指针本身,指针本身为常量
- 修饰函数参数
- 传递过来的参数在函数内不可改变(无意义,因为Var本身就是形参)
void f(const int Var);
- 参数指针所指内容为常量不可变
void f(const char* Var);
- 参数指针本身为常量不可变(也无意义,因为char* Var也是形参)
void f(char* const Var);
- 参数为引用,为了增加效率同时防止修改。
void f(const Class& Var); //引用参数在函数内不改变
void f(const TYPE& Var); //引用参数在函数内常量不可变
这样的const引用传递和最普通的函数按值传递的效果一模一样,禁止对引用的对象的一切修改,唯一不同的是按值传递会先建立一个对象的副本,然后传递过去,而它直接传递地址,所以const引用传递比按值传递更有效,另外只有引用const传递可以传递一个临时对象,以为临时对象都是const属性,且是不可见的,短时间存在一个局部域中,所以不能使用指针,只有引用的const传递能够捕捉到这个家伙。
- 修饰函数返回值
使用不多,含义和const修饰普通变量以及指针的含义基本相同
const int f1() //无意义,参数返回本身就是赋值
const int *f2() //调用时const int *pValue = f2();可以把f2()看成一个变量,即指针内容不可变
int *const f3() //调用时int *const pValue = f3();可以把f3()看成一个变量,即指针本身不可变
一般情况下,函数的返回值为某个对象时,如果将声明为const时,多用于操作符的重载。
通常不建议使用const修饰函数的返回值类型/为某个对象或某个对象引用的情况。如果返回值为某个对象const(const A test = A 实例)或某个对象的引用为const(const A& test = A实例),则返回值具有const属性,则返回实例只能访问类A中的共有(保护)数据成员和const成员函数,并且不允许对其进行赋值操作,这在一般情况下很少用到。
- const修饰成员变量
const修饰类的成员函数,表示成员常量,不能被修改,同时只能在初始化列表中赋值
class A{
const int nValue; //成员常量不能被修改
A(int x): nValue(x){...}; //只能在初始化列表中赋值
}
- const修饰成员函数
const修饰类的成员函数,则该成员函数不能修改类中任何非const成员函数。一般写在函数的最后来修饰。
class A{
void f() const; //常成员函数,不能改变对象的成员变量,也不能调用类中任何非const成员函数
}
对于const类对象/指针/引用,只能调用类的const成员函数,因此,const修饰成员函数的最重要作用就是限制对于const对象的作用。
- const成员函数不被允许修改它所在对象的任何一个数据成员;
- const成员函数能够访问对象的const成员,而其它成员函数不可以。
- const修饰类对象表示该对象为常量对象,其中的任何成员都不能被修改。对于对象指针和对象引用也是一样。
- const修饰的对象,该对象的任何非const成员函数都不能被调用,因为任何非const成员函数会有修改成员变量的企图。
class A{
void f1();
void f1() const;
}
const A aObj;
aObj.f1(); //错
aObj.f2()' //正确
const A* aObj = new A();
aObj->f1(); //错
aObj->f2(); //正确
const _ cast: const_cast
运算符用来修改类型的const或volatile属性。除了const或volatile修饰之外,type_id和expression的类型是一样的。
- 常量指针被转化成非常量指针,并且仍然指向原来的对象;
- 常量引用被转换成非常量引用,并且仍然指向原来的对象;
- 常量对象被转换成非常量对象。
- static和const并用,在外部初始化。
class A{
public: A() {}
private: static const int i: file:
} //必须是静态的
const int A::i = 3;
- 初始化列表
class A{
public: A(int i = 0):test(i) {}
private: const int i:
}
int b = 1;
int &a = b;
a是b的引用,即a是b的别名。
&是引用声明符 地址
若改变a的值,b的值也会随着改变,因为a和b存储在同一存储单元,只是名字不一样而已。同一个地址。
- 在声明引用变量类型时,必须同时使之初始化,即声明它是谁的引用,初始化后,不能再次成为其它变量的引用。
- 引用不能为NULL
- 数据类型
- (int) &a
&a指a的地址,前面int是将*十六进制表示的*地址强制转换为int类型
- 创造对象。任何一个对象创建时,都需要初始化才能使用,所以任何类想要创建实例对象就必须具有构造函数。
- 对象初始化。构造函数可以对对象进行初始化,并且是给与之格式(参数列表)相符合的对象初始化,是具有一定针对性的初始化函数
如果在类中我们不声明构造函数,JVM(Java Virtual Machine,Java虚拟机)会帮我们默认生成一个空参数的构造函数
如果在类中我们声明带参列表的构造函数,JVM就不会帮我们默认生成一个空参数的构造函数。
我们想要使用空参数的构造函数就必须自己去显式的声明一个空参的构造函数
public class student{
private String name;
private String sex;
private int age;
public Student(){
}
public Student(String name, String sex, int age){
this.name = name;
this.sex = sex;
this.age = age;
}
}
实例
Student s = new Student();
s.setName("Ming");
s.setSex("femal");
s.setAge(20);
Student s = New Student("Ming", "femal", 20);
void* malloc(unsigned size);
分配的内存位于堆中,并且没有初始化内存内容,因此基本上使用malloc之后调用函数memset初始化这部分内存空间。
在内存的动态存储区域中分配一块长度为size字节的连续区域,参数size为需要内存空间的长度,返回该区域的首地址。
void* calloc(size_t numElements, size_t sizeOfElement);
将初始化这部分内存设置为0。
与malloc相似,numElements为元素个数,参数sizeOfElement为申请地址单元的元素长度,即在内存中申请numElements*sizeOfElement字节大小的连续地址空间。
void* realloc(void* ptr, unsigned newsize);
对malloc申请的内存进行大小调整
给一个已经分配了地址的指针重新分配空间,参数ptr为原有的空间地址,newsize是重新申请的地址长度。