OpenCV之C++入门
1、Visual Studio安装及环境配置与搭建
登录账号下载即可,建议下载Visual Studio 2017 专业版,本教程使用该版本完成
该教程笔记是本人整理的OpenCV学堂视频教程内容,感谢贾志刚老师的视频教程,下面是OpenCV 4.5.4及源码下载链接
链接:https://pan.baidu.com/s/1HmWrX35P774rr6tlfUXB2A 提取码:urtd
- 配置系统环境变量,鼠标右键我的电脑,选择属性,之后按下图操作,复制opencv目录下的bin目录,vs2017选择vc15
- 安装完毕后,新建第一个项目如下图
- 右键源文件选择新建项新建一个main.cpp
- 添加包含目录、库目录及附加依赖项
- 在D盘下新建一个images文件夹,放入一张图片,图片名与下面代码段中的图片名字一致
- 在main.cpp中输入以下代码
#include<opencv2/opencv.hpp> #include<iostream> using namespace cv; using namespace std; int main(int argc, char**argv) { Mat src = imread("D:/images/lena.jpg"); imshow("input", src); waitKey(0); destroyAllWindows(); return 0; }
- 点击
调试
→开始调试
,如果出现下图则表示运行成功,配置成功
至此,Visual Studio的准备工作完成!
2、图像基本操作
多行注释快捷键:Ctrl + K + Ctrl + C
2.1、图像读取与显示
#include<opencv2/opencv.hpp> #include<iostream> using namespace cv; using namespace std; int main(int argc, char**argv) { //imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作 Mat src = imread("D:/images/lena.jpg",IMREAD_GRAYSCALE); //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径 if (src.empty()){ printf("could not load image...\n"); return -1; } namedWindow("输入窗口",WINDOW_FREERATIO); //不管图片大小,都能进行调整,图像很小可以不使用这个函数 imshow("输入窗口", src); //第一个参数为窗口名,imshow()只支持显示8位图像及浮点图像 waitKey(0); //窗口停留时间,0为一直停留,数值为停留的毫秒数 destroyAllWindows(); //关闭所有打开的窗口 return 0; }
2.2、图像色彩空间转换
新建一个头文件quickopencv.h
#pragma once #include<opencv2/opencv.hpp> using namespace cv; class QuickDemo { public: void colorSpace_Demo(Mat &image); };
添加该项目包含目录为当前文件夹,操作如下
新建一个源文件quickdemo.cpp
#include<quickopencv.h> void QuickDemo::colorSpace_Demo(Mat &image) { Mat gray, hsv; cvtColor(image, hsv, COLOR_BGR2HSV); // H 0~180 S 0~255 V 0~255 cvtColor(image, gray, COLOR_BGR2GRAY); imshow("HSV", hsv); imshow("灰度", gray); imwrite("D:/images/hsv.png", hsv); imwrite("D:/images/gray.png", gray); }
修改源文件test440,进行调试
#include<opencv2/opencv.hpp> #include<quickopencv.h> #include<iostream> using namespace cv; using namespace std; int main(int argc, char**argv) { //imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作 // B,G,R Mat src = imread("D:/images/lena.jpg"); //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径 if (src.empty()) { printf("could not load image...\n"); return -1; } //namedWindow("输入窗口", WINDOW_FREERATIO); //不管图片大小,都能进行调整,图像很小可以不使用这个函数 imshow("输入窗口", src); //第一个参数为窗口名 //引入类QuickDemo,调用方法 QuickDemo qd; qd.colorSpace_Demo(src); waitKey(0); //窗口停留时间,0为一直停留,数值为停留的毫秒数 destroyAllWindows(); //关闭所有打开的窗口 return 0; }
效果
2.3、图像对象的创建与赋值
quickopencv.h
#pragma once #include<opencv2/opencv.hpp> using namespace cv; class QuickDemo { public: void colorSpace_Demo(Mat &image); void mat_creation_demo(); };
quickdemo.cpp
#include<quickopencv.h> void QuickDemo::colorSpace_Demo(Mat &image) { Mat gray, hsv; cvtColor(image, hsv, COLOR_BGR2HSV); // H 0~180 S 0~255 V 0~255 cvtColor(image, gray, COLOR_BGR2GRAY); imshow("HSV", hsv); imshow("灰度", gray); imwrite("D:/images/hsv.png", hsv); imwrite("D:/images/gray.png", gray); } void QuickDemo::mat_creation_demo() { //克隆和复制才会创建新的对象,赋值不会创建新的对象 //Mat m1, m2; //m1 = image.clone(); //image.copyTo(m2); // 创建空白图像 Mat m3 = Mat::ones(Size(512, 512), CV_8UC3); m3 = Scalar(127, 127, 127); // 为像素赋予指定的值 B,G,R顺序 std::cout << "width: " << m3.cols << " height: " << m3.rows << " channels: " << m3.channels() << std::endl; //std::cout << m3 << std::endl; Mat m4 = m3; //赋值后m4改变,会引起m3改变,clone或copyTo则会创建新对象,不影响原对象 m4 = Scalar(0, 255, 255); imshow("创建图像", m3); Mat kernel = (Mat_<char>(3, 3) << 0,-1,0, // 3*3卷积核 -1,5,-1, 0,-1,0); }
test440.cpp
#include<opencv2/opencv.hpp> #include<quickopencv.h> #include<iostream> using namespace cv; using namespace std; int main(int argc, char**argv) { // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作 // B,G,R Mat src = imread("D:/images/lena.jpg"); //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径 if (src.empty()) { printf("could not load image...\n"); return -1; } //namedWindow("输入窗口", WINDOW_FREERATIO); //不管图片大小,都能进行调整,图像很小可以不使用这个函数 imshow("输入窗口", src); //第一个参数为窗口名 QuickDemo qd; qd.mat_creation_demo(); waitKey(0); //窗口停留时间,0为一直停留,数值为停留的毫秒数 destroyAllWindows(); //关闭所有打开的窗口 return 0; }
效果
2.4、图像像素的读写操作
quickopencv.h
#pragma once #include<opencv2/opencv.hpp> using namespace cv; class QuickDemo { public: void colorSpace_Demo(Mat &image); void mat_creation_demo(); void pixel_visit_demo(Mat &image); };
quickdemo.cpp
#include<quickopencv.h> void QuickDemo::pixel_visit_demo(Mat &image) { int w = image.cols; int h = image.rows; int dims = image.channels(); //for (int row = 0; row < h; row++) { // for (int col = 0; col < w; col++) { // if (dims == 1) { //灰度图像 // int pv = image.at<uchar>(row, col); //row,col → y,x // image.at<uchar>(row, col) = 255 - pv; //对像素值反转,image.at<uchar>为获取某点格式为uchar的像素值 // } // if (dims == 3) { //彩色图像 // Vec3b bgr = image.at<Vec3b>(row, col); //Vec3b为bgr图像像素点存储格式,对像素值进行反转 // image.at<Vec3b>(row, col)[0] = 255 - bgr[0]; // image.at<Vec3b>(row, col)[1] = 255 - bgr[1]; // image.at<Vec3b>(row, col)[2] = 255 - bgr[2]; // } // } //} for (int row = 0; row < h; row++) { uchar* current_row = image.ptr<uchar>(row); //获取当前行最初位置的指针 for (int col = 0; col < w; col++) { if (dims == 1) { //灰度图像 int pv = *current_row; *current_row++ = 255 - pv; //每次运算完,指针右移一位 } if (dims == 3) { //彩色图像 *current_row++ = 255 - *current_row; //由于bgr图像矩阵是连续的,所以指针直接指向下一位 *current_row++ = 255 - *current_row; *current_row++ = 255 - *current_row; } } } imshow("像素读写演示", image); }
test440.cpp
#include<opencv2/opencv.hpp> #include<quickopencv.h> #include<iostream> using namespace cv; using namespace std; int main(int argc, char**argv) { // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作 // B,G,R Mat src = imread("D:/images/lena.jpg"); //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径 if (src.empty()) { printf("could not load image...\n"); return -1; } //namedWindow("输入窗口", WINDOW_FREERATIO); //不管图片大小,都能进行调整,图像很小可以不使用这个函数 imshow("输入窗口", src); //第一个参数为窗口名 QuickDemo qd; qd.pixel_visit_demo(src); waitKey(0); //窗口停留时间,0为一直停留,数值为停留的毫秒数 destroyAllWindows(); //关闭所有打开的窗口 return 0; }
效果
2.5、图像像素的算数操作
quickopencv.h
#pragma once #include<opencv2/opencv.hpp> using namespace cv; class QuickDemo { public: void colorSpace_Demo(Mat &image); void mat_creation_demo(); void pixel_visit_demo(Mat &image); void operators_demo(Mat &image); };
quickdemo.cpp
#include<quickopencv.h> void QuickDemo::operators_demo(Mat &image) { Mat dst; Mat m = Mat::zeros(image.size(), image.type()); m = Scalar(2, 2, 2); //Scalar标量 //dst = image + Scalar(50, 50, 50); //dst = image - Scalar(50, 50, 50); //dst = image / Scalar(2, 2, 2); //加法手写实现,主要使用saturate_cast函数,运算可使用对应函数快速实现 /* int w = image.cols; int h = image.rows; int dims = image.channels(); for (int row = 0; row < h; row++) { for (int col = 0; col < w; col++) { Vec3b p1 = image.at<Vec3b>(row, col); Vec3b p2 = m.at<Vec3b>(row, col); //saturate_cast函数,将大于255的数转换为255,小于0的数转换为0 dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(p1[0] + p2[0]); dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(p1[1] + p2[1]); dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(p1[2] + p2[2]); } } imshow("加法操作", dst); */ //add(image, m, dst); //add(操作的图,对图片操作的参数,输出的结果) //subtract(image, m, dst); //减法 //divide(image, m, dst); //除法 multiply(image, m, dst); //乘法 //imshow("加法操作", dst); //imshow("减法操作", dst); //imshow("除法操作", dst); imshow("乘法操作", dst); }
test440.cpp
#include<opencv2/opencv.hpp> #include<quickopencv.h> #include<iostream> using namespace cv; using namespace std; int main(int argc, char**argv) { // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作 // B,G,R Mat src = imread("D:/images/dark_face.jpg"); //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径 if (src.empty()) { printf("could not load image...\n"); return -1; } //namedWindow("输入窗口", WINDOW_FREERATIO); //不管图片大小,都能进行调整,图像很小可以不使用这个函数 imshow("输入窗口", src); //第一个参数为窗口名 QuickDemo qd; qd.operators_demo(src); waitKey(0); //窗口停留时间,0为一直停留,数值为停留的毫秒数 destroyAllWindows(); //关闭所有打开的窗口 return 0; }
效果
2.6、使用滚动条调整图像亮度(TrackBar)
quickopencv.h
#pragma once #include<opencv2/opencv.hpp> using namespace cv; class QuickDemo { public: void colorSpace_Demo(Mat &image); void mat_creation_demo(); void pixel_visit_demo(Mat &image); void operators_demo(Mat &image); void tracking_bar_demo(Mat &image); };
quickdemo.cpp
Mat src, dst, m; int lightness = 50; //回调函数两个形参,第一个int为createTrackbar中当前滑块所在位置,初始为lightness,第二个为userdata,为createTrackbar最后一个参数,默认为0 static void on_track(int, void*) { m = Scalar(lightness, lightness, lightness); add(src, m, dst); imshow("亮度调整", dst); } void QuickDemo::tracking_bar_demo(Mat &image) { namedWindow("亮度调整", WINDOW_AUTOSIZE); dst = Mat::zeros(image.size(), image.type()); m = Mat::zeros(image.size(), image.type()); src = image; int max_value = 100; //createTrackbar(滑动条名,滑动条所在的窗口,滑动块初始位置,滑动条最大值,回调函数(滑块滑动时的处理)) createTrackbar("Value Bar:", "亮度调整", &lightness, max_value, on_track); on_track(50, 0); }
test440.cpp
#include<opencv2/opencv.hpp> #include<quickopencv.h> #include<iostream> using namespace cv; using namespace std; int main(int argc, char**argv) { // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作 // B,G,R Mat src = imread("D:/images/dark_face.jpg"); //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径 if (src.empty()) { printf("could not load image...\n"); return -1; } //namedWindow("输入窗口", WINDOW_FREERATIO); //不管图片大小,都能进行调整,图像很小可以不使用这个函数 imshow("输入窗口", src); //第一个参数为窗口名 QuickDemo qd; qd.tracking_bar_demo(src); waitKey(0); //窗口停留时间,0为一直停留,数值为停留的毫秒数 destroyAllWindows(); //关闭所有打开的窗口 return 0; }
效果
2.7、滚动条操作-通过参数传递度
quickopencv.h
#pragma once #include<opencv2/opencv.hpp> using namespace cv; class QuickDemo { public: void colorSpace_Demo(Mat &image); void mat_creation_demo(); void pixel_visit_demo(Mat &image); void operators_demo(Mat &image); void tracking_bar_demo(Mat &image); };
quickdemo.cpp 对上一节函数优化
//回调函数两个形参,第一个int为createTrackbar中的当前滑块所在位置,第二个为userdata,为createTrackbar最后一个参数,默认为0 static void on_lightness(int b, void* userdata) { Mat image = *((Mat*)userdata); //指针转换成Mat类型数据 Mat dst = Mat::zeros(image.size(), image.type()); Mat m = Mat::zeros(image.size(), image.type()); addWeighted(image, 1.0, m, 0, b, dst); //dst = image*1.0 + m*0 + b imshow("亮度与对比度调整", dst); } static void on_contrast(int b, void* userdata) { Mat image = *((Mat*)userdata); //指针转换成Mat类型数据 Mat dst = Mat::zeros(image.size(), image.type()); Mat m = Mat::zeros(image.size(), image.type()); double contrast = b / 100.0; //addWeighted()函数可以实现两张图片混合 addWeighted(image, contrast, m, 0, 0, dst); //dst = image*contrast + m*0 + 0 imshow("亮度与对比度调整", dst); } void QuickDemo::tracking_bar_demo(Mat &image) { namedWindow("亮度与对比度调整", WINDOW_AUTOSIZE); int lightness = 50; int light_max_value = 100; int contrast_value = 100; int contrast_max = 200; //createTrackbar(滑动条名,滑动条所在的窗口,滑动块初始位置,滑动条最大值,回调函数(滑块滑动时的处理),userdata(传递给回调函数的数据)) createTrackbar("Value Bar:", "亮度与对比度调整", &lightness, light_max_value, on_lightness, (void*)(&image)); createTrackbar("Contrast Bar:", "亮度与对比度调整", &contrast_value, contrast_max, on_contrast, (void*)(&image)); }
test440.cpp
#include<opencv2/opencv.hpp> #include<quickopencv.h> #include<iostream> using namespace cv; using namespace std; int main(int argc, char**argv) { // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作 // B,G,R Mat src = imread("D:/images/dark_face.jpg"); //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径 if (src.empty()) { printf("could not load image...\n"); return -1; } //namedWindow("输入窗口", WINDOW_FREERATIO); //不管图片大小,都能进行调整,图像很小可以不使用这个函数 imshow("输入窗口", src); //第一个参数为窗口名 QuickDemo qd; qd.tracking_bar_demo(src); waitKey(0); //窗口停留时间,0为一直停留,数值为停留的毫秒数 destroyAllWindows(); //关闭所有打开的窗口 return 0; }
效果
2.8、滚动条操作-键盘响应操作
quickopencv.h
#pragma once #include<opencv2/opencv.hpp> using namespace cv; class QuickDemo { public: void colorSpace_Demo(Mat &image); void mat_creation_demo(); void pixel_visit_demo(Mat &image); void operators_demo(Mat &image); void tracking_bar_demo(Mat &image); void key_demo(Mat &image); };
quickdemo.cpp
void QuickDemo::key_demo(Mat &image) { Mat dst = Mat::zeros(image.size(), image.type()); while (true) { int c = waitKey(1); //waitKey(图像刷新时间间隔)不断刷新图像,刷新间隔时间为1ms,视频处理时尽量设置1ms if (c == 27) { // 退出 break; } if (c == 49) { // Key #1 cvtColor(image, dst, COLOR_BGR2GRAY); imshow("键盘响应01", dst); } if (c == 50) { // Key #2 cvtColor(image, dst, COLOR_BGR2HSV); imshow("键盘响应02", dst); } if (c == 51) { // Key #3 dst = Scalar(50, 50, 50); add(image, dst, dst); imshow("键盘响应03", dst); } //imshow("键盘响应", dst); } }
test440.cpp
#include<opencv2/opencv.hpp> #include<quickopencv.h> #include<iostream> using namespace cv; using namespace std; int main(int argc, char**argv) { // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作 // B,G,R Mat src = imread("D:/images/lena.jpg"); //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径 if (src.empty()) { printf("could not load image...\n"); return -1; } //namedWindow("输入窗口", WINDOW_FREERATIO); //不管图片大小,都能进行调整,图像很小可以不使用这个函数 imshow("输入窗口", src); //第一个参数为窗口名 QuickDemo qd; qd.key_demo(src); waitKey(0); //窗口停留时间,0为一直停留,数值为停留的毫秒数 destroyAllWindows(); //关闭所有打开的窗口 return 0; }
效果
2.9、OpenCV自带颜色表操作
quickopencv.h
#pragma once #include<opencv2/opencv.hpp> using namespace cv; class QuickDemo { public: void colorSpace_Demo(Mat &image); void mat_creation_demo(); void pixel_visit_demo(Mat &image); void operators_demo(Mat &image); void tracking_bar_demo(Mat &image); void key_demo(Mat &image); void color_style_demo(Mat &image); };
quickdemo.cpp
void QuickDemo::color_style_demo(Mat &image) { int colormap[] = { COLORMAP_AUTUMN, COLORMAP_BONE, COLORMAP_JET, COLORMAP_WINTER, COLORMAP_RAINBOW, COLORMAP_OCEAN, COLORMAP_SUMMER, COLORMAP_SPRING, COLORMAP_COOL, COLORMAP_PINK, COLORMAP_HOT, COLORMAP_PARULA, COLORMAP_MAGMA, COLORMAP_INFERNO, COLORMAP_PLASMA, COLORMAP_VIRIDIS, COLORMAP_CIVIDIS, COLORMAP_TWILIGHT, COLORMAP_TWILIGHT_SHIFTED }; Mat dst; int index = 0; while (true) { int c = waitKey(2000); if (c == 27) { break; } applyColorMap(image, dst, colormap[index%19]); index++; imshow("颜色风格", dst); } }
test440.cpp
#include<opencv2/opencv.hpp> #include<quickopencv.h> #include<iostream> using namespace cv; using namespace std; int main(int argc, char**argv) { // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作 // B,G,R Mat src = imread("D:/images/lena.jpg"); //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径 if (src.empty()) { printf("could not load image...\n"); return -1; } //namedWindow("输入窗口", WINDOW_FREERATIO); //不管图片大小,都能进行调整,图像很小可以不使用这个函数 imshow("输入窗口", src); //第一个参数为窗口名 QuickDemo qd; qd.color_style_demo(src); waitKey(0); //窗口停留时间,0为一直停留,数值为停留的毫秒数 destroyAllWindows(); //关闭所有打开的窗口 return 0; }
效果