【Tools】这一次,彻底搞懂VS Code、C/C++、OpenCV

关于这篇博客

  还是第一次取这么标题党的题目。。。
  这是之前写的一篇关于使用VS Code配置C/C++和OpenCV的博客,但是最近遇到一点关于VS Code配置文件的问题,有点懵,翻找博客时联想到当时配置时也只是按照教程机械操作,对VS Code原理机制方面不了解,于是趁着帮同学再次配置OpenCV的契机,打算重构本博客,写一篇关于VS Code各种配置文件的原理和机制,授人与渔!

前言

  本文的重点将放在VS Code的原理和机制上,但是考虑直接讲原理方面会有些凌乱,于是打算从使用VS Code配置C/C++以及配置OpenCV的角度展开,讲解对各个配置文件的理解。在看下面的内容之前,你首先要有一点最基本的编译知识:

  • MinGW,Minimalist GNU for Windows,即GNU套装在Windows上的一个精简版,至于GNU的原理啥的不需要了解,只需要知道它内部有gcc,g++和gdb这些工具即可。其中gcc和g++是编译链接工具,可以生成执行文件exe,gdb是调试工具,需要输入编译链接好的exe文件。
  • VS Code本身只是一个编辑器,它不能编译C/C++,因此需要一个编译工具,在Windows上常用上面提到的MinGW

先来看看怎么配置C/C++

前情提要:由于VS Code更新太快,所以如果版本不同可能相关的界面和操作会有所区别,本文基于的版本为1.73.1,如果发现界面不同,不要惊慌,万变不离其宗,关键是掌握它的原理。

1 软件下载与安装

  这里简要介绍一下MinGW的安装教程。

  1. 打开链接后,下载小白版安装软件
    请添加图片描述
  2. 运行软件,设置一下参数即可
    在这里插入图片描述
  3. 然后就是选择路径,无脑下一步即可。

2 添加环境变量

  安装好MinGW之后,还需要将其路径添加到环境变量。操作简图如下。其中路径那里选择自己电脑上安装的路径即可。
在这里插入图片描述
  配置完之后,可以在VS Code的终端验证一下:

gcc --version #验证gcc
g++ --version #验证g++
gdb --version #验证gdb

如果不报找不到命令的错误,那表明配置成功了。如果报错,可以考虑重启终端(即重启VS Code),理论上来说差不多也够了,但保不齐会出什么bug,所以如果后面遇到啥问题,考虑一下重启电脑。

3 VS Code配置

这里需要注意,由于早期VS Code中的C++插件在右上角没有运行按钮,所以导致早期的教程都建议安装一个Code Runner插件,但是以目前的版本来看,其C++插件已经做得足够好用,不再需要安装Code Runner插件。

  VS Code这边,只需要安装一个插件即可,即C/C++。直接在扩展中搜索c++即可,一般第一个就是。
在这里插入图片描述

  安装好插件后,如果此时新建一个c或cpp文件,就可以发现已经有代码高亮了,还可以发现右上角多了一个三角形,可以用来运行和调试代码。此时随便建立一个cpp文件,然后点击运行,会出现一个悬浮窗让你选择使用那个编译器去运行代码。
在这里插入图片描述
一般选择g++或者gcc,差别不是特别大(更细节的咱也不懂。。。)

  点击之后就可以发现,在你工作区的.vscode文件夹下会自动生成一个tasks.json文件,如下图所示。
在这里插入图片描述

  于是,就来到了本文的一个重点:读懂tasks.json文件

  首先需要明确,这个文件是干什么的,如果愿意啃官方文档的可以看看这个链接。用直白的话来说,我认为,它的作用就是设置你安装的编译工具来对代码进行编译,也就是设置一个task。这样,当你设置好之后,下次需要编译时,只需要点击一个按钮即可,不再需要一条一条地敲命令。
  再来看看里面的各个属性。可以发现label项和command项就是你刚刚选择的编译器对应的信息。label的作用只是标注这个task,相当于一个ID,可以随便修改。command相当于点击运行按钮时执行的指令。
  除了这两个参数外,还需要重点关注另外两个项:argsoptions,其中options中的cwd项表示current work direction,即当前工作路径,这个是直接关系到你在代码里面读写文件时的相对路径中的./,非常重要!而其对应的值${fileDirname}可以理解为VS Code预定义的“宏”,就是表示文件所在文件夹的路径。除了这个之外,VS Code还提供了其他的“宏”供用户更改,如下图所示。【图片来自官方链接

在这里插入图片描述
这些变量在VS Code中编辑时会有代码提示,使用方便了不少。

  最后是args属性,这个是要输入到命令行中的,紧跟在command项后面,因此要和你设置的命令匹配。以g++为例的话,随意打开一个终端,输入g++ --help就能得到它能加的参数,如下图所示。

在这里插入图片描述
在这里插入图片描述
至于VS Code直接生成的默认tasks文件,其中-g表示启动调试,-o后面接的内容表示输出的exe文件。

4 是否要配置launch文件?

  配置好tasks之后,惊奇地发现,现在好像就可以进行运行和调试了,不再需要配置其他内容,但是如果翻以往的教程可以发现,此时应该是还得配置launch.json文件才对,这个估计就是VS Code更新的结果了。。。
  但是,如果不配置launch文件,在VS Code左边那里就没办法看到使用的调试器是啥(强迫症表示受不了),而且还不能配置调试。所以最好还是再配置一下launch文件,方法如下。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

另外,需要注意,早期的VS Code生成的默认launch文件是包含一个preLaunchTask属性,目前好像没有了,大胆猜测有可能是tasks一般情况下只有一个,所以默认执行了,如果一定要加的话,记得这一项要和tasks.json中的label项一致。

/* 2023.1.11更新 */
那个preLaunchTask属性必须得加上,它不会默认加上的!如果不加会导致调试的时候不会先编译一下,这样改动的代码也就失效了!

5 中英文和code runner

  通过这种方式配置好的c++编译和调试功能可以发现是不能运行更不能调试(这里注意区分运行和调试哦~)中文文件的【路径和文件都不能有中文】,其本质原因我认为是调试器gdb输入的exe文件不支持中文,否则会报错没有这个文件或者非法参数。因为在tasks文件中args属性中加了-g,但是实测发现即使注释掉-g也不好使,具体没太研究明白,有待后续探索。

  但是参考以往的教程可以发现,有一些还会装code runner插件,但其实code runner本质上只是帮你打命令而已,具体可以去看code runner设置中的executorMap,比如,cpp项的代码是这样的:

"cpp": "cd $dir && g++ $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt",

   &&相当于是命令的分界线,可以发现code runner首先是cd到你文件所在文件夹(保证了cwd),然后调用g++,编译你编写的文件,然后输出(-o)一个与代码文件同名但无后缀的exe文件,最后再运行这个exe文件。由于g++能够编译中文名文件,所以如果使用code runner,运行代码时基本不会出现因为文件名或路径是中文的报错。

  而上面的配置相当于是使用VS Code自带的cpp插件实现的,虽然也是调用MinGW套装,但是运行和调试似乎是密不可分的?具体不太懂。总之现在的问题在于不能运行和调试文件名或路径中含有中文的代码文件。通过参考这个链接,我找到了一种“骚方法”能够实现英文文件夹下的英文文件运行调试正常,中文文件能运行,但调试会有异常(就别调了);而中文文件夹下既不能调试,甚至运行都不行。 总的来说,如果有过往中文文件,只需要把它放在英文文件夹下即可运行(调试就别想了,除非改为英文名),操作也不是很复杂,而且还可以少一个code runner插件,赢!
  下面是操作方法。本质就是把生成的exe文件放到一个英文路径下,记得同时改tasks和launch文件就行。
在这里插入图片描述
在这里插入图片描述
这样操作还有一个好处就是不管运行多少文件,都只会有一个exe文件,干净了不少,再赢!

另外,不知道算不算不用code runner额外的好处,就是code runner似乎和最新的PowerShell7不兼容,如果要打印中文,老是会有乱码出现,而且用chcp还不能改。。。但是用c++插件运行和调试似乎都没有中文乱码的烦恼(如果有,建议把代码文件存为utf-8)

再来看看怎么配置OpenCV

  其实有了配置C++的基础,再配置OpenCV就简单了不少。这里假定你已经配置好了一个C++环境(就是上面的tasks和launch都配置好了)

1 下载OpenCV源码

  打开OpenCV官网可以发现,在它的Release下面有不同的选项可以下载,如下图所示。

在这里插入图片描述

如果是用Windows的话,可以选择Windows和Sources,它们的差别在于一个只有源码,一个除源码外,还有一个build文件夹。
在这里插入图片描述
那问题来了,既然它有build文件夹,为什么我们还要再次编译呢?emmm,关于这个的理解,我认为是编译器的不同,已有的build文件是Windows上(VS)常用的编译器(MSVC)编译得到的,所以它内部有VC14和VC15文件夹,所以如果是VS配置OpenCV,就不需要编译,只需要添加编译好的文件对应的路径即可,但是咱们VS Code配置用的是MinGW,所以还得编译一下。

那配置C++时能不用MinGW吗?是个好问题,找到一个VS Code配置MSVC的教程,有兴趣的可以参考一下。链接

  总的来说,如果只需要配置VS Code,就只下源码就行了,如果是还想配置VS,那就下载Windows版本。

2 编译OpenCV源码

  下载完源码后,并不能直接使用,还需要对源码进行编译。

  OpenCV配置最麻烦的就是编译这块,因为一旦编译错误,似乎很难找到问题所在。所以,如果有现成的编译好的文件,比如别人电脑上的文件,是可以直接复制过来使用的(实测有效!),但是要保证MinGW版本之间没差太多,而且尽量文件夹不要有空格!!!

  OpenCV源码一般都是使用CMake进行编译。首先要下载CMake:https://cmake.org/download/,安装好之后一定记得把bin文件夹添加到环境变量,然后打开cmake-gui。
在这里插入图片描述
进行一些简单的配置:
在这里插入图片描述
这里需要注意的是,放编译文件(Makefile)的文件夹可以自定义,但是建议和OpenCV放在一起(方便找)。
  这一步一般不会出错,如果出错,据说可以通过勾选和取消勾选中间的红色区域选项(具体不太懂,建议定点搜索),再次Configure并Generate,速度一般会比第一次快不少。

  配置好之后,接下来就是编译过程了,也是最容易出错的过程。其实就只有两步:

cd .... #先cd到放编译文件的文件夹下
minGW32-make -j 4 #4表示线程数,如果嫌不够可以继续加
minGW32-make install #等上一个指令运行到100%,再运行该指令即可

错误记录

  • error: ‘sleep_for’ is not a member of ‘std::this_thread‘:参考这个教程,是在代码gapi_async_test.cpp中添加一个头文件#include <thread> ,亲测确实有效!

3 添加环境变量

  编译好OpenCV后,会得到一个放编译文件的文件夹,也是需要添加到环境变量中。以我电脑上的版本为例,我把编译好的文件放在了x64/MinGW文件夹下,然后添加环境变量时,只需要添加该文件夹下的bin文件夹即可。
在这里插入图片描述

另外,如果要配置VS版本的OpenCV,记得把VC14和VC15的bin路径也添加到环境变量(本教程中用不到)。同理,配置完环境变量后,记得重启终端(重启VS Code)

4 配置VS Code

  前面提到,如果有现成的配置好的C++环境,这一步将非常简单,相当于只需要把OpenCV相关库文件添加进去即可。

  • tasks.json
{
    "tasks": [
        {
            "type": "cppbuild",
            "label": "C/C++: g++.exe 生成活动文件",
            "command": "C:\\Program Files\\MinGW_x64\\bin\\g++.exe",
            "args": [  //发现没有,在原C++基础上只需要改这个属性即可
                "${file}",
                "-I",
                "C:/Program Files/Opencv 4.5.1/build/include", //路径记得确认一下
                "-I",
                "C:/Program Files/Opencv 4.5.1/build/include/opencv2", //路径记得确认一下
                "-L",
                "C:/Program Files/Opencv 4.5.1/build/x64/MinGW/lib",//路径记得确认一下
                "-l",
                "libopencv_core451",
                "-l",
                "libopencv_imgproc451",
                "-l",
                "libopencv_imgcodecs451",
                "-l",
                "libopencv_video451",
                "-l",
                "libopencv_ml451",
                "-l",
                "libopencv_highgui451",
                "-l",
                "libopencv_objdetect451",
                "-l",
                "libopencv_flann451",
                "-l",
                "libopencv_imgcodecs451",
                "-l",
                "libopencv_photo451",
                "-l",
                "libopencv_videoio451",
                "-o",
                "${fileDirname}/${fileBasenameNoExtension}.exe"
            ],
            "options": {
                "cwd": "${fileDirname}"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "detail": "调试器生成的任务。"
        }
    ],
    "version": "2.0.0"
}

  这里简单解释一下吧,-I表示包含目录,即#include-L表示库目录,即需要包含进去的lib文件夹;-l表示link,即编译时需要链接的库。【似乎和VS配置OpenCV对上了?】至于需要链接哪些库,lib文件夹下的都加上就好了(.a后缀表示静态链接库)

  • launch.json
    没啥要改的,保持原样即可。

  • c_cpp_properties.json
      这个文件是设置C++插件的,理论上来说其实可以不需要管这个文件,但是如果不改的话,代码里面include那里会报错找不到文件,虽然不影响运行,但是呢,一方面是不方便查看源码(头文件定位不过去),另一方面就是画波浪线受不了呀~~
      一般设置这个有两种方式:
      一种是修改C++插件的设置。如下图所示。
    在这里插入图片描述
    但是亲测发现,虽然能打开头文件,但是仍然会有波浪线,强迫症表示受不了。。。

      于是,建议采用下面的方式:
    在这里插入图片描述
    在这里插入图片描述
    一般会打开一个C++插件的设置,然后添加进去OpenCV的路径即可。或者直接打开命令面板(Ctrl + Shift + P),输入c++,得到下图。
    在这里插入图片描述
    总之,最后本质上就是在修改c_cpp_properties.json文件,也不需要改很多,只需要添加两个路径即可,如下图所示。
    在这里插入图片描述

  到此,include画波浪线的问题就解决了,OpenCV也配置完了。

总结

  总结一下,不管是配置C++还是OpenCV或者其他什么框架,最关键的就是理解各个部分的作用是什么,代码运行的逻辑是什么,各个插件的定位是什么。VS Code是一个很好的工具,但是也得花一点时间研究一下它的使用方式。

其他问题拾遗

  考虑到以后还得继续使用VS Code,这部分的内容还是继续保留吧,以后遇到什么问题也会继续更新。

1 code runner使用

  • 外部控制台运行
      coderunner作为vs code的“官方运行代码的插件,可以说功能很强大了,但是也有一部分问题,其中一个就是运行代码只能在内部终端运行,无法在外部控制台运行,但是调试还是可以在外部控制台输入的,这个可以通过设置调整。
      无意间找到一个教程,发现其实在外部控制台运行也是可以的,只需要改变一下coderunner的设置即可,直接看教程链接吧。但是经过我的测试,发现其实这个教程也有一定的问题,比如会闪退(必须要在最后加上system(“PAUSE”) 才行)

  • 设置code runner允许中文名,允许空格
      之所以会存在这个问题,是因为code runner中提供的预定义的“宏”有一些没有引号,有一些又有,傻傻分不清楚【所以建议不要用
    在这里插入图片描述
    复制代码如下:

 "c": "cd $dir && gcc $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt",    //原始代码
//"c": "g++ $fullFileName -o $fileNameWithoutExt.exe && start $fileNameWithoutExt.exe",//更改后可以使得.c文件运行在外部窗口
 
//"cpp": "cd $dir && g++ $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt",  //原始代码
"cpp": "cd $dir && g++ -std=c++17 \"$fileName\" -o \"run\" && .\\\"run\"", //更改后可以使文件夹中只有一个run.exe执行文件,且可以避免文件名空格问题
//"cpp": "g++ $fullFileName -o $fileNameWithoutExt.exe && start $fileNameWithoutExt.exe", //更改后可以使cpp文件在外部终端运行
//"cpp": "cd $dir && g++ $fullFileName -o run && start run",//外部终端,同时运行可以只有一个run.exe执行文件

2 一个关于VS Code使用比较细致的教程

link

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
YOLO (You Only Look Once) is an object detection algorithm that uses deep neural networks to detect objects in real-time. OpenCV is a popular computer vision library that provides various tools and functions for image processing and computer vision tasks. To use YOLO with OpenCV in C++, you need to follow these steps: 1. Download the YOLOv3 weights and configuration files from the official website. 2. Load the model using OpenCV's dnn module. 3. Read the input image and preprocess it. 4. Pass the image through the model to get the output. 5. Postprocess the output to get the object detection results. 6. Draw bounding boxes around the detected objects and display the output image. Here's a sample code that demonstrates how to use YOLO with OpenCV in C++: ``` #include <iostream> #include <opencv2/opencv.hpp> using namespace std; using namespace cv; int main() { // Load YOLOv3 model String modelWeights = "yolov3.weights"; String modelConfiguration = "yolov3.cfg"; dnn::Net net = dnn::readNetFromDarknet(modelConfiguration, modelWeights); // Read input image Mat image = imread("input.jpg"); // Preprocess input image Mat blob = dnn::blobFromImage(image, 1/255.0, Size(416, 416), Scalar(0,0,0), true, false); // Set input for the network net.setInput(blob); // Get output from the network vector<Mat> outs; net.forward(outs, net.getUnconnectedOutLayersNames()); // Postprocess the output float confThreshold = 0.5; vector<int> classIds; vector<float> confidences; vector<Rect> boxes; for (size_t i = 0; i < outs.size(); ++i) { // Extract information from the output Mat output = outs[i]; for (int j = 0; j < output.rows; ++j) { Mat scores = output.row(j).colRange(5, output.cols); Point classId; double confidence; minMaxLoc(scores, 0, &confidence, 0, &classId); if (confidence > confThreshold) { // Get bounding box coordinates int centerX = static_cast<int>(output.at<float>(j, 0) * image.cols); int centerY = static_cast<int>(output.at<float>(j, 1) * image.rows); int width = static_cast<int>(output.at<float>(j, 2) * image.cols); int height = static_cast<int>(output.at<float>(j, 3) * image.rows); int left = centerX - width / 2; int top = centerY - height / 2; // Save detection results classIds.push_back(classId.x); confidences.push_back(static_cast<float>(confidence)); boxes.push_back(Rect(left, top, width, height)); } } } // Draw bounding boxes around the detected objects vector<String> classNames = {"person", "car", "bus", "truck"}; vector<Scalar> colors = {Scalar(0, 0, 255), Scalar(255, 0, 0), Scalar(0, 255, 0), Scalar(255, 255, 0)}; for (size_t i = 0; i < boxes.size(); ++i) { rectangle(image, boxes[i], colors[classIds[i]], 2); String label = format("%.2f", confidences[i]); label = classNames[classIds[i]] + ":" + label; int baseLine; Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine); rectangle(image, Point(boxes[i].x, boxes[i].y - labelSize.height - baseLine), Point(boxes[i].x + labelSize.width, boxes[i].y), colors[classIds[i]], FILLED); putText(image, label, Point(boxes[i].x, boxes[i].y - baseLine), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255,255,255)); } // Display the output image imshow("YOLO Object Detection", image); waitKey(0); return 0; } ``` Note that this sample code is for YOLOv3 and may need to be modified for other versions of YOLO. Also, make sure to download the correct weights and configuration files for the version you are using.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

记录无知岁月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值