OpenCV总结

目录

  • 1、简介
    • 1.1、什么是Open CV
    • 1.2、优点
    • 1.3、如何获得Open CV
  • 2、我的第一个Open CV程序
    • 2.1、工具及版本
    • 2.2、opencv安装与环境配置
    • 2.3、将Open CV与Visual Studio 2017关联
    • 2.4、开始第一个项目
  • 3、图像读取、显示与保存
    • 3.1、头文件与命名空间
    • 3.2、imread()函数
    • 3.3、namedWindow()函数
    • 3.4、imshow()函数
    • 3.5、imwrite()函数
    • 3.6、waitKey()函数
    • 3.7、图像属性
    • 3.8、示例程序
    • 3.9、效果展示
  • 4、摄像头/视频文件读写
    • 4.1、VideoCapture类
    • 4.2、VideoWriter类
    • 4.3、读取视频与摄像头示例源代码
    • 4.3、效果展示
  • 5、视频处理实例
    • 5.1、图像批量读取
    • 5.2、视频分解
    • 5.3、多图合并
  • 6、Mat类基础
    • 6.1、常用数据结构
    • 6.2、Mat类基础
  • 7、基本绘图函数
    • 7.1、line()函数
    • 7.2、circle()函数
    • 7.3、rectangle()函数
    • 7.4、ellipse()函数
    • 7.5、fillPoly()/polylines()函数
    • 7.6、putText()函数
    • 7.7、示例源代码
    • 7.8、效果展示
  • 8、鼠标与滑动条操作
    • 8.1、鼠标操作
    • 8.2、滑动条操作
  • 9、鼠标与滑动条实例
    • 9.1、鼠标截图
    • 9.2、滑动条视频播放
  • 10、访问图像像素
    • 10.1、动态地址计算访问
    • 10.2、指针访问
    • 10.4、添加减色效果
    • 10.5、添加雪花效果
  • 11、基本图像运算
    • 11.1、图像加法
    • 11.2、图像减法
    • 11.3、图像乘除法
    • 11.4、图像逻辑运算
  • 12、对比度亮度调整与通道分离
    • 12.1、对比度亮度调整
    • 12.2、通道分离与合并
  • 13、ROI与mask掩码
    • 13.1、感兴趣区域ROI
    • 13.2、ROI图像融合
    • 13.3、mask掩码
  • 14、图像几何变换
    • 14.1、图像缩放
    • 14.2、图像平移
    • 14.3、图像旋转
    • 14.4、转置和镜像
  • 15、图像滤波
    • 15.1、方框滤波
    • 15.2、均值滤波
    • 15.3、高斯滤波
    • 15.4、中值滤波
    • 15.5、双边滤波
    • 15.6、示例
  • 16、图像阈值化
    • 16.1、固定阈值
    • 16.2、自适应阈值
    • 16.3、进度条调节阈值
  • 17、总结

 

1、简介

1.1、什么是Open CV

OpenCV总结_第1张图片

​ OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android和Mac OS操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。

1.2、优点

  • OpenCV致力于真实世界的实时应用
  • 通过优化的C代码的编写对其执行速度带来了可观的提升
  • 并且可以通过购买Intel的IPP高性能多媒体函数库(Integrated Performance Primitives)得到更快的处理速度。

1.3、如何获得Open CV

  • 官网:https://opencv.org/
  • GitHub:https://github.com/opencv/opencv

2、我的第一个Open CV程序

2.1、工具及版本

  • Visual Studio 2017
  • opencv-3.4.0
  • 电脑x64系统(x86系统则配置时选择x86下的文件即可)

2.2、opencv安装与环境配置

  • 打开下载的opencv-3.4.0.exe,选择一个安装的目录,选择Extract(提取)即可。
  • 提取完成后,配置opencv环境变量
    • 环境变量设置路径:右键计算机图标—>属性—>高级系统设置—>环境变量,找到Path变量
    • 将对应opencv安装路径添加至环境变量列表,格式参考:G:\opencv\build\x64\vc15\bin

OpenCV总结_第2张图片

2.3、将Open CV与Visual Studio 2017关联

  • Visual Studio 2017新建一个C++空项目,然后点击【视图】,【其他窗口】,【属性管理器】,然后就弹出一个属性管理器窗口,如下图:

    OpenCV总结_第3张图片

  • 双击打开Debug | x64 文件夹下的Micrsoft.Cpp.x64.user(x86的选择Debug | Win32下的Micrsoft.Cpp.Win32.user ),在下图标注的位置添加包含目录

OpenCV总结_第4张图片

OpenCV总结_第5张图片

  • VC++目录下,包含目录选项,追加以下三条路径
    • G:\opencv\build\include
    • G:\opencv\build\include\opencv
    • G:\opencv\build\include\opencv2
  • 库目录选项,追加一条路径
    • G:\opencv\build\x64\vc15\lib
  • 链接器下,附加依赖项选项,追加一个配置文件
    • opencv_world340d.lib
  • 配置完成,应用变动,确认退出Micrsoft.Cpp.Win32.user配置

2.4、开始第一个项目

  • 将窗口上的解决方案配置设置为Debug,解决方案平台设置为x64(x86系统则设置为x86)

    1584978635227

  • 视图选项 -> 解决方案资源管理器,或者快捷键Ctrl+Alt+L,在源文件夹新建一个C++项目,右键源文件 -> 添加 -> 新建项 -> C++文件,书写代码测试

    #include
    using namespace cv;
    void main() {
        //图片1.jpg存在于项目C++文件的同一目录下
    	Mat img = imread("1.jpg");
    	//显示图片
    	imshow("img",img);
    	waitKey(0);
    }
    
  • 局部效果图

    OpenCV总结_第6张图片

  • 可能出现的问题

    • 丢失opencv-core.dll之类的错误
      • 从G:\opencv\build\bin中将提示丢失的对应文件复制进C:\Windows\SysWOW64文件夹中,可能需要管理员权限

3、图像读取、显示与保存

3.1、头文件与命名空间

#include "opencv2/opencv.hpp" 
using namespace cv;

3.2、imread()函数

  • 函数原型
    • Mat imread( const string& filename, int flags=1 );
  • 函数参数
    • 第一个参数,需要填入图片路径名 ,支持常见的图片格式
    • 第二个参数,指定加载图像的颜色类型,默认为1

3.3、namedWindow()函数

  • 函数原型
    • namedWindow(const string& winname, int flags = WINDOW_AUTOSIZE);
  • 函数参数
    • 第一个参数,设置作为标识的窗口名称
    • 第二个参数,窗口显示方式
      • WINDOW_NORMAL:正常大小显示,大小可调节
      • WINDOW_AUTOSIZE:根据图像大小自动调整
      • WINDOW_OPENGL:支持openGL

3.4、imshow()函数

  • 函数原型
    • imshow(const string& winname, InputArray mat);
  • 函数参数
    • 第一个参数,设置需要显示的窗口名称
    • 第二个参数,填写需要显示的图像

3.5、imwrite()函数

  • 函数原型:
    • bool imwrite( const string& filename, InputArray img,const vector& params=vector());
  • 函数参数
    • 第一个参数,设置保存的文件名,需填写后缀,如"1.bmp"
    • 第二个参数,要保存的Mat类型图像数据
    • 第三个参数,表示特定格式保存的参数编码,一般采用默认值不填写

3.6、waitKey()函数

  • 函数原型:
    • int waitKey(int delay = 0);
  • 函数参数
    • 第一个参数,如果delay>0, 表示等待delay毫秒之后结束
    • 如果delay=0, 表示无限等待,直到有按键按下结束
    • 返回值为对应按下按键的ASCII码值,如Esc的ASCII码为27

3.7、图像属性

  • 基本属性
    • empty() 判断文件读取是否正确
    • rows 获取图像行数(高度)
    • cols 获取图像列数(长度)
    • channels() 获取图像通道数
    • depth() 获取图像位深度

3.8、示例程序

#include
#include 

using namespace cv;
using namespace std;

void main() {
	Mat srcImg = imread("1.jpg");//读取图片
	if (!srcImg.empty()) {
		cout<< "高度:" << srcImg.rows << endl;
		cout << "宽度:" << srcImg.cols << endl;
		cout << "通道数:" << srcImg.channels() << endl;
		cout << "位深度:" << srcImg.depth() << endl;
	}
	cvtColor(srcImg,srcImg,CV_BGR2GRAY);//转化为灰度图
	namedWindow("img",WINDOW_AUTOSIZE);//创建窗口
	imshow("img",srcImg);
	imwrite("1.bmp",srcImg);
	waitKey(0);
}

3.9、效果展示

OpenCV总结_第7张图片

4、摄像头/视频文件读写

4.1、VideoCapture类

对视频文件或摄像头进行视频读取。

  • 构造方法
    • CV_WRAP VideoCapture()
    • CV_WRAP VideoCapture(const string& filename)
    • CV_WRAP VideoCapture(int device)
  • 参数说明
    • 参数filename表示输入视频文件的路径及名称
    • device表示打开摄像头索引号
  • 常用函数
    • open()—打开视频文件或者摄像头
    • isOpened()--判断读取视频文件是否正确,正确返回true
    • release()—关闭视频流文件
    • grab()—抓取下一帧的视频文件或设备
    • Retrieve()—解码并返回视频帧
    • get()—返回指定视频类的相关参数信息
    • set()—设置类信息的一个属性

4.2、VideoWriter类

对视频文件或摄像头进行视频写入磁盘。

  • 写入方法
    • writer.write(frame);
    • writer<
  • 注意事项
    • 写入视频前需安装对应的编解码器
    • 生成视频是否支持彩色应与构造函数设置一致
    • 生成视频尺寸需与读取视频尺寸一致

4.3、读取视频与摄像头示例源代码

#include
using namespace cv;

void main() {
	//读取视频文件,视频文件2.avi与C++文件处于同一目录
	VideoCapture cap("2.avi");
	//读取摄像头
	//VideoCapture cap(0);
	if (!cap.isOpened()) {
		return;
	}
	Mat frame;
	while (1) {
		cap >> frame;
		//Canny(frame, frame, 30, 100);  //Canny边缘检测
		//cvtColor(frame, frame, CV_BGR2HSV); //颜色空间转换到HSV
		if (!frame.empty()) {
			imshow("video", frame);
			if (waitKey(30) == 27) {
				break;
			}
		}
		else
			break;
	}
	cap.release();
}

4.3、效果展示

OpenCV总结_第8张图片

5、视频处理实例

5.1、图像批量读取

char filename[50];
char winName[50];
Mat srcImg;
for(int i = 1; i<30; i++){
    //图片集位于E:\\pic文件夹,命名为 1.bmp、2.bmp ......
    sprintf_s(filename, "E:\\pic\\%d.bmp", i);
    sprintf_s(winName, "NO--%d", i);
    srcImg = imread(filename);
    if(srcImg.empty())
        break;
    imshow(winName, srcImg);
}
waitKey(0);
destroyAllWindows();

5.2、视频分解

Mat frame;
char outfile[50];
VideoCapture cap("E:\\2.avi");
if(!cap.isOpened())  //打开失败
    return;
int totalFrame = cap.get(CV_CAP_PROP_FRAME_COUNT); //获取视频总帧数
for(int i = 1; i<=totalFrame; i++){
    cap>>frame;
    if(frame.empty())
        break;
    sprintf_s(outfile, "E:\\pic\\%d.bmp", i);//规律命名每一帧图片
    imwrite(outfile, frame);//图片写入磁盘文件
    imshow("video", frame);
    waitKey(15);
}
cap.release();
destroyAllWindows();

5.3、多图合并

VideoWriter writer("E:\\out.avi", -1, 20, Size(720, 576), true);
VideoCapture cap;
char filename[50];
Mat frame;
for (int i = 1; i < 400; i++){
    sprintf_s(filename, "E:\\pic\\%d.bmp", i);
    cap.open(filename);
    if (!cap.isOpened())
        break;
    cap >> frame;
    if (frame.empty())
        break;
    writer << frame;
}
waitKey(0);
destroyAllWindows();

6、Mat类基础

6.1、常用数据结构

  • Point类
    • Point类数据结构表示二维坐标系的点,由坐标x, y指定的2D点
    • 定义平面内一点(20,10):Point pt; pt.x = 20; pt.y = 10;
  • Rect类
    • Rect类用来表示矩形,成员有x,y, width, height
    • 成员函数
      • Size()返回值Size表示大小
      • tl()返回左上角坐标
      • area()返回矩形面积
      • br()返回右下角坐标
      • contains(Point)判断点是否在矩形内
      • Inside(Rect)判断矩形是否在该矩形内
  • Size类
    • Size表示区域大小,常用构造函数Size(int _width, int _height)
  • Scalar类
    • Scalar()表示具有四个元素的数组,大量用来传递像素值
    • 一般形式:Scalar(double B, double G, double R, double Alpha)
    • Scalar表示颜色顺序为BGR

6.2、Mat类基础

  • 简介

    • Mat是一个类,由两个数据部分组成:矩阵头(大小,通道,数据类型等)和数据块(像素值)。
    • Mat头部属性如:rows,cols,channels,data。data是一个指向数据块的指针,可以用empty()方法判断图像是否为空
  • Mat类创建

    • Mat img; //创建无初始化矩阵
    • Mat img1(20,10,CV_8UC1); //创建20行10列类型为8位的单通道矩阵
    • Mat img2(Size(0,10),CV8UC3); /创建大小为20x10类型为8位的3通道矩阵
    • Mat img3(20,10,CV 8UC3,Scalar(0,255,0));//创建大小为10x20的8位3通道矩阵
    • Mat img4(20,10,CV_8UC1,Scalar(255));/创建大小为10x20的8位单通道矩阵
    • Mat img5(img4);//将img4赋值给img5,共享数据对象

7、基本绘图函数

7.1、line()函数

  • 绘制直线
  • CV_EXPORTS_W void line(InputOutputArray img, Point pt1, Point pt2, const Scalar& color,
    int thickness = 1, int lineType = LINE_8, int shift = 0);

7.2、circle()函数

  • 绘制圆
  • CV_EXPORTS_W void circle(InputOutputArray img, Point center, int radius,
    const Scalar& color, int thickness = 1,
    int lineType = LINE_8, int shift = 0);

7.3、rectangle()函数

  • 用于绘制矩形
  • CV_EXPORTS_W void rectangle(InputOutputArray img, Point pt1, Point pt2,
    const Scalar& color, int thickness = 1,
    int lineType = LINE_8, int shift = 0);

7.4、ellipse()函数

  • 绘制椭圆
  • CV_EXPORTS_W void ellipse(InputOutputArray img, Point center, Size axes,
    double angle, double startAngle, double endAngle,
    const Scalar& color, int thickness = 1,
    int lineType = LINE_8, int shift = 0);

7.5、fillPoly()/polylines()函数

  • 绘制多边形
  • CV_EXPORTS_W void fillPoly(InputOutputArray img, InputArrayOfArrays pts,
    const Scalar& color, int lineType = LINE_8, int shift = 0,
    Point offset = Point() );

7.6、putText()函数

  • 添加文字
  • CV_EXPORTS_W 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 );

7.7、示例源代码

Mat img(300, 300, CV_8UC3, Scalar(0, 0, 0));
line(img, Point(10, 10), Point(200, 200), Scalar(0, 255, 255), 10, 8);  //画线
circle(img, Point(150, 150), 100, Scalar(255, 255, 0), -1, 8);  //画圆
rectangle(img, Point(10, 10), Point(240, 200), Scalar(0, 0, 255), 2, 8);  //画矩形
rectangle(img, Rect(10, 10, 230, 190), Scalar(0, 0, 255), -1, 8); //填充矩形
ellipse(img, Point(150, 150), Size(100, 50), 45, 0, 360, Scalar(0, 255, 255), -1, 8); //画椭圆
ellipse(img, RotatedRect(Point(150, 150), Size(100, 50), 0), Scalar(0, 255, 0), 2, 8);
Point ppt[] = { Point(120, 50), Point(180, 50), Point(210, 100), Point(180, 150), Point(120, 150), Point(90, 100) };
const Point* pts[] = { ppt };
int npt[] = { 6 };
fillPoly(img, pts, npt, 1, Scalar(0, 255, 255), 8); //画填充多边形
polylines(img, pts, npt, 1, true, Scalar(0, 154, 209), 2, 8);  //画非填充多边形
putText(img, "China", Point(100, 100), CV_FONT_HERSHEY_COMPLEX, 2, Scalar(0, 255, 255), 2, 8);//添加文字
imshow("image",img);
waitKey(0);

7.8、效果展示

OpenCV总结_第9张图片

8、鼠标与滑动条操作

8.1、鼠标操作

  • 指定鼠标操作消息回调函数

  • 原型: setMouseCallback(const string& winname,MouseCallback onMouse,void* userdata=0)

    • winname-----窗口名
    • onMouse-----鼠标事件时被调用的函数指针,
      • 原型形式:void Fun(int event, int x, int y, int flags, void* param);
        • event设置触发方式(鼠标进入,按下,抬起等待)
        • x和y是鼠标指针在图像坐标系的坐标
    • userdata -----用户定义传到回调函数的参数,默认值0
  • 示例源代码

    #include
    using namespace cv;
    
    Mat img(500, 500, CV_8UC3, Scalar(255, 255, 255));
    Point pt;
    
    //鼠标回调函数,名称可变,但是参数不可变
    void onMouse(int event, int x, int y, int flag, void *param) {
    	if (event == CV_EVENT_LBUTTONDOWN) {//鼠标左键按下,画出圆形
    		circle(img, Point(x, y), 100, Scalar(0, 0, 255), 2, 8);		
    	}
    	else if (event == CV_EVENT_RBUTTONDOWN) {//鼠标右键按下,记录按下点
    		pt.x = x;
    		pt.y = y;
    	}
    	else if (event == CV_EVENT_RBUTTONUP) {//鼠标右键抬起,画出矩形框
    		rectangle(img,Point(pt.x, pt.y), Point(x, y), Scalar(0, 255, 255), 2, 8);
    	}
    }
    void main() {
    	//鼠标点击调用
    	namedWindow("Mouse",WINDOW_AUTOSIZE);
    	setMouseCallback("Mouse", onMouse, 0);
    	while (1) {
    		imshow("Mouse", img);
    		if(27==waitKey(20))
    			break;
    	}
    }
    

8.2、滑动条操作

  • 创建滑动条并指定回调函数

  • 原型:createTrackbar(const string& trackbarname,const string& winname,int* value,int count,TrackbarCallback onChange=0,void* userdata=0)

    • trackbarname-----滚动条名称
    • winname-----滚动条所依附的窗口名称(namedWindow创建)
    • value----指向型指针,表示滑动块位置
    • count---滑动块最大位置,默认最小为0
    • onChange----指向回调函数的指针,原型必须为void xxx(int, void*);
    • userdata -----用户传给回调函数的数据,默认值0
  • 获得滚动条当前位置

    • int getTrackbarPos(const string& trackbarname,const string& winname);
  • 示例源代码

    #include
    using namespace cv;
    
    Mat srcImg = imread("1.jpg", 0);
    Mat desImg;
    int value = 20;
    //滚动条回调函数
    void onchange(int value, void *param) {
    	//threshold(srcImg,desImg,value,255,THRESH_BINARY);//灰度
    	Canny(srcImg, desImg, value, 255);//边缘检测
    	imshow("TrackBar", desImg);
    }
    void main() {
    	//滚动条
    	namedWindow("TrackBar",WINDOW_AUTOSIZE);
    	//threshold(srcImg, desImg, value, 255, THRESH_BINARY);
    	createTrackbar("Threshlod","TrackBar",&value,255,onchange,0);
    	Canny(srcImg, desImg, value, 255);//边缘检测
    	imshow("TrackBar", desImg);
    	waitKey(0);
    }
    

9、鼠标与滑动条实例

9.1、鼠标截图

  • 主要功能

    • 鼠标左键按下拖动显示轨迹,鼠标左键弹起显示截图并保存截图到本地。
  • 源程序

    #include
    #include
    using namespace cv;
    using namespace std;
    
    Mat img = imread("1.jpg");
    Mat temp = img.clone();
    Mat ROI;
    bool flag1 = false;
    Point pt;
    //鼠标监测事件
    void onMouse(int event,int x,int y,int flag,void *param) {
    	switch (event)
    	{
    	case CV_EVENT_LBUTTONDOWN:
    		pt.x = x;
    		pt.y = y;
    		flag1 = true;
    		break;
    	case CV_EVENT_MOUSEMOVE:
    		if (flag1) {
    			temp.copyTo(img);
    			rectangle(img,Point(pt.x,pt.y),Point(x,y),Scalar(0,0,255),2,8);
    		}
    		break;
    	case CV_EVENT_LBUTTONUP:
    		flag1 = false;
    		temp.copyTo(img);
    		ROI = img(Rect(pt.x,pt.y,abs(x - pt.x),abs(y-pt.y)));
    		imshow("ROI",ROI);
    		break;
    	default:
    		break;
    	} 
    }
    void main() {
    	namedWindow("Mouse",WINDOW_AUTOSIZE);
    	setMouseCallback("Mouse",onMouse,0);
    	while (1) {
    		imshow("Mouse",img);
    		if (27 == waitKey(20)) {
    			break;
    		}
    	}
    }
    
  • 效果图

9.2、滑动条视频播放

  • 主要功能

    • 视频播放时,滑动条同时显示播放帧的位置和视频帧率,滑动条拖动时可以实现同步指定帧播放
  • 源程序

    #include
    #include
    using namespace cv;
    using namespace std;
    
    int value = 20;//记录滑动块位置
    void onchange(int value,void *param) {
    	VideoCapture cap = *(VideoCapture *)param;//强制转换指针类型
    	cap.set(CV_CAP_PROP_POS_FRAMES,value);
    }
    
    void main() {
    	VideoCapture cap("2.avi");
    	int frameCount = cap.get(CV_CAP_PROP_FRAME_COUNT);//视频总帧数
    	Mat frame;
    	if (!cap.isOpened()) {//视频打开失败
    		return;
    	}
    	namedWindow("video",WINDOW_AUTOSIZE);
    	createTrackbar("帧数","video",&value,frameCount,onchange,&cap);
    	while (1) {
    		cap >> frame;
    		int pos = cap.get(CV_CAP_PROP_POS_FRAMES);
    		setTrackbarPos("帧数", "video", pos);
    		if (frame.empty()) {
    			break;
    		}
    		imshow("video",frame);
    		if (27 == waitKey(30)) {
    			break;
    		}
    	}
    	cap.release();
    	destroyAllWindows();
    }
    
  • 效果图

10、访问图像像素

10.1、动态地址计算访问

  • 核心代码

    Mat img = imread("1.jpg");
    Mat dst = img.clone();//图像克隆/复制
    int rows = dst.rows;//记录图像行数
    int cols = dst.cols;//记录图像列数
    for (int i = 0; i < rows; i++) {
        for (int j = 300; j < cols; j++) {
            //彩色图像 image.at(i,j)[channel] = value;
            //灰度图像 image.at(i,j)= value;
            dst.at(i, j)[0] = 0;//访问第i行第j列像素蓝色通道
            dst.at(i, j)[1] = 255;//访问第i行第j列像素绿色色通道
            dst.at(i, j)[2] = 0;//访问第i行第j列像素红色通道
        }
    }
    

10.2、指针访问

  • 核心代码

    int rowNumber = img.rows;//行数
    int colNumber = img.cols*img.channels();//列数*通道数=每一行元素个数
    for (int i = 0; i < rowNumber; i++) {
        uchar * data = dst.ptr(i);//获取第i列的首元素地址
        for (int j = 0; j < colNumber; j++) {
            switch (j%3){
                case 0:data[j] = 0;
                    break;
                case 1:data[j] = 255;
                    break;
                case 2:data[j] = 0;
                    break;
                default:
                    break;
            }
        }
    }
    

10.3、迭代器访问

  • 核心代码

    Mat_::iterator it = dst.begin();//初始位置
    Mat_::iterator itend = dst.end();//终止位置
    for (; it != itend; ++it) {
        (*it)[0] = 0;//蓝色通道
        (*it)[1] = 255;//绿色通道
        (*it)[0] = 0;//红色通道
    }
    

10.4、添加减色效果

  • 核心代码

    data[j] = data[j]/64*64+20;//注意data[j]/64*64 <=data[j]
    

10.5、添加雪花效果

  • 核心代码

    for(int k=0;k<4000;k++){
        int i=rand() % img.rows;
        int j=rand() % img.cols;
        dst.at(i, j)[0] = 255;//访问第i行第j列像素蓝色通道
        dst.at(i, j)[1] = 255;//访问第i行第j列像素绿色色通道
        dst.at(i, j)[2] = 255;//访问第i行第j列像素红色通道
    }
    

11、基本图像运算

11.1、图像加法

  • 常用函数

    • +,add(), addWeighted()
  • 示例

    Mat img1, img2;
    Mat dst;
    dst = img1 +img2;
    add(img1, img2, dst);
    addWeighted(img1, 0.5, img2, 0.5, 0, dst); //设置加的权值
    

11.2、图像减法

  • 常用函数

    • -,subtract(), absdiff()
  • 示例

    Mat img1, img2;
    Mat dst;
    dst = img1 -img2;
    subtract(img1, img2, dst);
    absdiff(img1, img2, dst); 
    

11.3、图像乘除法

  • 常用函数

    • *、/
  • 示例

    Mat img1, img2;
    Mat dst;
    dst = A * img1;
    dst = img1 /A;
    

11.4、图像逻辑运算

  • 常用函数

    • bitwise_and(img1,img2,dst) 与运算
    • bitwise_or(img1,img2,dst) 或运算
    • bitwise_not(img1,dst) 非运算
    • bitwise_xor(img1,img2,dst) 异或运算
  • 示例

    bitwise_and(img1,img2,dst);//与运算
    bitwise_or(img1, img2, dst);//或运算
    bitwise_not(img1,dst);//非运算
    bitwise_xor(img1, img2, dst);//异或运算
    

12、对比度亮度调整与通道分离

12.1、对比度亮度调整

  • 原理: g(x) = a * f(x) + b

    • 参数f(x)表示原图像像素
    • 参数g(x)表示输出图像像素
    • 参数a(a>0),被称为增益(gain), 通常用来控制图像的对比度
    • 参数b通常被称为偏置(bias), 通常用来控制图像的亮度
  • 示例源程序

    #include
    #include
    
    using namespace std;
    using namespace cv;
    
    
    int constast_value = 20;//对比度初始值
    int bright_value = 20;//亮度初始值
    
    void onchange(int value, void *param) {
    	Mat img = *(Mat *)param;
    	Mat dst(img.size(),img.type());//创建跟img大小一致的图形
    	int rows = img.rows;
    	int cols = img.cols;
    	for (int i = 0; i < rows; i++) {
    		for (int j = 0; j < cols; j++) {
    			//saturate_cast()函数用于防止溢出,data<0?0:data data>255?255:data
    			dst.at(i, j)[0] =saturate_cast( img.at(i, j)[0] * constast_value*0.01 + bright_value);
    			dst.at(i, j)[1] = saturate_cast(img.at(i, j)[1] * constast_value*0.01 + bright_value);
    			dst.at(i, j)[2] = saturate_cast(img.at(i, j)[2] * constast_value*0.01 + bright_value);
    		}
    	}
    	imshow("效果图",dst);
    }
    void main() {
    	Mat img = imread("1.jpg");
    	namedWindow("效果图",WINDOW_AUTOSIZE);
    	createTrackbar("对比度","效果图",&constast_value,300,onchange,&img);
    	createTrackbar("亮度", "效果图", &bright_value, 300, onchange, &img);
    	onchange(constast_value,&img);
    	onchange(bright_value, &img);
    }
    

12.2、通道分离与合并

  • 通道分离:split()函数

    • CV_EXPORTS void split(const Mat& src,Mat * nvbegin);
    • CV_EXPORTS void split(const Mat& m,vector& mv);
  • 示例程序

    void channelsSplit() {
    	Mat img = imread("1.jpg");
    	vector channels;
    	Mat blueChannel, greenChannel, redChannel;
    	split(img,channels);
    	blueChannel = channels.at(0);
    	greenChannel = channels.at(1);
    	redChannel = channels.at(2);
    	imshow("Blue",blueChannel);
    	imshow("Green",greenChannel);
    	imshow("Red",redChannel);
    }
    
  • 通道合并:merge()函数

    • CV_EXPORTS void merge(const Mat* mv,size_t count,OutputArray dst);
    • CV_EXPORTS void merge(const vector& mv,OutputArray dst);
  • 示例程序

    void channelsMerge() {
    	Mat img = imread("1.jpg");
    	Mat mergeImg = Mat::zeros(img.size(),img.type());
    	vector channels;
    	Mat blueChannel, greenChannel, redChannel;
    	split(img, channels);
    	blueChannel = channels.at(0);
    	greenChannel = channels.at(1);
    	redChannel = channels.at(2);
    	//对每个通道进行二值化处理
    	threshold(blueChannel,blueChannel,100,255,THRESH_BINARY);
    	threshold(greenChannel, greenChannel, 100, 255, THRESH_BINARY);
    	threshold(redChannel,redChannel,100,255,THRESH_BINARY);
    	//进行通道合并
    	merge(channels,mergeImg);
    	imshow("Merge",mergeImg);
    }
    

13、ROI与mask掩码

13.1、感兴趣区域ROI

  • 介绍

    • 作用:能够确定分析重点,减少处理时间,增加精度。
    • 定义方法:使用Rect表示矩形区域或用Range设定行列范围
  • 源程序示例

    #include 
    using namespace cv;
    
    void main() {
    	Mat img = imread("1.jpg");
    	Mat ROI;
    	//ROI = img(Rect(100,100,200,200));//Rect矩形区域,x,y,w,h
    	ROI = img(Range(300,300+200),Range(300,300+200));//Range行列范围
    	imshow("img",img);
    	imshow("ROI",ROI);
    	waitKey(0);
    }
    

13.2、ROI图像融合

  • 简单融合:将图片添加到另一张图片上方

    • 使用copyTo()方法

      Mat img = imread("1.jpg");
      Mat logo = imread("logo.png");
      Mat ROI = img(Rect(10,10,logo.cols,logo.rows));
      logo.copyTo(ROI);
      imshow("ROI",ROI);
      imshow("img",img);
      

13.3、mask掩码

  • 特点

    • lmask—(掩码)---是一个8位单通道图像(灰度图/二值图)
    • 掩码某个位置如果为0,则在此位置上的操作不起作用
    • 掩码某个位置如果不为0,则在此位置上的操作会起作用
  • 高级融合:去除底色,将无背景的logo添加至另一张图

    • 使用copyTo()方法
    Mat img = imread("1.jpg");
    Mat logo = imread("logo.png");
    Mat mask = imread("logo.png",0);//转为灰度图
    bitwise_not(mask, mask);//图像取反操作
    threshold(mask, mask, 100, 255, THRESH_BINARY);//二值化处理
    Mat ROI;
    ROI = img(Rect(20,20,logo.cols,logo.rows));
    //logo复制到ROI位置,使用利用logo生成的掩码,相当于抠图
    logo.copyTo(ROI, mask);//使用了mask掩码操作
    imshow("ROI",ROI);
    imshow("img",img);
    

14、图像几何变换

14.1、图像缩放

  • resize()函数

  • 原型:resize(InputArray src,OutputArray dst,Size dsize,double fx=0,double fy=0,int interpolation=INTER_LINEAR);

    • src: 输入图像,Mat类型即可
    • dst: 输出图像,当其非0时,由dsize确定尺寸
    • dsize: Size类型,指定输出图像大小
    • fx: 沿水平方向的缩放系数
    • fy: 沿垂直方向的缩放系数
    • interpolation: 用于指定插值方式,默认为INTER_LINEAR(线性插值)
  • 示例代码

    ex1:
    Mat dstImg = Mat::zeros(512, 512, CV_8UC3);//建立一张512*512像素的彩色图
    Mat srcImg = imread(“1.jpg”);
    resize(srcImg, dstImg, dstImg.size());//缩放至目标图大小
    
    ex2:
    Mat dstImg ;
    Mat srcImg = imread(“1.jpg”);
    resize(srcImg, dstImg, Size(), 0.5, 0.5);//自动大小,水平与竖直方向缩放0.5
    

14.2、图像平移

  • 不改变图片大小

    Mat imageTranslate(Mat &src, int xOffset, int yOffset) {
    	int rows = src.rows;
    	int cols = src.cols;
    	Mat dst = Mat::zeros(src.size(), src.type());
    	for (int i = 0; i < rows; i++) {
    		for (int j = 0; j < cols; j++) {
    			int x = j + xOffset;//偏移量
    			int y = i + yOffset;
    			if (x < cols&& y < rows &&x>=0 && y>=0) {
    				dst.at(y, x) = src.at(i, j);
    			}
    		}
    	}
    	return dst;
    }
    
  • 改变图片大小

    Mat imageTranslate(Mat &src, int xOffset, int yOffset) {
    	int rows = src.rows +abs(yOffset);
    	int cols = src.cols +abs(xOffset);
        Mat dst = Mat::zeros(rows,cols,src.type());
        ......
    }
    

14.3、图像旋转

  • 函数getRotationMatrix2D()、warpAffine()

    void picMove() {
    	Mat img = imread("1.jpg");
    	Point2f center = Point2f(img.cols / 2, img.rows / 2);//中心点
    	double angle = 45;//旋转角度
    	double scale = 0.5;//缩放尺度
    
    	Mat rotateMat;
    	rotateMat = getRotationMatrix2D(center,angle,scale);
    	Mat rotateImg;
    	warpAffine(img, rotateImg, rotateMat, Size(1200, 1800));
    	imshow("dst",rotateImg);
    }
    

14.4、转置和镜像

  • 用到的函数 transpose()、flip(),可以实现转置和镜像变换,以及90°,180°旋转

    void TransposeAndFlip() {
    	Mat img = imread("1.jpg");
    	Mat dst;
    	//transpose(img,dst);//沿主对角线翻转
    	flip(img,dst,0);//flipCode = 0,沿x轴翻转,>0 沿y轴翻转,<0 水平垂直翻转
    	imshow("dst",dst);
    }
    

15、图像滤波

15.1、方框滤波

  • 函数:boxFilter()
  • 原型:boxFilter(InputArray src,OutputArray dst,int ddepth,Size ksize,Point anchor=Point(-1,-1))
    • lddepth: 输出图像的深度, -1代表使用原图像深度,即src.depth()
    • ksize: Size类型表示内核大小,一般用Size(w,h)表示内核大小, Size(3,3)表示3x3的核大小
    • anchor: 表示锚点(即被平滑的那个点), 默认值Point(-1, -1),表示锚点在核中心
    • normalize: 默认值true, 标识符, 表示内核是否被归一化
    • borderType: 图像像素边界模式,一般用默认值即可

15.2、均值滤波

  • 函数:blur()
  • 原型:blur(InputArray src,OutputArray dst,Size ksize,Point anchor=Point(-1,-1),int borderType=BORDER_DEFAULT)
    • ksize: Size类型表示内核大小,一般用Size(w,h)表示内核大小, Size(3,3)表示3x3的核大小
    • anchor: 表示锚点(即被平滑的那个点), 默认值Point(-1, -1),表示锚点在核中心
    • borderType: 图像像素边界模式,一般用默认值

15.3、高斯滤波

  • 函数:blurGaussianBlur()
  • 原型:GaussianBlur(InputArray src,OutputArray dst,Size ksize,double sigmaX,double sigmaY=0,int borderType=OBRDER_DEFAULT);
    • ksize: 高斯内核大小,一般用Size(w,h)表示内核大小, w, h可以不同, 但是必须为正奇数或者0
    • sigmaX: 表示高斯函数在X方向上的标准偏差
    • sigmaY: 表示高斯函数在Y方向上的标准偏差, 若sigmaY=0, 就将它设置为sigmaX;
    • borderType: 图像像素边界模式,一般用默认值即可

15.4、中值滤波

  • 函数:medianBlur()
  • 原型:medianBlur(InputArray src,OutputArray dst,int ksize)
    • ksize: int类型的孔径的线性尺寸, 大于1的奇数

15.5、双边滤波

  • 函数:bilateralFilter()
  • 原型:bilateralFilter(InputArray src,OutputArray dst,int d,double sigmaColor,double sigmaSpace,int borderType=BORDER_DEFAULT)
    • d: 表示过滤过程中每个像素的邻域直径
    • sigmaColor: 颜色空间滤波器sigma值, 值越大表面该像素邻域内有越广泛的颜色会混到一起,产生较大的半相等颜色区域
    • sigmaSpace: 坐标空间中滤
    • borderType: 图像像素边界模式,一般用默认值即可

15.6、示例

  • 源程序

    #include
    using namespace cv;
    
    void main() {
    	Mat src = imread("1.jpg");
    	Mat dst;
    	//方框滤波
    	boxFilter(src, dst, -1, Size(3, 3), Point(-1, -1), true);
    	//均值滤波
    	blur(src, dst, Size(5, 5));
    	//高斯滤波
    	GaussianBlur(src,dst,Size(5,5),1);
    	//中值滤波
    	medianBlur(src,dst,3);
    	//双边滤波
    	bilateralFilter(src,dst,5,10.0,2.0);
    	imshow("dst", dst);
    	waitKey(0);
    }
    

16、图像阈值化

16.1、固定阈值

  • 函数:threshold()

  • 原型:double threshold(InputArray src,OutputArray dst,double thresh,double maxval,int type);

    • lsrc: 单通道图像(灰度图或二值图)
    • dst: 输出图像要求和src一样的尺寸和类型
    • thresh: 给定的阈值
    • maxval: 第五个参数设置为CV_THRESH_BINARY或 CV_THRESH_BINARY_INV 阈值类型的最大值
  • 示例代码

    threshold(src,dst,120,255,CV_THRESH_BINARY);//120-255的值为1,其他为0
    

16.2、自适应阈值

  • 函数:adaptiveThreshold()

  • 原型:adaptiveThreshold(InputArray src,OutputArray dst,double maxValue,int adaptiveMethod,int thresholdType,int blockSize,double C)

    • src: 单通道图像(灰度图或二值图)
    • dst: 输出图像要求和src一样的尺寸和类型
    • maxValue:使用 CV_THRESH_BINARY 和 CV_THRESH_BINARY_INV 的最大值
    • adaptiveMethod: 指定自适应阈值算法, 可取值为CV_ADAPTIVE_THRESH_MEAN_C 或CV_ADAPTIVE_THRESH_GAUSSIAN_C
    • thresholdType: 取阈值类型取值必须为CV_THRESH_BINARY、CV_THRESH_BINARY_INV二者之一
    • blockSize: 用来计算阈值的邻域大小3, 5, 7,…
    • C: 减去平均或加权平均后的常数值
  • 示例代码

    //注意src图片需要为灰度图
    adaptiveThreshold(src,dst,255,ADAPTIVE_THRESH_GAUSSIAN_C,CV_THRESH_BINARY,11,5);
    

16.3、进度条调节阈值

  • 示例程序

    #include
    using namespace cv;
    
    int fixvalue = 20;
    int blocksize = 5;
    int c = 5;
    Mat dst;
    void onchange(int, void * param) {
    	Mat src = *(Mat *)param;
    	threshold(src, dst, fixvalue, 255, THRESH_BINARY);
    	if (blocksize % 2 == 0)
    		blocksize++;
    	adaptiveThreshold(src, dst, 255, ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, blocksize, c);
    	imshow("固定阈值",dst);
    	imshow("自适应阈值", dst);
    }
    void main() {
    	Mat img = imread("1.jpg", 0);
    	namedWindow("固定阈值", WINDOW_AUTOSIZE);
    	namedWindow("自适应阈值", WINDOW_AUTOSIZE);
    	createTrackbar("fixvalue", "固定阈值", &fixvalue, 255, onchange, &img);
    	createTrackbar("blocksize", "自适应阈值", &blocksize, 100, onchange, &img);
    	createTrackbar("c", "自适应阈值", &c, 100, onchange, &img);
    
    	onchange(fixvalue, &img);
    	onchange(blocksize, &img);
    	onchange(c, &img);
    	imshow("img", img);
    	waitKey(0);
    }
    

17、总结

  • 简单的学习了一下Open CV,懂得了一些新的知识,包括图像的各种简单的处理、进度条的操作等,总结学习的知识体系,为以后的深入学习打下基础。

你可能感兴趣的:(opencv,图像处理,视频处理,计算机视觉)