目录

简单的变换

不那么简单的变换

cv::pyrDown()

cv::Canny() & cv::cvtColor()

从摄像头中读取

写入AVI文件

练习


简单的变换

许多基础的计算机视觉工作都包括对视频流使用滤波器。

一个最简单的操作就是对图像的平滑处理,这将通过高斯核或者其他核卷积效减小图像的信息量。

#include <opencv2/opencv.hpp>using namespace std;int main()
{cv::namedWindow("Example2-5-in", cv::WINDOW_AUTOSIZE);cv::namedWindow("Example2-5-out", cv::WINDOW_AUTOSIZE);cv::Mat image = cv::imread("./images/girl.jpg");cv::imshow("Example2-5-in", image);cv::Mat out;cv::GaussianBlur(image, out, cv::Size(5, 5), 3, 3);cv::GaussianBlur(out, out, cv::Size(5, 5), 3, 3);cv::imshow("Example2-5-out", out);cv::waitKey();cv::destroyAllWindows();return EXIT_SUCCESS;
}

实例化一个输出矩阵out,这将由程序自行管理并在合适的时候自动分配、释放内存。

将原始图像输入到两个cv::GaussianBlur()函数中,输入图像被5*5大小的高斯核模糊并且写入out中。

注意:高斯核的大小必须时奇数,因为高斯卷积会在其覆盖区域的中心输出结果。

不那么简单的变换

cv::pyrDown()

使用高斯模糊对一张图像实现基2的降采样。如果要进行多次的降采样,就要建立一个尺度空间(图像金字塔),这一方法是计算机视觉用于处理传感器和目标尺度变化的常用手段之一。

对信号的降采样等效于和一系列脉冲函数进行卷积(将这些函数视为“峰值”)。

在OpenCV中,高斯模糊以及降采样通过 cv::pyrDown()函数来实现。

void cv::pyrDown(    InputArray src,OutputArray dst,const Size & dstsize = Size(),int borderType = BORDER_DEFAULT
)   

size of the output image is computed as Size((src.cols+1)/2, (src.rows+1)/2), but in any case, the following conditions should be satisfied:

输出图像的大小以公式 Size((src.cols+1)/2, (src.rows+1)/2) 计算所得,但是在任何例子中,下面两个条件需要被满足。

//示例2-6 使用cv::pyrDown()来创建一个新的图像,其宽高均为原始图像的一半
#include <opencv2/opencv.hpp>using namespace std;int main()
{cv::Mat img1, img2;cv::namedWindow("Example1", cv::WINDOW_AUTOSIZE);cv::namedWindow("Example2", cv::WINDOW_AUTOSIZE);img1 = cv::imread("./images/girl.jpg");cv::imshow("Example1", img1);cv::pyrDown(img1, img2);cv::imshow("Example2", img2);cv::waitKey();return EXIT_SUCCESS;
}

cv::Canny() & cv::cvtColor()

//示例2-7:Canny边缘检测器输出一个单通道的(灰度)图像
#include <opencv2/opencv.hpp>using namespace std;int main()
{cv::Mat img_rgb, img_gry, img_cny;cv::namedWindow("Example_Gray", cv::WINDOW_AUTOSIZE);cv::namedWindow("Example_Canny", cv::WINDOW_AUTOSIZE);img_rgb = cv::imread("./images/girl.jpg");cv::cvtColor(img_rgb, img_gry, cv::COLOR_BGR2GRAY);cv::imshow("Example_Gray", img_gry);cv::Canny(img_gry, img_cny, 10, 100, 3, true);cv::imshow("Example_Canny", img_cny);cv::waitKey();return EXIT_SUCCESS;
}

cv::Canny()

void cv::Canny(inputArray,       //image:输入图像(8-bit)outputArray,       //edges:输出图像(单通道,8-bit,size与输入图像一致)double,          //threshold1:阈值1double,         //threshold2:阈值2int,                //apertureSize = 3: Sober算子大小bool              //L2gradient = false:是否采用更精确的方式计算图像梯度);void cv::Canny(inputArray,      //dx:输入图像在x方向的导数:16-bit(CV_16SC1 & CV_16SC3)inputArray,        //dy:输入图像在y方向的导数:16-bit(CV_16SC1 & CV_16SC3)outputArray,       //edges:输出边缘图像(单通道,8-bit,size与输入图像一致)double,            //threshold1:阈值1double,         //threshold2:阈值2bool                //L2gradient = false:是否采用更精确的方式计算图像梯度);

关于阈值:小于 阈值1 不是边缘,介于阈值1与阈值2之间的是弱边缘,大于阈值2的是强边缘

关于L2gradient参数:

如果为true,计算图像梯度的时候会使用:(更加准确)

如果是false,计算图像梯度的时候使用:

//示例2-8:在一个简单图像处理流程中结合图像金字塔操作(两次)和Canny边缘检测器
//示例2-9:读写示例2-8的像素值
#include <iostream>
#include <opencv2/opencv.hpp>using namespace std;int main()
{cv::Mat img_rgb, img_gry, img_cny, img_pyr, img_pyr2;cv::namedWindow("Example_Gray", cv::WINDOW_AUTOSIZE);cv::namedWindow("Example_Canny", cv::WINDOW_AUTOSIZE);img_rgb = cv::imread("./images/girl.jpg");cv::cvtColor(img_rgb, img_gry, cv::COLOR_BGR2GRAY);cv::pyrDown(img_gry, img_pyr);cv::pyrDown(img_pyr, img_pyr2);cv::Canny(img_pyr2, img_cny,10, 100, 3, true);int x = 16, y = 32;cv::Vec3b intensity = img_rgb.at<cv::Vec3b>(y, x);uchar blue = intensity[0];uchar green = intensity[1];uchar red = intensity[2];cout << "At(x, y) = (" << x << "," << y << "):(blue, green, red) = (" << (unsigned int)blue << ","<< (unsigned int)green << "," << (unsigned int)red << ")" << endl;cout << "Gray pixel there is : " << (unsigned int)img_gry.at<uchar>(y, x) << endl;x /= 4;y /= 4;cout << "Gray pixel there is : " << (unsigned int)img_gry.at<uchar>(y, x) << endl;img_cny.at<uchar>(x, y) = 128;cv::waitKey();return EXIT_SUCCESS;
}

从摄像头中读取

OpenCV的HighGui模块提供了摄像头接口。

使用cv::VideoCapture()从硬盘读取视频和摄像头有一致的接口。

对于前者:只需要提供读取文件的路径

对于后者:需要给它一个相机ID号(如果只有一个摄像头连接,这个ID号通常是0),ID的默认是-1,意味着 随意选择一个摄像头

#include <iostream>
#include <string>
#include <stdlib.h>
#include <opencv2/opencv.hpp>using namespace std;int main()
{cv::namedWindow("Example2_10", cv::WINDOW_AUTOSIZE);cv::VideoCapture cap;cap.open(0);cv::Mat frame;if (!cap.isOpened()){cout << "Couldn't open capture!" << endl;return -1;}while (1){cap >> frame;if (frame.empty()){cout << "图片写入失败" << endl;return -1;}cv::imshow("Example2_10", frame);if (cv::waitKey(33) >= 0) //手动退出,任意键退出{break;}}cv::destroyAllWindows();return EXIT_SUCCESS;
}

写入AVI文件

创建一个写入对象以便将帧依次输入到一个视频文件中,允许我们进行这个工作的对象是cv::VideoWriter.

一旦将其实例化,可以将每一帧图像输入到cv::VideoWriter对象中,在完成写入之后调用cv::VideoWriter.release()方法。

//示例2-11:一个完整的读取彩色视频并转换为对数极坐标视频的程序
#include <iostream>
#include <opencv2/opencv.hpp>using namespace std;int main()
{cv::namedWindow("Example2_11", cv::WINDOW_AUTOSIZE);cv::namedWindow("Log_Polar", cv::WINDOW_AUTOSIZE);cv::VideoCapture cap;cap.open("./images/bike.avi");double fps = cap.get(cv::CAP_PROP_FPS);cv::Size size((int)cap.get(cv::CAP_PROP_FRAME_WIDTH),(int)cap.get(cv::CAP_PROP_FRAME_HEIGHT));cv::VideoWriter writer;writer.open("log_bike.avi", CV_FOURCC('M', 'J', 'P', 'G'), fps, size, true);//注意writer写入文件的名称,需要加上后缀名cv::Mat logpolar_frame, bgr_frame;while (1){cap >> bgr_frame;if (bgr_frame.empty()){break;}cv::imshow("Example2_11", bgr_frame);cv::logPolar(bgr_frame,logpolar_frame,cv::Point2f(bgr_frame.cols/2,bgr_frame.rows/2),40,cv::WARP_FILL_OUTLIERS);cv::imshow("Log_Polar", logpolar_frame);writer << logpolar_frame;char c = cv::waitKey(33);if (c == 27){break;}}cap.release();return EXIT_SUCCESS;
}

cv::VideoWriter的调用参数:

第一个参数是新建视频文件的文件名;

第二个参数是视频编码方式,指明视频将以何种方式进行压缩;

第三个参数是视频的帧率;

第四个参数是视频的Size。

cv::logPolar的调用参数:Log-polor转换表示从笛卡尔坐标到极坐标的变换

void cvLogPolar( const CvArr* src,   //输入图像CvArr* dst,           //输出图像CvPoint2D32f center,      //变换的中心,输出图像在这里最清晰double M,          //幅度的尺度参数int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS );

flags:插值方法和以下选择标志的结合

  1. CV_WARP_FILL_OUTLIERS -填充输出图像所有像素,如果这些点有和外点对应的,则置零。

  2. CV_WARP_INVERSE_MAP - 表示矩阵由输出图像到输入图像的逆变换,并且因此可以直接用于像素插值。否则,函数从map_matrix中寻找逆变换。

练习

3、将示例2-11和2-6中的代码连接起来,建立一个读取视频并存储降采样后的彩色图像的程序。

4、修改练习3中的代码,并结合示例2-2中窗口显示的代码来显示处理的图像

#include <iostream>
#include <string>
#include <stdlib.h>
#include <opencv2/opencv.hpp>using namespace std;
int main()
{cv::namedWindow("Example2_11", cv::WINDOW_AUTOSIZE);cv::namedWindow("pyr_image", cv::WINDOW_AUTOSIZE);cv::VideoCapture cap;cap.open("./images/bike.avi");double fps = cap.get(cv::CAP_PROP_FPS);cv::Size size((int)cap.get(cv::CAP_PROP_FRAME_WIDTH),(int)cap.get(cv::CAP_PROP_FRAME_HEIGHT));cv::VideoWriter writer;writer.open("log_bike_pyr.avi", CV_FOURCC('M', 'J', 'P', 'G'), fps, size, true);cv::Mat pyr_frame, bgr_frame;while (1){cap >> bgr_frame;if (bgr_frame.empty()){break;}cv::imshow("Example2_11", bgr_frame);cv::pyrDown(bgr_frame, pyr_frame);cv::imshow("pyr_image", pyr_frame);writer << pyr_frame;char c = cv::waitKey(33);if (c == 27){break;}}cap.release();return EXIT_SUCCESS;
}

5、修改4,添加一个示例2-4中的滑动条,用户可以动态控制金字塔的降采样等级(从2-8)。可以跳过存储的步骤,但要将处理结果显示出来。

//问题:进度条的数字不能随进度条的改变而改变,初始程序无法自动播放视频,需要手动点击进度条,由于能力有限,仅完成以下部分。
#include <iostream>
#include <string>
#include <stdlib.h>
#include <opencv2/opencv.hpp>using namespace std;int g_slider_position = 2;
int g_old_position = 2;
bool g_dontset = false;
cv::VideoCapture g_cap;
cv::Mat pyr_frame, bgr_frame;
int g_frames;
int n = 0;void onTrackbarSlide(int pos, void*)
{while (1){if (g_old_position != g_slider_position){g_old_position = g_slider_position;cv::destroyWindow("pyr_image");cv::namedWindow("pyr_image", cv::WINDOW_AUTOSIZE);}if (n == g_frames - 1){g_cap.set(CV_CAP_PROP_POS_FRAMES, 1);n = 0;}n++;g_cap >> bgr_frame;if (bgr_frame.empty()){break;}cv::imshow("Example2_11", bgr_frame);for (int i = 1; i < pos; i++){cv::pyrDown(bgr_frame, bgr_frame);}cv::imshow("pyr_image", bgr_frame);char c = cv::waitKey(33);if (c == 27){break;}}
}int main()
{cv::namedWindow("Example2_11", cv::WINDOW_AUTOSIZE);cv::namedWindow("pyr_image", cv::WINDOW_AUTOSIZE);g_cap.open("./images/bike.avi");double fps = g_cap.get(cv::CAP_PROP_FPS);cv::Size size((int)g_cap.get(cv::CAP_PROP_FRAME_WIDTH),(int)g_cap.get(cv::CAP_PROP_FRAME_HEIGHT));int frames = (int)g_cap.get(cv::CAP_PROP_FRAME_COUNT);int tmpw = (int)g_cap.get(cv::CAP_PROP_FRAME_WIDTH);int tmph = (int)g_cap.get(cv::CAP_PROP_FRAME_HEIGHT);g_frames = frames;cv::createTrackbar("Position", "Example2_11", &g_slider_position, 8, onTrackbarSlide);cv::waitKey();return EXIT_SUCCESS;
}

学习OpenCV(2)OpenCV初探-2相关推荐

  1. Opencv学习笔记之OpenCV介绍

    一.  OpenCV介绍 OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux.Windows.Android和Mac OS操作系统上.它轻量级而且高效--由一系列 ...

  2. 基础学习笔记之opencv(14):随机数发生器绘制文字

    本文主要介绍下opencv中自带的一个随机数发生器的类RNG,这里我用这个类来画一些图形,和基础学习笔记之opencv(13):基本绘图 一文中类似,只是 这里画出来图像的坐标,大小,颜色,角度等所有 ...

  3. 【OpenCV学习】 《OpenCV3编程入门》--毛星云 01 邂逅OpenCV(OpenCV基本概念与基本架构) ROS系统上的运用(python实现)

    对 <OpenCV3编程入门>第一章的学习笔记:理解什么是计算机视觉,什么是OpenCV,以及其中的联系等等. PS:此书为2014年出版,opencv的版本和接口也与现在有些不一致了,作 ...

  4. 2021年学习CV和OpenCV的五个最佳网课

    本文将分享学习Computer Vision和OpenCV的最佳网课.这些课程适合想学习计算机视觉和Open CV的高级概念的初学者和经验丰富的程序员.它是机器学习和人工智能中最突出领域之一,并已在各 ...

  5. OpenCV学习笔记#002 OpenCV相机检校例程运行

    OpenCV学习笔记#002 OpenCV相机检校例程运行 OpenCV学习笔记#002 OpenCV相机检校例程运行 所需文件 修改文件 修改in_VID5.xml 修改VID5.xml VS 设置 ...

  6. 【机器视觉学习笔记】OpenCV C++的安装、配置及多版本共存 (VS2015)

    目录 下载 (可选 -- 二选一)添加环境变量 新建项目和配置 配置包含目录 配置库目录 添加库 (可选 -- 二选一)添加dll文件的路径 测试 平台:Windows 10 20H2 Visual ...

  7. 如何学习才能精通opencv

    在线教程 OpenCV Tutorials opencv中文论坛 数字图像处理英文第四版 图像处理基础理论论述与软件实践方法相结合的第一本书,它集成了冈萨雷斯和伍兹所著的<数字图像处理>一 ...

  8. 暑期科研见习总结:移动设备上的深度学习与模型剪枝初探

    本次暑期科研见习,我有机会初步了解了人工智能的深度学习和模型压缩的基本内容,并在移动设备(树莓派3B)上进行了一些简单的深度学习模型训练.在见习结束之际,总结一下这次学习的内容,也期待之后能够继续在相 ...

  9. 学习OpenCV-(1)-安装与初探

    文章目录 学习OpenCV-(1)-安装与初探 1.概述 下载和安装 OpenCV所拥有的模块 2.初探 1.显示图片 2.显示视频 3.简单的变换 4.不那么简单的变换 5.从摄像头中读取 6.写入 ...

  10. 如何在ARM开发板上从源码编译安装OpenCV和OpenCV contrib

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 本文主要介绍如何在ARM开发板上从源码编译安装OpenCV和OpenCV contrib. OpenC ...

最新文章

  1. iOS架构设计-URL缓存(上)
  2. 腾讯优图开源业界首个3D医疗影像大数据预训练模型
  3. OpenGL SDK glew(OpenGL Extension Wrangler Library )
  4. 【自动驾驶】21.左手坐标系和右手坐标系
  5. 09.snapshot and restore操作
  6. ACM Fellow发文抨击【同行评审】作弊轻松中顶会
  7. ant+jenkins+testng+selenium集成环境搭建
  8. 管状合金电阻和片状合金电阻的区别_SAE 6118、高电阻合金际锻材
  9. Vector3.MoveTowards与Vector3.Lerp()区别
  10. 开源项目推荐ruoyi
  11. win10电脑桌面透明便签_win10系统在桌面添加透明便签的操作方法
  12. 思科模拟器路由器常见问题及操作记录
  13. 【汇编程序】实现判断输入的年份是否为闰年
  14. 物联网建设,智慧城市道路智能交通解决方案
  15. 计算机网络软件系统是什么结构,计算机软件系统的组成是什么?
  16. webpack不报错但是图标和字体却无法显示
  17. Redis源码学习(14),t_set.c 学习(二),sismember,scard,spop 命令学习
  18. jQuery的页面加载完毕事件?
  19. 元宇宙,小荷才露尖尖角
  20. 养肾=养命!这7个最伤肾的行为你犯了吗?程序员收藏

热门文章

  1. Ubuntu安装wine和Wine QQ
  2. sql server2014使用BULK INSERT导入UTF-8数据中文乱码问题
  3. 解析offsetHeight,clientHeight,scrollHeight之间的区别
  4. 【数学建模】传染病SIR模型
  5. EDI系统-AS2传输常见问题
  6. Jsoup——抓取图片
  7. 台达EH3系列PLC进行MODBUS RTU通信的具体方法和步骤(非常详细)
  8. python滑动验证_Python实现图片滑动式验证识别方法
  9. 九齐单片机NY8B062D项目开发总结
  10. VM14 安装黑苹果教程步骤