学习opencv3中文版 笔记

    技术2023-10-03  74

    一些概念

    计算机视觉: 将静止的图像,或者是视频转换成一个决策或者一种新的表达方式,这些转化都是为了达到一个目标。 且输入数据可以包含一些辅助信息,比如摄像机架在物品之上,激光扫描仪在一米处发现一个物体。

    本质:把具有噪声成分的数值矩阵变成感知

    视觉问题的病态本质: 随着视点的变化,物体的二维外观会变化很大。同一张二维图像,可以表示多种三维场景。 具体的问题: 数据被噪声和形变影响。

    [ 😱] 一些疑问点:

    “一般来说不可能通过比较一个点和它紧密相连的点来检测图像里的边缘”,所以问题是如何进行边缘检测? 书中提到的“观察一个局部区域的统计特征,边缘检测会变得容易些”是什么意思呢? “由局部区域卷积的响应连成的点串,构成边缘” 又是什么意思呢?

    opencv的结构和内容 opencv主体分为5个模块, CV图像处理和视觉算法, MLL统计分类器, HighGUI图像和视频输入/输出, CXCORE基本机构和算法+XML支持+绘图函数, CvAux

    HighGUI常用: 里面提供读取各种类型的图像文件,视频内容以及摄像机输入的功能。

    安装配置opencv

    踩坑1: 未找到依赖 dll文件 解决方式: 设置环境变量,Path中加入opencv/build/x64/bin的路径,然后重启!

    踩坑2 :MFC和win32项目的区别? 这个博主有解释 目前还是不清楚,win32中包含许多基本的API,MFC中包含很多类库,可通过类库间接使用API win32程序更加的底层,MFC程序可以调用win32?

    踩坑3 : 无法打开元数据文件 “platform.winmd” 首先 元数据文件platform.winmd是什么? 解决方式就是重新创建了一下项目,莫名其妙的不再报错,有可能是在配置vs时debug和x64在对应配置目录时没有选择对应的选项。

    踩坑4 cmake是干嘛的?

    2-1 展示图片

    #include <iostream> #include <opencv2/opencv.hpp> using namespace cv; int main() { Mat srcImg = imread("C://Users//lfy//opencv//1.jpg"); namedWindow("Example1", WINDOW_AUTOSIZE); imshow("Example1", srcImg); waitKey(0); return 0; }

    踩坑1: 在加载某个图像时,出现未经处理的异常 解决方式: 认为是路径格式的问题 ,必须是:// 而不能是:\

    2-2 播放视频

    代码如下:

    #include<iostream> #include<opencv2/highgui/highgui.hpp> #include<opencv2/imgproc/imgproc.hpp> using namespace std; using namespace cv; int main(int argc, char **argv) { namedWindow("exp2-3", cv::WINDOW_AUTOSIZE); VideoCapture cap; cap.open(string(argv[1])); Mat frame; for (;;) { cap >> frame; if (frame.empty())break; // ran out of file imshow("exp2-3", frame); if (waitKey(33) >= 0) break; } return 0; }

    踩坑1: 如果直接运行程序会报错,因为argv[1]没有设定,会报strlen处的一个错误。 实际运行过程应该是右键项目->属性->调试->命令参数处填入相应的参数。

    知识点:

    实例化VedioCapture类型是为了播放以及停止各种类型的视频VedioCapture的open函数打开一个视频,然后定义一个Mat类型的frame,将vedio一帧帧导入frame,即 cap>>framewaitKey()参数是秒数,可以控制视频播放每一帧之间的间隔

    2-3 Moving around- 为视频增加一个slider tracker

    操作: 按下s键,一步一步播放,按下R键,切换为流畅地播放 创建tracker,我们用到了createTrackbar()函数

    #include<opencv2/highgui/highgui.hpp> #include<opencv2/imgproc/imgproc.hpp> #include<iostream> #include<fstream> using namespace std; using namespace cv; int g_slider_position = 0; int g_run = 1, g_dontset = 0; // start out in single step mode VideoCapture g_cap; void onTrackbarSlide(int pos, void*) { g_cap.set(CAP_PROP_POS_FRAMES, pos); // 将滑块对应的数值赋值给起始帧 if (!g_dontset) g_run = 1; g_dontset = 0; // 但是如果这个回调函数被用户点击触发,此处使得在新的下一帧未到达时,保持单步模式。 // 具体g_dontset是什么意思还没有搞清楚,g_run是一个控制播放模式的变量,给g_run=1时表示单步播放即显示当前这一帧,g_run=-1时开始正常播放。 } int main(int argc, char** argv) { namedWindow("exp2-4", WINDOW_AUTOSIZE); g_cap.open(string(argv[1])); int frames = (int)g_cap.get(CAP_PROP_FRAME_COUNT); int tmpw = (int)g_cap.get(CAP_PROP_FRAME_WIDTH); int tmph = (int)g_cap.get(CAP_PROP_FRAME_HEIGHT); cout << " video has " << frames << "frames of dimensions(" << tmpw << "," << tmph << ")." << endl; createTrackbar("position", "exp2-4", &g_slider_position,frames,onTrackbarSlide); // createTrackbar的四个参数! Mat frame; for (;;) { // 当g_run=-1播放,当g_run=1只播放1帧图片 if (g_run != 0) { g_cap >> frame; if (frame.empty())break; int current_pos = (int)g_cap.get(CAP_PROP_POS_FRAMES); g_dontset = 1; setTrackbarPos("position", "exp2-4", current_pos); imshow("exp2-4", frame); g_run -= 1; } // 每播完一帧到如下程序, // 如果此时g_run=1时,下次循环进入if后 g_run-=1 =>0, 如果不按下r使g_run!=0,则视频不会再播放,单独显示下一帧 // 如果此时g_run=-1时,下次进入if后不断减一,一直不等于0则可以一直播放下一帧。 char c = (char)waitKey(10); if (c == 's') { g_run = 1; cout << "single step,run=" << g_run << endl; } if (c == 'r') { g_run = -1; cout << "run mode,run=" << g_run << endl; } if (c == 27) { break; } } return 0; }

    createTrackbar的四个参数 setTrackbarPos的搭配使用 VideoCapture的get()方法

    2-4 A Simple Transformation

    smoothing an image, 通过高斯或者其他卷积运算,减少图像中的信息内容

    下述程序的作用:在视频显示之前加载并且平滑图像

    #include<opencv2/opencv.hpp> using namespace cv; void example2_5(const Mat &image) { // 创建一些窗口去显示输入和输出图像 namedWindow("example2_5-in", WINDOW_AUTOSIZE); namedWindow("example2_5-out1", WINDOW_AUTOSIZE); namedWindow("example2_5-out2", WINDOW_AUTOSIZE); imshow("example2_5-in", image); Mat out; // 平滑处理 GaussianBlur(image, out, Size(5, 5), 3, 3); // 被5*5的卷积核进行高斯滤波,且高斯核通常为奇数,为什么呢? 忘记了... imshow("example2_5-out1", out); // 以下是第二次卷积所得 GaussianBlur(out, out, Size(5, 5), 3, 3); // 在输出窗口展示平滑后的图像 imshow("example2_5-out2", out); waitKey(0); } int main() { Mat srcImg=imread("C://Users//lfy//opencv//1.jpg"); example2_5(srcImg); return 0; }

    踩坑1:异常: cv::Exception,位于内存位置… 本以为是传参的格式问题,看了半天发现是图片的路径写错的问题啦 !

    2-5 A Not-SO-Simple Transformation

    图像降采样,用到了pyrdown()函数,先将图像高斯模糊,再进行降采样。 pyrdown()函数 对这个函数的一些解释 摘要:我们在对图像进行处理时,大多是要着眼于图像中有意义的部分,而同一幅图像中可能含有不同尺度下“有意义”的信息,为了充分利用这些图像信息,就需要对图像进行多尺度描述了。

    /* 创造新的图像,是原图像长宽的一半 */ #include<opencv2/opencv.hpp> using namespace cv; int main() { Mat img1, img2; namedWindow("exp1", WINDOW_AUTOSIZE); namedWindow("exp2", WINDOW_AUTOSIZE); img1 = imread("C://Users//lfy//opencv//1.jpg"); imshow("exp1", img1); pyrDown(img1, img2); imshow("exp2", img2); waitKey(0); return 0; }

    canny函数

    /* cv.candy 可以用于边缘检测,首先要把图像转换为单通道的图像,用cvtColor变为灰度图像 */ #include<opencv2/opencv.hpp> using namespace cv; int main() { Mat img_rgb, img_gry, img_cny; namedWindow("exp gray", WINDOW_AUTOSIZE); namedWindow("exp canny", WINDOW_AUTOSIZE); img_rgb = imread("C://Users//lfy//opencv//1.jpg"); cvtColor(img_rgb, img_gry, COLOR_BGR2GRAY); imshow("exp gray", img_gry); Canny(img_gry, img_cny, 10, 100, 3, true); imshow("exp canny", img_cny); waitKey(0); }

    canny函数:

    void cvCanny( const CvArr* image, CvArr* edges, double threshold1,double threshold2, int aperture_size=3 );

    参数image: 单通道输入图像 参数edges: 单通道存储边缘的输出图像 参数threshold1: 阈值1 参数threshold2: 阈值2 参数aperture_size: sobel算子的核大小

    疑问:两个阈值中,小阈值控制边缘的连接,大阈值控制强边缘的分割?

    2-6 Input from a camera

    2-7 writing into an avi file: logPolar函数,调用了摄像头

    #include<opencv2/opencv.hpp> #include<iostream> using namespace cv; int main() { namedWindow("exp2-11", WINDOW_AUTOSIZE); namedWindow("Log_Polar", WINDOW_AUTOSIZE); VideoCapture capture(0); double fps = capture.get(CAP_PROP_FPS); Size size( (int)capture.get(CAP_PROP_FRAME_WIDTH), (int)capture.get(CAP_PROP_FRAME_HEIGHT) ); VideoWriter writer; writer.open("C://Users//lfy//opencv",-1,fps,size); Mat logpolar_frame, bgr_frame; for (;;) { capture >> bgr_frame; if (bgr_frame.empty())break; imshow("exp2_11", bgr_frame); logPolar( bgr_frame, logpolar_frame, Point2f( bgr_frame.cols / 2, // x bgr_frame.rows / 2 // y ), 40, // 幅 比例尺参数? WARP_FILL_OUTLIERS //Fill outliers with zero ); imshow("Log_Polar", logpolar_frame); writer << logpolar_frame; char c = cv::waitKey(10); if (c == 27)break; } capture.release(); }

    VideoWriter: writer需要打开一个文件夹,且VideoWriter.open()有许多个参数。 参数1: 文件夹的路径 参数2:视频压缩的解码器 using the macro CV_FOURCC(),这个会报错啦? 参数3:重播帧速率 参数4:将使用的图片大小

    LogPolar

    chapter 3 Getting to Know OpenCV Data Types

    Processed: 0.020, SQL: 9