**
前言
**
前面的都比较简单,上一篇算是开始变得复杂起来了。不过都是些小操作和小知识,比起需要矩阵论、概率论的算法,还是小巫见大巫。
**
cvtColor色彩空间转换
**
void cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0 );
- 第4个参数是目标图像的通道数,默认0表示目标图像通道为输入图像通道数。
下面写一个BGR转换成灰度图像的示例:
Mat src = imread("E:/File/face.jpg");
Mat gray;
cvtColor(src, gray, COLOR_BGR2GRAY);
imshow("【灰度图像】", gray);
waitKey(0);
可以在COLOR_BGR2GRAY上按F12看源码,这个枚举常量有200多个,就不列举了。
- waitKey必须写在该停留的位置上。比如上面的程序,就不应该在用system(“pause”)等函数来暂停,不然图像加载不出来。
**
core模块的其他常用知识点
**
- Matx是个轻量级Mat,但是是类模板,不能直接使用。必须使用前规定大小,比如2*3的float型的Matx,声明为
Matx23f m1(
1, 2, 3,
4, 5, 6
);
- Vec是Matx的一个派生类,是一个一维的Matx,类似vector。定义为:
template<typename _Tp, int cn> class Vec : public Matx<_Tp, cn, 1>{ ... } ;
typedef Vec<float, 2> Vec2f;
//....
- Opencv中防止内存溢出的函数有:alignPtr、alignSize、allocate、deallocate、fastMalloc、fastFree等
- Opencv中RNG()作用是为初始化随机数状态的生成器
- <base.hpp><fast_math.hpp>等里有计算向量角度的函数fastAtan2、计算立方根的函数cubeRoot、向上取整cvCeil、向下取整cvFloor、四舍五入cvRound等等。类似MATLAB里面的函数,比如cvIsInf判断自变量是否无穷大、cvIsNaN判断自变量是否不是数字(一般传入的double、float型数据都是数字,返回0,但是有例外,返回1)。
float a=fastAtan2(3,2);
cout << "点(3,2)的角度 : " << a << "\n";
float b = cubeRoot(3);
cout << "3的立方根是 :" << b << "\n";
float c = sqrt(4);
cout << "4的平方根是 :" << c << "\n";
int d = cvCeil(23.144);
cout << "23.144向上取整-------意思是不关小数部分多少,取上一位数-------是 :" << d << "\n";
int e = cvFloor(23.999);
cout << "23.999向下取整---------意思是丢掉小数部分--------是 :" << e << "\n";
int f = cvRound(23.555);
cout << "23.555四舍五入是 :" << f << "\n";
cout << cvIsInf(23.4442) << endl;
cout << cvIsNaN(8.9) << endl;
**
基本图形的绘制
**
#include<opencv2/opencv.hpp>
#include<iostream>
#include<cmath>
#define WINDOW_NAME1 "【绘制图1】"
#define WINDOW_NAME2 "【绘制图2】"
#define WINDOW_WIDTH 600
using namespace std;
using namespace cv;
void DrawEllipse(Mat& temp,double angle) {
int thickness = 2;//线宽
int lineType = LINE_8;
ellipse(temp,
Point(WINDOW_WIDTH / 2, WINDOW_WIDTH / 2), //中心点
Size(WINDOW_WIDTH / 4, WINDOW_WIDTH / 16),//大小位于这个Size内
angle, //顺时针旋转角度
0, //开始角度
360, //结束角度 ,顺时针绕一圈,表示椭圆整个弧线
Scalar(255, 129, 0),
thickness,
lineType);
}
void DrawFilledCircle(Mat& temp,Point center) {
int thickness = -1;
int lineType = LINE_4;
circle(temp,
center,
WINDOW_WIDTH / 32,//半径
Scalar(0, 0, 255),
thickness,
lineType);
}
void DrawPolygon(Mat& temp) {
int lineType = LINE_8;
//创建一些点
Point rookPoints[1][20];
rookPoints[0][0] = Point(WINDOW_WIDTH / 4, 7 * WINDOW_WIDTH/8 );
rookPoints[0][1] = Point(3*WINDOW_WIDTH / 4, 7 * WINDOW_WIDTH/8 );
rookPoints[0][2] = Point(3*WINDOW_WIDTH / 4, 13 * WINDOW_WIDTH/16);
rookPoints[0][3] = Point(11*WINDOW_WIDTH / 16, 13 * WINDOW_WIDTH/16 );
rookPoints[0][4] = Point(19*WINDOW_WIDTH / 32, 3 * WINDOW_WIDTH/8 );
rookPoints[0][5] = Point(3*WINDOW_WIDTH / 4, 3 * WINDOW_WIDTH/8 );
rookPoints[0][6] = Point(3*WINDOW_WIDTH / 4, WINDOW_WIDTH/8);
rookPoints[0][7] = Point(26*WINDOW_WIDTH / 40, WINDOW_WIDTH/8 );
rookPoints[0][8] = Point(26 * WINDOW_WIDTH / 40, WINDOW_WIDTH / 4);
rookPoints[0][9] = Point(22*WINDOW_WIDTH / 40, WINDOW_WIDTH/4 );
rookPoints[0][10] = Point(22*WINDOW_WIDTH / 40,WINDOW_WIDTH/8 );
rookPoints[0][11] = Point(18*WINDOW_WIDTH / 40, WINDOW_WIDTH/8 );
rookPoints[0][12] = Point(18*WINDOW_WIDTH / 40, WINDOW_WIDTH/4 );
rookPoints[0][13] = Point(14*WINDOW_WIDTH / 40, WINDOW_WIDTH/4 );
rookPoints[0][14] = Point(14*WINDOW_WIDTH / 40, WINDOW_WIDTH/8 );
rookPoints[0][15] = Point(WINDOW_WIDTH / 4, WINDOW_WIDTH/8 );
rookPoints[0][16] = Point(WINDOW_WIDTH / 4, 3* WINDOW_WIDTH/8 );
rookPoints[0][17] = Point(13*WINDOW_WIDTH / 32,3 * WINDOW_WIDTH/8 );
rookPoints[0][18] = Point(5*WINDOW_WIDTH / 16, 13* WINDOW_WIDTH/16 );
rookPoints[0][19] = Point(WINDOW_WIDTH / 4, 13 * WINDOW_WIDTH/16 );
const Point* ppt[1] = { rookPoints[0] };
int npt[] = { 20 };
fillPoly(temp,
ppt, //多边形顶点集是双重指针
npt, //要绘制的多边形顶点数目
1 , //要绘制的多边形个数
Scalar(255, 255, 255),
lineType);
}
void DrawLine(Mat& temp,Point start,Point end) {
int thickness = 2;
int lineType = LINE_8;
line(temp,
start,
end,
Scalar(0, 0, 0),
thickness,
lineType);
}
int main() {
//创建空Mat图像
Mat atomImg = Mat::zeros(WINDOW_WIDTH, WINDOW_WIDTH, CV_8UC3);
Mat rookImg = atomImg.clone();
//绘制椭圆
for (int i = -1; i < 3; ++i) {
DrawEllipse(atomImg, 45*i);
}
//绘制圆心
DrawFilledCircle(atomImg, Point(WINDOW_WIDTH / 2, WINDOW_WIDTH / 2));
//绘制椭圆
DrawPolygon(rookImg);
//绘制矩形
rectangle(rookImg,
Point(0, 7 * WINDOW_WIDTH / 8),
Point(WINDOW_WIDTH, WINDOW_WIDTH),
Scalar(0, 255, 255),
-1,
8);
//绘制线段
DrawLine(rookImg,
Point(0, 15 * WINDOW_WIDTH / 16),
Point(WINDOW_WIDTH, 15 * WINDOW_WIDTH / 16)
);
DrawLine(rookImg,
Point(WINDOW_WIDTH/4, 7 * WINDOW_WIDTH / 8),
Point(WINDOW_WIDTH/4 , WINDOW_WIDTH )
);
DrawLine(rookImg,
Point(WINDOW_WIDTH/2, 7 * WINDOW_WIDTH / 8),
Point(WINDOW_WIDTH/2 , WINDOW_WIDTH )
);
DrawLine(rookImg,
Point(3*WINDOW_WIDTH / 4, 7 * WINDOW_WIDTH / 8),
Point(3*WINDOW_WIDTH / 4, WINDOW_WIDTH)
);
//显示图像
imshow(WINDOW_NAME1, atomImg);
moveWindow(WINDOW_NAME1, 0, 200);
imshow(WINDOW_NAME2, rookImg);
moveWindow(WINDOW_NAME2, WINDOW_WIDTH, 200);
waitKey(0);
destroyAllWindows();
}
上面的代码里,在使用circle()等函数前,先用中间变量设置传入的参数这部分。看起来是白费功夫,但是这比全部写入函数括号内,更简单易懂。别看只是这么点变化,等到忘记了后再看,会感谢自己写的这么简单(或者怨恨自己为什么不载写简单点)。
还有注释也是,让自己的代码更规范,让初学者也能一眼看懂,这也是保证代码的可维护性的关键一环。
毕竟,就算是英语单词,也有忘记的一天。
文本绘制
void putText( InputOutputArray img,
const String& text,
Point org,
int fontFace,
double fontScale,
Scalar color,
int thickness = 1,
int lineType = LINE_8,
bool bottomLeftOrigin = false );
最后一个参数表示,默认图像数据源位于左上角,否则位于左下角。下面是我得到的结果:
可以自己试试:
string text = "put text on image";
Point p(200, 140);
circle(src, p, 2, Scalar(0, 255, 0));
int fontFace = FONT_HERSHEY_SIMPLEX;//字体类型
cout << "fontFace : " << fontFace << endl;
double fontScale = 1.1;//比例因子
Scalar color(0, 0, 255);
putText(src, text, p, fontFace, fontScale, color,2,8,false);
参考:《Opencv3编程入门》