C/C++ vs2017 OpenCV简单入门
Posted cpp_learners
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C/C++ vs2017 OpenCV简单入门相关的知识,希望对你有一定的参考价值。
离职之际,自学一下图像相关的知识点,只是简单学了一点皮毛!
目录
一、 OpenCV环境搭建
官网下载链接:Releases - OpenCV
下载后双击开始解压安装
解压完毕
进入路径 D:\\opencv\\opencv\\build\\x64\\vc14\\bin
vs2019及其以上的版本可以选择vc15那个文件夹
拷贝该路径,设置环境变量
在路径D:\\opencv\\opencv\\build\\x64\\vc14\\lib 会有项目中需要使用到的lib
新建一个VS工程,
右键 属性 - VC++目录 - 包含库目录,添加头文件路径进来
右键 属性 - VC++目录 - 库目录,添加lib文件路径进行
右键 属性 - 链接器 - 输入 - 附加依赖项,将opencv_world460d.lib添加进来,如果是release项目,那么就添加opencv_world460.lib
注意,属性中的“配置”和“平台”需要和界面的保持一致
当然,上面添加目录和库目录的操作,可以将相应的头文件和库拷贝到项目路径,再添加项目路径进来即可!
编写如下代码测试环境:
#include <opencv2/opencv.hpp>
#include <iostream>
#include <stdio.h>
using namespace cv;
void int test1(Mat src)
// 设置新的窗体标题,参数一窗体标题,参数二窗体随图片大小
namedWindow("opencv窗口2", WINDOW_AUTOSIZE);
Mat output_image;
/* 设置图片颜色 */
cvtColor(src, output_image, COLOR_BGRA2RGB);
imshow("opencv窗口2", output_image);
/* 保存图片到本地 */
imwrite("D:/new.png", output_image);
// 等待
waitKey(0);
int main(void)
// 正常:IMREAD_COLOR
// 灰度:IMREAD_GRAYSCALE
Mat image = imread("图.jpeg", IMREAD_COLOR); // 读取一张图片
if (image.empty()) // 判断图片是否读取成功
printf("path image NULL!\\n");
return -1;
// 显示图片 参数一是窗体标题,参数二图片对象
imshow("原图", image);
test1(image);
return 0;
编译运行,不出意外的话,就会显示两张我们指定路径读取的图片
左边那一种是修改颜色后的图片,右边是原图!
至此,环境搭建完毕!
二、使用opencv
常用接口说明
1. imread
Mat image = imread("图.jpeg", IMREAD_COLOR);
解析:读取一张图片。
2. image.empty()
解析:判断文件是否读取成功,ture表示不成功,false表示成功。
3. imshow
imshow("opencv窗口2", output_image);
解析:显示一张图片,参数一是窗体名字,参数二是图片对象,也就是Mat对象
4. imwrite
imwrite("D:/new.png", output_image);
解析:将图像保存到本地。参数一是文件路径名,参数二是图片对象。
5. waitKey
int waitKey(int delay = 0);
解析:等待,相当于c/c++中的system("pause"); 参数为0,表示一直等待,其他大于零的数,则表示等待对应的秒数。
6. destroyAllWindows
void destroyAllWindows();
解析:销毁所有打开的窗体。
7. cvtColor
void cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0 );
解析:设置图像的颜色。参数一是输入图像对象,参数二是设置好输出的图像对象,参数三是设置图像颜色枚举(enum ColorConversionCodes)
8. clone
Mat src = image.clone()
解析:将图像对象克隆赋值,需要另一个Mat对象去接收,相当于深拷贝。
8. copyTo
Mat m2;
image.copyTo(m2)
解析:将图像对象拷贝给另一个图像对象,相当于深拷贝。
9. zeros
Mat m4 = Mat::zeros(Size(128, 128), CV_8UC3);
解析:创建空白图像。参数一是图像大小,参数二表示通道数。
10. Scalar
m4 = Scalar(255, 255, 0);
解析:给图像设置颜色。因为是给三个通道的图像设置颜色,所以这里使用三个参数;如果是给单通道设置颜色,则设置一个参数即可。
11. cols
int width = m4.cols;
解析:获取图像的宽度。
12. rows
int height = m4.rows;
解析:获取图像的高度。
13. channels
int channels = m4.channels();
解析:获取通向的通道数。单通道表示灰色图像,三通道表示彩色图像。
14. add
add(image, m1, dst1);
解析:图像的像素相加。参数一和参数二是输入图像,参数三是输出图像。也就是将参数一和参数二的像素相加后输出到参数三。
15. subtract
subtract(image, m2, dst2);
解析:图像的像素相减。参数一和参数二是输入图像,参数三是输出图像。也就是将参数一和参数二的像素相减后输出到参数三。
16. multiply
multiply(image, m3, dst3);
解析:图像的像素相乘。参数一和参数二是输入图像,参数三是输出图像。也就是将参数一和参数二的像素相乘后输出到参数三。
17. divide
divide(image, m4, dst4);
解析:图像的像素相除。参数一和参数二是输入图像,参数三是输出图像。也就是将参数一和参数二的像素相除后输出到参数三。
18. waitKey
int c = waitKey(100);
解析:等待键盘输入,如果参数设置的毫秒数结束后还没有键盘输入,则默认输入-1,结束等待。
19. applyColorMap
applyColorMap(image, dst, COLORMAP_COOL);
解析:设置图像彩色映射。参数一是输入图像,参数二是输出图像,参数三是映射的颜色类型,他是枚举enum ColormapTypes。
20. bitwise_and
bitwise_and(m1, m2, dst1);
解析:图像像素逻辑与操作。参数一和参数二是输入图像,参数三是输出图像。
21. bitwise_or
bitwise_or(m1, m2, dst2);
解析:图像像素逻辑或操作。参数一和参数二是输入图像,参数三是输出图像。
22. bitwise_not
bitwise_not(image, dst3);
解析:图像像素取反操作。参数一是输入图像,参数二是输出图像。
23. bitwise_xor
bitwise_xor(m1, m2, dst4);
解析:图像像素逻辑异或操作。参数一和参数二是输入图像,参数三是输出图像。
24. split
std::vector<Mat> mv;
split(image, mv);
解析:通道分离。
25. rectangle
rectangle(dst1, rect, Scalar(0, 255, 255), 2, 8, 0);
解析:绘制一个矩形。参数一是输出图像,参数二是矩形对象,参数三是颜色,参数四是边框厚度,参数五是反锯齿(可以使用LINE_AA效果更加),参数六不清楚。
如果是需要填充,则将参数四传入-1。
26. circle
circle(dst1, Point(300, 400), 30, Scalar(255, 0, 255), 2, 8, 0);
解析:绘制一个圆形。参数一是输出图像,参数二是圆的中心位置,参数三是圆的半径,参数四是颜色,参数五是边框厚度,参数六是反锯齿(可以使用LINE_AA效果更加),参数七不清楚。
如果是需要填充,则将参数五传入-1。
27. line
line(dst5, Point(100, 130), Point(300, 400), Scalar(255, 0, 0), 2, 8, 0);
解析:绘制一条线。参数一是输入输出图像, 参数二是第一个点位置,参数三是第二个点位置,参数四是颜色,参数五是线的宽度,参数六是反锯齿,参数七不清楚。
28. RNG
RNG rng((unsigned)time(NULL)); // 用系统时间作为种子初始化rng,要用到time.h库
int b = rng.uniform(0, 255); // 随机生成 0 - 255
解析:opencv的随机函数。
29. drawContours
drawContours(canvas, contours, 0, Scalar(255, 0, 0), -1);
解析:绘制多边形或者填充多边形。参数一是输入输出图像,参数二是std::vector<std::vector<Point>>类型对象,参数三指定绘制容器中指定数据的第几个(-1表示全都绘制),最后一个参数为多边形的边框(-1表示填充)
30. resize
resize(image, zoomin, Size(w / 2, h / 2));
解析:图像缩放。参数一是输入图像,参数二是输出图像,参数三是重新设置的图像大小。
31. flip
// 上下翻转
flip(image, dst, 0);
// 左右翻转
flip(image, dst, 1);
// 先左右翻转再上下翻转
flip(image, dst, -1);
解析:图像翻转。参数一是输入图像,参数二是输出图像,参数三0表示上下翻转,1表示左右翻转,-1表示先左右翻转再上下翻转。
使用案例
以下函数的参数都基于此读取的图像对象:
int main(void)
// 正常:IMREAD_COLOR
// 灰度:IMREAD_GRAYSCALE
Mat image = imread("图.jpeg", IMREAD_COLOR);
if (image.empty())
printf("path image NULL!\\n");
return -1;
imshow("原图", image);
waitKey(0);
destroyAllWindows();
return 0;
1. 图像色彩空间转换
/* 图像色彩空间转换 */
void colorSpace_Demo(Mat &image)
Mat gray, hsv;
cvtColor(image, hsv, COLOR_BGR2HSV);
cvtColor(image, gray, COLOR_BGR2GRAY); // 灰度图像
imshow("HSV", hsv);
imshow("灰度", gray);
imwrite("HSV.png", hsv);
imwrite("GRAY.png", gray);
运行截图
2. Mat对象的创建与赋值
/* Mat对象的创建与赋值 */
void mat_creation_demo(Mat &image)
Mat m1, m2, m3;
// 克隆
m1 = image.clone(); // 深拷贝
// 拷贝
image.copyTo(m2); // 深拷贝
// 赋值
m3 = image; // 浅拷贝
// 创建空白图像
//Mat m4 = Mat::zeros(Size(8, 8), CV_8UC1); // 创建一通道
Mat m4 = Mat::zeros(Size(128, 128), CV_8UC3); // 最后的数字表示通道数
// 给通道赋值(相当于设置颜色)
m4 = Scalar(123, 200, 100); // 因为是3通道,所以赋三个值;如果是一通道,给一个参数值即可
//std::cout << m4 << std::endl;
imshow("m4", m4);
// 图像的宽
int width = m4.cols;
// 图像的高
int height = m4.rows;
// 图像的通道数
int channels = m4.channels();
printf("width = %d\\theight = %d\\tchannels = %d\\n", width, height, channels);
// C++11新出的创建空白图像方法
Mat kernel = (Mat_<char>(3, 3) <<
0, -1, 0,
-1, 5, -1,
0, -1, 0);
kernel = Scalar(50, 100, 150);
imshow("kernel", kernel);
运行截图
3. 图像像素的读写操作
/* 图像像素的读写操作 */
void 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 (1 == dims)
// // 获取通道中的值
// int pv = image.at<uchar>(row, col);
// // 还可以对其进行修改
// image.at<uchar>(row, col) = 255 - pv; // 得确保值在0-255区间
// else if (3 == dims) // 三通道 - 彩色图像
// // 获取通道中的三个值
// Vec3b bgr = image.at<Vec3b>(row, col);
// // 还可以对其进行修改
// 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 (1 == dims)
*current_row++ = 255 - *current_row;
else if (3 == dims)
*current_row++ = 255 - *current_row;
*current_row++ = 255 - *current_row;
*current_row++ = 255 - *current_row;
imshow("pixel_visit_demo", image);
运行截图:
4. 图像像素的算术操作
/* 图像像素的算术操作 */
void operators_demo(Mat &image)
// 加
Mat dst1;
Mat m1 = Mat::zeros(image.size(), image.type());
m1 = Scalar(100, 100, 100); // 给通道赋值(相当于设置颜色)
add(image, m1, dst1);
imshow("图像像素加法操作", dst1);
// 减
Mat dst2;
Mat m2 = Mat::zeros(image.size(), image.type());
m2 = Scalar(50, 50, 50);
subtract(image, m2, dst2);
imshow("图像像素减法操作", dst2);
// 乘
Mat dst3;
Mat m3 = Mat::zeros(image.size(), image.type());
m3 = Scalar(2, 2, 2);
multiply(image, m3, dst3); // 参数一乘以参数二结果给参数三
imshow("图像像素乘法操作", dst3);
// 除
Mat dst4;
Mat m4 = Mat::zeros(image.size(), image.type());
m4 = Scalar(5, 5, 5);
divide(image, m4, dst4);
imshow("图像像素除法操作", dst4);
///* 另外一种方式实现加法操作 */
//Mat dst5 = Mat::zeros(image.size(), image.type());
//Mat m5 = Mat::zeros(image.size(), image.type());
//m5 = Scalar(50, 50, 50);
//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 (3 == dims)
// Vec3b p1 = image.at<Vec3b>(row, col);
// Vec3b p2 = m5.at<Vec3b>(row, col);
// // 加减乘除都是一样的
// dst5.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(p1[0] + p2[0]);
// dst5.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(p1[1] + p2[1]);
// dst5.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(p1[2] + p2[2]);
//
//
//
//
//imshow("图像像素加法操作", dst5);
运行截图
5. 滚动条操作演示
static void on_track(int b, void *userdata)
Mat image = *((Mat*)userdata);
Mat dst = Mat::zeros(image.size(), image.type());
Mat m = Mat::zeros(image.size(), image.type());
m = Scalar(b, b, b);
add(image, m, dst);
imshow("亮度调整", dst);
/* 滚动条操作演示 */
void tracking_bar_demo(Mat &image)
namedWindow("亮度调整", WINDOW_AUTOSIZE);
int lightness = 0;
int max_value = 100;
// 创建一个滚动条
createTrackbar("Value Bar:", "亮度调整", &lightness, max_value, on_track, (void*)(&image));
on_track(lightness, &image);
运行截图
6. 键盘响应操作
/* 键盘响应操作 */
void key_demo(Mat &image)
bool flag = true;
Mat input;
image.copyTo(input);
while (flag)
int c = waitKey(100); // 等待键盘输入,等待100ms
printf("按键:%d\\n", c);
switch (c)
case 27: // Esc退出
flag = false;
break;
case 52: // 4 向左旋转
break;
case 54: // 6 向右旋转
break;
case 56: // 8 放大
break;
case 50: // 2 缩小
break;
case 48: // 0 复原
break;
default:
break;
imshow("原图", image);
这个键盘响应,我用来写了一个小demo,通过键盘按键来对图片进行旋转、缩放、平移、翻转和裁剪的操作。
7. OpenCV自带颜色表操作
/* OpenCV自带颜色表操作 */
void color_style_demo(Mat &image)
int colorMap[] =
COLORMAP_AUTUMN,
COLORMAP_BONE,
COLORMAP_CIVIDIS,
COLORMAP_COOL,
COLORMAP_DEEPGREEN,
COLORMAP_HOT,
COLORMAP_HSV,
COLORMAP_INFERNO,
COLORMAP_JET,
COLORMAP_MAGMA,
COLORMAP_OCEAN,
COLORMAP_PARULA,
COLORMAP_PINK,
COLORMAP_PLASMA,
COLORMAP_RAINBOW,
COLORMAP_SPRING,
COLORMAP_SUMMER,
COLORMAP_TURBO,
COLORMAP_TWILIGHT,
COLORMAP_TWILIGHT_SHIFTED,
COLORMAP_VIRIDIS,
COLORMAP_WINTER,
DECOMP_NORMAL
;
Mat dst;
int index = 0;
while (1)
int c = waitKey(1000);
if (27 == c)
break;
applyColorMap(image, dst, colorMap[index % 19]);
index++;
imshow("Opencv自带颜色表", dst);
数组colorMap中存储的,都是enum ColormapTypes枚举中的数据。
运行截图
8. 图像像素的逻辑操作
/* 图像像素的逻辑操作 */
void bitwise_demo(Mat &image)
Mat m1 = Mat::zeros(Size(256, 256), CV_8UC3);
Mat m2 = Mat::zeros(Size(256, 256), CV_8UC3);
rectangle(m1, Rect(100, 100, 80, 80), Scalar(255, 255, 0), -1, LINE_8, 0);
rectangle(m2, Rect(150, 150, 80, 80), Scalar(0, 255, 255), -1, LINE_8, 0);
imshow("m1", m1);
imshow("m2", m2);
// 逻辑与
Mat dst1;
bitwise_and(m1, m2, dst1);
imshow("逻辑与", dst1);
// 逻辑或
Mat dst2;
bitwise_or(m1, m2, dst2);
imshow("逻辑或", dst2);
// 逻辑非
Mat dst3;
bitwise_not(image, dst3);
imshow("逻辑非", dst3);
// 逻辑异或
Mat dst4;
bitwise_xor(m1, m2, dst4);
imshow("逻辑异或", dst4);
运行截图
9. 通道分离与合并
/* 通道分离与合并 */
void channels_demo(Mat &image)
std::vector<Mat> mv;
// 将一个多通道数组划分为多个单通道数组
split(image, mv);
imshow("blue", mv.at(0));
imshow("green", mv.at(1));
imshow("red", mv.at(2));
Mat dst;
//mv.at(1) = 0;
mv.at(2) = 0;
// 通道合并
merge(mv, dst);
imshow("合并通道颜色", dst);
int from_to[] = 0, 2, 1, 1, 2, 0 ; // 将0 和 2通道交换
// 通道混合
mixChannels(&image, 1, &dst, 1, from_to, 3);
imshow("通道混合", dst);
运行截图
10. 图像色彩空间转换
/* 图像色彩空间转换 */
void inrange_demo(Mat &image)
Mat hsv;
// 转换位hsv的色彩空间
cvtColor(image, hsv, COLOR_BGR2HSV);
Mat mask;
inRange(hsv, Scalar(35, 43, 46), Scalar(77, 255, 255), mask); // 将草莓扣掉
Mat redback = Mat::zeros(image.size(), image.type());
redback = Scalar(40, 40, 200); // 红色背景图
bitwise_not(mask, mask); // 逻辑非
imshow("mask", mask);
image.copyTo(redback, mask); // 将原图草莓图中按照mask里白色区域拷贝到参数一中
imshow("roi区域提取", redback);
运行截图
11. 图像像素值统计
/* 图像像素值统计 */
void pixel_statistic_demo(Mat &image)
double minv, maxv;
Point minLoc, maxLoc;
std::vector<Mat> mv;
split(image, mv); // 通道分离
for (int i = 0; i < mv.size(); i++)
// 找出通道中的最大值和最小值
minMaxLoc(mv[i], &minv, &maxv, &minLoc, &maxLoc, Mat());
printf("No.channels:%d\\tminvalue:%f\\tmaxvalue:%f\\n", i, minv, maxv);
Mat mean, stddev;
// 计算矩阵的均值和标准偏差
meanStdDev(image, mean, stddev);
std::cout << "means: " << mean << std::endl;
std::cout << "stddev:" << stddev << std::endl;
运行截图
12. 图像几何形状绘制
/* 图像几何形状绘制 */
void drawing_demo(Mat &image)
Rect rect;
rect.x = 100;
rect.y = 130;
rect.width = 200;
rect.height = 270;
Mat dst1 = image.clone();
Mat dst2 = image.clone();
// 绘制一个矩形
rectangle(dst1, rect, Scalar(0, 255, 255), 2, 8, 0);
// 绘制一个圆形
circle(dst1, Point(300, 400), 30, Scalar(255, 0, 255), 2, 8, 0);
imshow("绘制演示", dst1);
// 填充一个矩形
rectangle(dst2, rect, Scalar(255, 255, 0), -1, 8, 0);
// 填充一个圆形
circle(dst2, Point(100, 400), 30, Scalar(0, 255, 0), -1, 8, 0);
imshow("填充演示", dst2);
Mat dst5 = image.clone();
// 绘制线
line(dst5, Point(100, 130), Point(300, 400), Scalar(255, 0, 0), 2, 8, 0);
// 绘制椭圆
RotatedRect rrt;
rrt.center = Point(200, 200);
rrt.size = Size(100, 200);
rrt.angle = 90.0;
ellipse(dst5, rrt, Scalar(0, 0, 255), 2, 8); // 如果需要填充,第四个参数传-1
imshow("线和椭圆", dst5);
Mat dst3, dst4;
dst3 = Mat::zeros(image.size(), image.type());
dst3 = Scalar(100, 180, 200);
imshow("dst3", dst3);
// 将两张相同大小,相同类型的图片融合的函数
addWeighted(image, 0.7, dst3, 0.5, 1, dst4);
imshow("两种图片融合", dst4);
运行截图
13. 随机数与随机颜色
/* 随机数与随机颜色 */
void random_drawing_demo()
Mat canvas = Mat::zeros(Size(512, 512), CV_8UC3);
int w = canvas.cols;
int h = canvas.rows;
RNG rng((unsigned)time(NULL)); // 用系统时间作为种子初始化rng,要用到time.h库
while (1)
int c = waitKey(10);
if (27 == c)
break;
canvas = Scalar(0, 0, 0);
// 获得随机值
int x1 = rng.uniform(0, w);
int y1 = rng.uniform(0, h);
int x2 = rng.uniform(0, w);
int y2 = rng.uniform(0, h);
int b = rng.uniform(0, 255);
int g = rng.uniform(0, 255);
int r = rng.uniform(0, 255);
line(canvas, Point(x1, y1), Point(x2, y2), Scalar(b, g, r), 1, LINE_AA, 0);
imshow("随机数与随机颜色", canvas);
运行截图
14. 多边形填充与绘制
/* 多边形填充与绘制 */
void polyline_drawing_demo()
Mat canvas = Mat::zeros(Size(512, 512), CV_8UC3);
Point p1(100, 100);
Point p2(350, 120);
Point p3(300, 350);
Point p4(450, 500);
Point p5(50, 200);
std::vector<Point> pts;
pts.emplace_back(p1);
pts.emplace_back(p2);
pts.emplace_back(p3);
pts.emplace_back(p4);
pts.emplace_back(p5);
// 填充一个多边形
//fillPoly(canvas, pts, Scalar(255, 0, 255), 8, 0);
// 绘制一个多边形
//polylines(canvas, pts, true, Scalar(0, 0, 255), 2, LINE_AA, 0);
std::vector<std::vector<Point>> contours;
contours.push_back(pts);
// 绘制多边形或者填充多边形,参数三指定绘制容器中指定数据的第几个(-1表示全都绘制),最后一个参数为多边形的边框(-1表示填充)
drawContours(canvas, contours, 0, Scalar(255, 0, 0), -1);
imshow("多边形填充与绘制", canvas);
运行截图
15. 鼠标操作与响应
Point sp(-1, -1);
Point ep(-1, -1);
Mat temp;
static void on_draw(int event, int x, int y, int flags, void *userdata)
Mat image = *((Mat*)userdata);
if (event == EVENT_LBUTTONDOWN) // 鼠标左键按下
sp.x = x; // 获取鼠标坐下按下后的位置坐标
sp.y = y;
std::cout << "start point:" << sp << std::endl;
else if (event == EVENT_LBUTTONUP)
ep.x = x; // 获得鼠标松开后的位置坐标
ep.y = y;
// 相减得出长和宽
int dx = ep.x - sp.x;
int dy = ep.y - sp.y;
if (dx > 0 && dy > 0 && ep.y < image.size().height && ep.x < image.size().width)
Rect box(sp.x, sp.y, dx, dy);
rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0); // 绘制矩形
imshow("鼠标绘制", image);
imshow("ROI区域提取", temp(box)); // 提取矩形中的图像
else
temp.copyTo(image);
imshow("鼠标绘制", image);
sp.x = -1;
sp.y = -1;
else if (event == EVENT_MOUSEMOVE)
if (sp.x > 0 && sp.y > 0)
ep.x = x;
ep.y = y;
int dx = ep.x - sp.x;
int dy = ep.y - sp.y;
if (dx > 0 && dy > 0)
temp.copyTo(image);
Rect box(sp.x, sp.y, dx, dy);
rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
imshow("鼠标绘制", image);
/* 鼠标操作与响应 */
void mouse_drawing_demo(Mat &image)
namedWindow("鼠标绘制", WINDOW_AUTOSIZE);
// 设置鼠标回调
setMouseCallback("鼠标绘制", on_draw, (void*)(&image));
imshow("鼠标绘制", image);
temp = image.clone();
运行截图
16. 图像像素类型转换与归一化
/* 图像像素类型转换与归一化 */
void norm_demo(Mat &image)
Mat dst;
std::cout << image.type() << std::endl;
image.convertTo(image, CV_32F);
std::cout << image.type() << std::endl;
normalize(image, dst, 1.0, 0, NORM_MINMAX);
std::cout << dst.type() << std::endl;
imshow("图像数据归一化", dst);
运行截图
17. 图像缩放与插值
/* 图像缩放与插值 */
void resize_demo(Mat &image)
Mat zoomin, zoomout;
int h = image.rows;
int w = image.cols;
resize(image, zoomin, Size(w / 2, h / 2), 0, 0, INTER_LINEAR);
imshow("zoomin", zoomin);
resize(image, zoomout, Size(w*1.5, h*1.5), 0, 0, INTER_LINEAR);
imshow("zoomout", zoomout);
运行截图
18. 图像翻转
/* 图像翻转 */
void flip_demo(Mat &image)
Mat dst;
// 上下翻转
flip(image, dst, 0);
// 左右翻转
//flip(image, dst, 1);
// 先左右翻转再上下翻转
//flip(image, dst, -1);
imshow("图像翻转", dst);
运行截图
19. 图像旋转
/* 图像旋转 */
void rotate_demo(Mat &image)
Mat dst, M;
int w = image.cols;
int h = image.rows;
M = getRotationMatrix2D(Point2f(w / 2, h / 2), -45, 1.0);
// 计算旋转后需要多大的窗体才能完全装下旋转后的图像
double cos = abs(M.at<double>(0, 0));
double sin = abs(M.at<double>(0, 1));
int nw = cos * w + sin * h;
int nh = sin * w + cos * h;
M.at<double>(0, 2) += (nw / 2 - w / 2);
M.at<double>(1, 2) += (nh / 2 - h / 2);
warpAffine(image, dst, M, Size(nw, nh), INTER_LINEAR, 0, Scalar(255, 0, 0));
imshow("图像旋转", dst);
运行截图
20. 视频文件摄像头使用
/* 视频文件摄像头使用 */
void video_demo()
// VideoCapture capture(0); // 参数是0,就是读取电脑摄像头
VideoCapture capture("E:\\\\Code\\\\vs2017Code\\\\OpencvTest2\\\\OpencvTest2\\\\win10.mp4");
// 视频宽
int frame_width = capture.get(CAP_PROP_FRAME_WIDTH);
// 视频高
int frame_hegiht = capture.get(CAP_PROP_FRAME_HEIGHT);
// 视频总帧率
int count = capture.get(CAP_PROP_FRAME_COUNT);
// 视频每秒多少fps(每秒多少帧)
double fps = capture.get(CAP_PROP_FPS);
std::cout << "froma_width:" << frame_width << std::endl;
std::cout << "frame_hegiht:" << frame_hegiht << std::endl;
std::cout << "count:" << count << std::endl;
std::cout << "fps:" << fps << std::endl;
// 定义视频保存对象
VideoWriter writer("D://test.mp4", capture.get(CAP_PROP_FOURCC), fps, Size(frame_width, frame_hegiht), true);
Mat frame;
while (1)
capture.read(frame); // 读取画面
//flip(frame, frame, 1); // 左右翻转,读取电脑摄像头时需要翻转,视频不用
if (frame.empty())
break;
imshow("frame", frame);
// 保存视频
writer.write(frame);
int c = waitKey(10);
if (27 == c)
break;
// 释放
capture.release();
writer.release();
运行截图
21. 图像卷积操作
/* 图像卷积操作 */
void blur_demo(Mat &image)
Mat dst;
blur(image, dst, Size(1, 1), Point(-1, -1)); // // 设置参数三的数值即可
imshow("图像模糊", dst);
运行截图
22. 高斯模糊
/* 高斯模糊 */
void gaussian_blur_demo(Mat &image)
Mat dst;
GaussianBlur(image, dst, Size(0, 0), 5); // 参数三默认0即可,设置参数四实现模糊
imshow("高斯模糊", dst);
运行截图
23. 高斯双边模糊
/* 高斯双边模糊 */
void bifilter_demo(Mat &image)
Mat dst;
bilateralFilter(image, dst, 0, 100, 10);
imshow("双边模糊", dst);
运行截图
三、键盘操作小demo
1. 键盘小demo
对图片操作,旋转,缩放,平移,翻转,裁剪的操作。
#include <opencv2/opencv.hpp>
using namespace cv;
void imageOperate1(Mat &image, Mat input, double angle, double scale, int xOffset, int yOffset, int startRow, int &endRow, int startCol, int &endCol, bool up_down, bool left_right)
input.copyTo(image);
// 图像平移
Size dst_sz = image.size();
//定义平移矩阵
Mat t_mat = Mat::zeros(2, 3, CV_32FC1);
t_mat.at<float>(0, 0) = 1;
t_mat.at<float>(0, 2) = xOffset; //水平平移量
t_mat.at<float>(1, 1) = 1;
t_mat.at<float>(1, 2) = yOffset; //竖直平移量
//根据平移矩阵进行仿射变换
warpAffine(image, image, t_mat, dst_sz);
// 旋转图像
Point2f center((image.cols - 1) / 2.0, (image.rows - 1) / 2.0); // 图像中心位置
Mat rotation_matix = getRotationMatrix2D(center, angle, 1.0);
warpAffine(image, image, rotation_matix, image.size());
// 缩放图像
int width = int(input.cols * scale);
int height = int(input.rows * scale);
resize(image, image, cv::Size(width, height), 0, 0, INTER_LINEAR);
if (0 == endRow) // 发生了缩放操作
endRow = height;
endCol = width;
// 裁剪图像
image = image(Range(startRow, endRow), Range(startCol, endCol));
// 上下翻转
if (up_down) flip(image, image, 0);
// 左右翻转
if (left_right) flip(image, image, 1);
/* 键盘响应操作 */
void key_demo1(Mat &image)
bool flag = true;
double scale = 1.0; // 缩放比例
double angle = 0; // 旋转角度
int xOffset = 0; // 水平平移量
int yOffset = 0; // 竖直平移量
int startRow = 0; // 裁剪起始行
int endRow = image.size().height; // 裁剪结束行
int startCol = 0; // 裁剪起始列
int endCol = image.size().width; // 才接结束列
bool up_down = false; // 上下翻转
bool left_right = false; // 左右翻转
Mat input;
image.copyTo(input);
while (flag)
int c = waitKey(100); // 等待键盘输入,等待100ms
printf("按键:%d\\n", c);
switch (c)
case 27:
// Esc退出
flag = false;
break;
case 52:
// 4 向左旋转
angle += 5;
imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
break;
case 54:
// 6 向右旋转
angle -= 5;
imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
break;
case 56:
// 8 放大
scale += 0.1;
if (scale <= 2.05) // 设置最大放大是2
endRow = 0;
imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
else
scale = 2.0;
break;
case 50:
// 2 缩小
scale -= 0.1;
if (scale >= 0.15) // 最小缩小是0.2
endRow = 0;
imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
else
scale = 0.2;
break;
case 87:
case 119:
// wW 图片上移
yOffset -= 2;
imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
break;
case 83:
case 115:
// sS 图片下移
yOffset += 2;
imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
break;
case 65:
case 97:
// aA 图片左移
xOffset -= 2;
imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
break;
case 68:
case 100:
// dD 图片右移
xOffset += 2;
imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
break;
case 73:
// I 图片上边复原
if (startRow > 0)
startRow -= 1;
imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
else
startRow = 0;
break;
case 105:
// i 图片上边裁剪
if (startRow < endRow - 1)
startRow += 1;
imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
else
startRow = endRow - 1;
break;
case 75:
// K 图片下边复原
if (endRow < input.size().height)
endRow += 1;
imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
else
endRow = input.size().height;
break;
case 107:
// k 图片下边裁剪
if (endRow > startRow + 1)
endRow -= 1;
imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
else
endRow = startRow + 1;
break;
case 74:
// J 图片左边恢复
if (startCol > 0)
startCol -= 1;
imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
else
startCol = 0;
break;
case 106:
// j 图片左边裁剪
if (startCol < endCol - 1)
startCol += 1;
imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
else
startCol = endCol - 1;
break;
case 76:
// L 图片右边复原
if (endCol < input.size().width)
endCol += 1;
imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
else
endCol = input.size().width;
break;
case 108:
// l 图片右边裁剪
if (endCol > startCol + 1)
endCol -= 1;
imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
else
endCol = startCol + 1;
break;
case 43:
// + 上下翻转
up_down = !up_down;
imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
break;
case 45:
// - 左右翻转
left_right = !left_right;
imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
break;
case 48:
// 0 复原
scale = 1.0; // 缩放比例
angle = 0; // 旋转角度
xOffset = 0; // 水平平移量
yOffset = 0; // 竖直平移量
startRow = 0; // 裁剪起始行
endRow = input.size().height; // 裁剪结束行
startCol = 0; // 裁剪起始列
endCol = input.size().width; // 才接结束列
up_down = false; // 上下翻转
left_right = false; // 左右翻转
imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
break;
default:
break;
imshow("原图", image);
int main(void)
Mat image = imread("图.jpeg", IMREAD_COLOR);
if (image.empty())
printf("path image NULL!\\n");
return -1;
imshow("原图", image);
key_demo1(image);
waitKey(0);
destroyAllWindows();
return 0;
运行截图
2. 旋转、缩放、裁剪、平移案例
#include <stdio.h>
#include <Windows.h>
#include "opencv2/opencv.hpp"
using namespace cv;
// 图片旋转
Mat imageRotate(Mat input, double angle)
angle *= -1;
// get the center coordinates of the image to create the 2D rotation matrix
Point2f center((input.cols - 1) / 2.0, (input.rows - 1) / 2.0);
// using getRotationMatrix2D() to get the rotation matrix
Mat rotation_matix = getRotationMatrix2D(center, angle, 1.0);
Mat newImage;
warpAffine(input, newImage, rotation_matix, input.size());
//namedWindow("测试图片旋转", WINDOW_FREERATIO);
//imshow("测试图片旋转", newImage);
imshow("测试显示图片", newImage);
return newImage;
// 图片缩放
Mat imageZoom(Mat input, float scaleW, float scaleH)
//float scaleW = 0.5; // 定义新图像的大小,宽度缩小到80%
//float scaleH = 0.5; //定义新图像的大小,高度缩小到80%
int width = int(input.cols * scaleW);
//定义想要扩大或者缩小后的宽度,src.cols为原图像的宽度,乘以80%则得到想要的大小,并强制转换成int型
int height = int(input.rows * scaleH);
//定义想要扩大或者缩小后的高度,src.cols为原图像的高度,乘以80%则得到想要的大小,并强制转换成int型
cv::Mat dst;
resize(input, dst, cv::Size(width, height));//缩放图像
//namedWindow("测试图片缩放", WINDOW_FREERATIO);
//imshow("测试图片缩放", dst);
imshow("测试显示图片", dst);
return dst;
// 图片裁剪
Mat imageCut(Mat input, int startRow, int endRow, int startCol, int endCol)
Mat cropped_image = input(Range(startRow, endRow), Range(startCol, endCol));
//namedWindow("测试裁剪图片", WINDOW_FREERATIO);
//imshow("测试裁剪图片", cropped_image);
imshow("测试显示图片", cropped_image);
return cropped_image;
// 图像平移
Mat imageTranslation(Mat srcImage, int xOffset, int yOffset)
Size dst_sz = srcImage.size();
//定义平移矩阵
Mat t_mat = Mat::zeros(2, 3, CV_32FC1);
t_mat.at<float>(0, 0) = 1;
t_mat.at<float>(0, 2) = xOffset; //水平平移量
t_mat.at<float>(1, 1) = 1;
t_mat.at<float>(1, 2) = yOffset; //竖直平移量
//根据平移矩阵进行仿射变换
Mat TranslationMat;
warpAffine(srcImage, TranslationMat, t_mat, dst_sz);
//namedWindow("测试平移图片", WINDOW_FREERATIO);
//imshow("测试平移图片", TranslationMat);
imshow("测试显示图片", TranslationMat);
return TranslationMat;
int main(void)
Mat image =imread("123.png");
//namedWindow("测试显示图片", WINDOW_FREERATIO); // WINDOW_FREERATIO:可以手动调节大小
//imshow("测试显示图片", image);
//waitKey(0);
double angle = 120;
Mat imgRotate = imageRotate(image, angle);
waitKey(0);
float scale = 0.5;
Mat imgZoom = imageZoom(imgRotate, scale, scale);
waitKey(0);
Mat imgCut = imageCut(imgZoom, 50, 80, 200, 300);
waitKey(0);
imageTranslation(imgCut, 10, 20);
waitKey(0);
destroyAllWindows();
return 0;
3. 往图片中写入中文文字
记录一个类型转换:
// char* 转 wchar_t*
wchar_t wcha[255] = 0 ;
MultiByteToWideChar(CP_ACP, 0, text, strlen(text), wcha, 255);
putTextCN.h
#pragma once
#include <windows.h>
#include <string>
#include <opencv2/opencv.hpp>
using namespace cv;
// 内部调用
static void GetStringSize(HDC hDC, const char* str, int* w, int* h);
// 内部调用
static void putTextZH(Mat dst, const char* str, Point org, Scalar color, int fontSize,
const char *fn, bool italic, bool underline, bool lfWeight);
// 外部调用,往图片中写入文字
extern void putTextZh(InputOutputArray img,
const char *text,
Point org,
int fontSize,
Scalar color,
const char *font = "Arial",
bool italic = false,
bool underline = false,
bool lfWeight = false);
putTextCN.cpp
#include "putTextCN.h"
static void GetStringSize(HDC hDC, const char* str, int* w, int* h)
SIZE size;
GetTextExtentPoint32A(hDC, str, strlen(str), &size);
if (w != 0) *w = size.cx;
if (h != 0) *h = size.cy;
static void putTextZH(Mat dst, const char* str, Point org, Scalar color, int fontSize, const char* fn, bool italic, bool underline, bool lfWeight)
CV_Assert(dst.data != 0 && (dst.channels() == 1 || dst.channels() == 3));
int x, y, r, b;
if (org.x > dst.cols || org.y > dst.rows) return;
x = org.x < 0 ? -org.x : 0;
y = org.y < 0 ? -org.y : 0;
LOGFONTA lf;
lf.lfHeight = -fontSize;
lf.lfWidth = 0;
lf.lfEscapement = 0;
lf.lfOrientation = 0;
if (true == lfWeight) // 粗体
lf.lfWeight = 700;
else
lf.lfWeight = 400;
lf.lfItalic = italic; // 斜体
lf.lfUnderline = underline; // 下划线
lf.lfStrikeOut = 0;
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfOutPrecision = 0;
lf.lfClipPrecision = 0;
lf.lfQuality = PROOF_QUALITY;
lf.lfPitchAndFamily = 0;
strcpy_s(lf.lfFaceName, fn);
HFONT hf = CreateFontIndirectA(&lf);
HDC hDC = CreateCompatibleDC(0);
HFONT hOldFont = (HFONT)SelectObject(hDC, hf);
int strBaseW = 0, strBaseH = 0;
int singleRow = 0;
char buf[1 << 12];
strcpy_s(buf, str);
char *bufT[1 << 12]; // 这个用于分隔字符串后剩余的字符,可能会超出。
//处理多行
int nnh = 0;
int cw, ch;
const char* ln = strtok_s(buf, "\\n", bufT);
while (ln != 0)
GetStringSize(hDC, ln, &cw, &ch);
strBaseW = max(strBaseW, cw);
strBaseH = max(strBaseH, ch);
ln = strtok_s(0, "\\n", bufT);
nnh++;
singleRow = strBaseH;
strBaseH *= nnh;
if (org.x + strBaseW < 0 || org.y + strBaseH < 0)
SelectObject(hDC, hOldFont);
DeleteObject(hf);
DeleteObject(hDC);
return;
r = org.x + strBaseW > dst.cols ? dst.cols - org.x - 1 : strBaseW - 1;
b = org.y + strBaseH > dst.rows ? dst.rows - org.y - 1 : strBaseH - 1;
org.x = org.x < 以上是关于C/C++ vs2017 OpenCV简单入门的主要内容,如果未能解决你的问题,请参考以下文章