前言:
1.本文基于以下环境:Windows10 /C++ /OpenCV4.5.4 /Visual Studio2019 /OpenCV-contrib4.5.4
2.如果是版本不同,不用担心,每一步的思想都是相同的,如果有具体情况大家不会处理可以评论,你的问题大家一起解决。
前言:安装OpenCV-contrib之前我们首先要了解它是什么,干嘛用的,知己知彼百战不殆嘛。之后胡在慢慢了解怎么用它。
相较于之前我们安装的OpenCV是一个由多个模块、函数组成的用来坐计算机视觉开发的工具包而言,OpenCV-contrib是它的一个补充包,那为什么需要这个补充包呢,因为有一部分非常好的功能由于专利原因在OpenCV中没办法用所以在OpenCV-contrib中,我们也需要下载。
OpneCV-contrib 4.5.4的直接下载链接
大家不需要找什么国内开源网站,这个本身的下载速度就很快了。
这个是Github链接:https://github.com/opencv/opencv_contrib
这个速度会慢一点,但是可以自选版本。
下载后是一个.zip 的压缩文件,注意要将它解压在D:\opencv-4.5.4\opencv_contrib-4.x这个路径下(这个是我自己的路径,你可以解压在自己的路径下,尽量是相应版本的OpenCV文件夹下)。
之后需要用到一个工具:CMake编译工具
想要具体了解它是什么可以参考《CMake编译工具概述》
CMake下载地址:https://cmake.org/download/
CMake版本选择:因为之前的CMake版本不支持Visual Studio2019因此我下载的是3.20版本,如果你的是Visual Studio2015或者之前的版本下载3.7版本的CMake就可以了,如果是VS2017版本选3.9版本即可,不然后期容易出错。
下载好的是一个.exe可执行文件双击它就可以开始安装了,一路确定就完成安装了。
打开CMake图形界面在路径:D:\CMake\bin 中(这是我自己CMake的安装路径,大家在自己的文件夹中找到安装路径下的bin文件夹)打开后如下图所示:
编译前有两个需要设置:
1.source源文件:D:\opencv-4.5.4\opencv\sources 这个路径是之前安装OpenCV的路径下的source文件夹,大家找到自己的相应路径复制粘贴到上图的第一栏中。
2.编译后的目标路径:在OpenCV文件夹中创建一个newbuild 文件夹;选其为编译目标路径填入上图第二栏中;D:\opencv-4.5.4\opencv\newbuild 这是我自己的路径。
然后点击【Configure】按钮选择自己的VS版本(如下图所示:)
点击【Finish】,然后再点击【Configure】开始构建,出现"configuring done",构建完成。
此时在CMake界面中有很多变量,勾选上" BUILD_opencv_world"和" OPENCV_ENABLE_NONFREE"和" OPENCV_EXTRE_MODULESOPATH"变量
再次点击【Configure】(多点几次)直到所有红色变量变成白色,然后点击【Generate】开始编译
编译过程会比较慢,编译完成后在newbuild文件夹中找到OpenCV.sln文件
右键点击,打开方式,用VS2019打开(如下图所示:)
依次点击:生成>重新生成解决方案(如下图所示:)
然后在右侧的资源管理器中找到CMakeTargets中的INSTALL文件,右键选择“仅用于项目”>“仅生成INSTALL”,在newbuild 文件夹中生成一个install 文件夹。
注意:newbuild中有很多文件,其中只有install文件是重要文件,其他文件可以有选择的删除
以上OpneCV-contrib的安装就完成了。下一步就是配置环境啦!加油
在VS2019中新建一个项目依次点击“视图”>“其他窗口”>“属性管理器” (如下图所示:)
将上面的编译选择改成Debug X64
然后依次点击“Debug|x64”>“Microsoft.Cpp.x64.user”>“属性”(如下图所示:)
然后依次点击“VC++目录”>“包含目录”>“编辑”(如下图所示:)
添加下两个路径:
D:\opencv-4.5.4\opencv\newbuild\install\include
D:\opencv-4.5.4\opencv\newbuild\install\include\opencv2
注意:
这两个路径都是在刚才安装过程中生成的newbuild\install中的!!
一定不要弄错了
然后依次点击“链接器”>“输入”>“附加依赖项”>“编辑”(如下图所示:)
添加这个.lib:opencv_world454d.lib
然后全部应用确定完成VS2019的环境设置;
打开我的电脑>右键此电脑选择属性
点击高级属性设置
点击环境变量
编辑系统变量中的PATH
加入这个路径:D:\opencv-4.5.4\opencv\newbuild\install\bin
注意:
这个路径也是在刚才安装过程中生成的newbuild\install中的!!
一定不要弄错了,不要选成newbuild中的bin文件夹路径!!
好啦到这一步就完成全部的安装及环境配置步骤啦。下面来找一个样例试试手吧
在VS2019中创建一个新项目:
这是一个简单的二维码识别程序代码如下:
#include "opencv2/objdetect.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/imgcodecs.hpp"
#include
#include
using namespace std;
using namespace cv;
static int liveQRCodeDetect();
static int imageQRCodeDetect(const string& in_file);
static bool g_modeMultiQR = false;
static bool g_detectOnly = false;
static string g_out_file_name, g_out_file_ext;
static int g_save_idx = 0;
static bool g_saveDetections = false;
static bool g_saveAll = false;
static string getQRModeString()
{
std::ostringstream out;
out << "QR"
<< (g_modeMultiQR ? " multi" : "")
<< (g_detectOnly ? " detector" : " decoder");
return out.str();
}
int main(int argc, char *argv[])
{
const string keys =
"{h help ? | | print help messages }"
"{i in | | input image path (also switches to image detection mode) }"
"{detect | false | detect QR code only (skip decoding) }"
"{m multi | | use detect for multiple qr-codes }"
"{o out | qr_code.png | path to result file }"
"{save_detections | false | save all QR detections (video mode only) }"
"{save_all | false | save all processed frames (video mode only) }"
;
CommandLineParser cmd_parser(argc, argv, keys);
cmd_parser.about("This program detects the QR-codes from camera or images using the OpenCV library.");
if (cmd_parser.has("help"))
{
cmd_parser.printMessage();
return 0;
}
string in_file_name = cmd_parser.get<string>("in"); // path to input image
if (cmd_parser.has("out"))
{
std::string fpath = cmd_parser.get<string>("out"); // path to output image
std::string::size_type idx = fpath.rfind('.');
if (idx != std::string::npos)
{
g_out_file_name = fpath.substr(0, idx);
g_out_file_ext = fpath.substr(idx);
}
else
{
g_out_file_name = fpath;
g_out_file_ext = ".png";
}
}
if (!cmd_parser.check())
{
cmd_parser.printErrors();
return -1;
}
g_modeMultiQR = cmd_parser.has("multi") && cmd_parser.get<bool>("multi");
g_detectOnly = cmd_parser.has("detect") && cmd_parser.get<bool>("detect");
g_saveDetections = cmd_parser.has("save_detections") && cmd_parser.get<bool>("save_detections");
g_saveAll = cmd_parser.has("save_all") && cmd_parser.get<bool>("save_all");
int return_code = 0;
if (in_file_name.empty())
{
return_code = liveQRCodeDetect();
}
else
{
return_code = imageQRCodeDetect(samples::findFile(in_file_name));
}
return return_code;
}
static
void drawQRCodeContour(Mat &color_image, const vector<Point>& corners)
{
if (!corners.empty())
{
double show_radius = (color_image.rows > color_image.cols)
? (2.813 * color_image.rows) / color_image.cols
: (2.813 * color_image.cols) / color_image.rows;
double contour_radius = show_radius * 0.4;
vector< vector<Point> > contours;
contours.push_back(corners);
drawContours(color_image, contours, 0, Scalar(211, 0, 148), cvRound(contour_radius));
RNG rng(1000);
for (size_t i = 0; i < 4; i++)
{
Scalar color = Scalar(rng.uniform(0,255), rng.uniform(0, 255), rng.uniform(0, 255));
circle(color_image, corners[i], cvRound(show_radius), color, -1);
}
}
}
static
void drawFPS(Mat &color_image, double fps)
{
ostringstream convert;
convert << cv::format("%.2f", fps) << " FPS (" << getQRModeString() << ")";
putText(color_image, convert.str(), Point(25, 25), FONT_HERSHEY_DUPLEX, 1, Scalar(0, 0, 255), 2);
}
static
void drawQRCodeResults(Mat& frame, const vector<Point>& corners, const vector<cv::String>& decode_info, double fps)
{
if (!corners.empty())
{
for (size_t i = 0; i < corners.size(); i += 4)
{
size_t qr_idx = i / 4;
vector<Point> qrcode_contour(corners.begin() + i, corners.begin() + i + 4);
drawQRCodeContour(frame, qrcode_contour);
cout << "QR[" << qr_idx << "] @ " << Mat(qrcode_contour).reshape(2, 1) << ": ";
if (decode_info.size() > qr_idx)
{
if (!decode_info[qr_idx].empty())
cout << "'" << decode_info[qr_idx] << "'" << endl;
else
cout << "can't decode QR code" << endl;
}
else
{
cout << "decode information is not available (disabled)" << endl;
}
}
}
else
{
cout << "QR code is not detected" << endl;
}
drawFPS(frame, fps);
}
static
void runQR(
QRCodeDetector& qrcode, const Mat& input,
vector<Point>& corners, vector<cv::String>& decode_info
// +global: bool g_modeMultiQR, bool g_detectOnly
)
{
if (!g_modeMultiQR)
{
if (!g_detectOnly)
{
String decode_info1 = qrcode.detectAndDecode(input, corners);
decode_info.push_back(decode_info1);
}
else
{
bool detection_result = qrcode.detect(input, corners);
CV_UNUSED(detection_result);
}
}
else
{
if (!g_detectOnly)
{
bool result_detection = qrcode.detectAndDecodeMulti(input, decode_info, corners);
CV_UNUSED(result_detection);
}
else
{
bool result_detection = qrcode.detectMulti(input, corners);
CV_UNUSED(result_detection);
}
}
}
static
double processQRCodeDetection(QRCodeDetector& qrcode, const Mat& input, Mat& result, vector<Point>& corners)
{
if (input.channels() == 1)
cvtColor(input, result, COLOR_GRAY2BGR);
else
input.copyTo(result);
cout << "Run " << getQRModeString()
<< " on image: " << input.size() << " (" << typeToString(input.type()) << ")"
<< endl;
TickMeter timer;
vector<cv::String> decode_info;
timer.start();
runQR(qrcode, input, corners, decode_info);
timer.stop();
double fps = 1 / timer.getTimeSec();
drawQRCodeResults(result, corners, decode_info, fps);
return fps;
}
int liveQRCodeDetect()
{
VideoCapture cap(0);
if (!cap.isOpened())
{
cout << "Cannot open a camera" << endl;
return 2;
}
cout << "Press 'm' to switch between detectAndDecode and detectAndDecodeMulti" << endl;
cout << "Press 'd' to switch between decoder and detector" << endl;
cout << "Press ' ' (space) to save result into images" << endl;
cout << "Press 'ESC' to exit" << endl;
QRCodeDetector qrcode;
for (;;)
{
Mat frame;
cap >> frame;
if (frame.empty())
{
cout << "End of video stream" << endl;
break;
}
bool forceSave = g_saveAll;
Mat result;
try
{
vector<Point> corners;
double fps = processQRCodeDetection(qrcode, frame, result, corners);
cout << "FPS: " << fps << endl;
forceSave |= (g_saveDetections && !corners.empty());
//forceSave |= fps < 1.0;
}
catch (const cv::Exception& e)
{
cerr << "ERROR exception: " << e.what() << endl;
forceSave = true;
}
if (!result.empty())
imshow("QR code", result);
int code = waitKey(1);
if (code < 0 && !forceSave)
continue; // timeout
char c = (char)code;
if (c == ' ' || forceSave)
{
string fsuffix = cv::format("-%05d", g_save_idx++);
string fname_input = g_out_file_name + fsuffix + "_input.png";
cout << "Saving QR code detection input: '" << fname_input << "' ..." << endl;
imwrite(fname_input, frame);
string fname = g_out_file_name + fsuffix + g_out_file_ext;
cout << "Saving QR code detection result: '" << fname << "' ..." << endl;
imwrite(fname, result);
cout << "Saved" << endl;
}
if (c == 'm')
{
g_modeMultiQR = !g_modeMultiQR;
cout << "Switching QR code mode ==> " << (g_modeMultiQR ? "detectAndDecodeMulti" : "detectAndDecode") << endl;
}
if (c == 'd')
{
g_detectOnly = !g_detectOnly;
cout << "Switching QR decoder mode ==> " << (g_detectOnly ? "detect" : "decode") << endl;
}
if (c == 27)
{
cout << "'ESC' is pressed. Exiting..." << endl;
break;
}
}
cout << "Exit." << endl;
return 0;
}
int imageQRCodeDetect(const string& in_file)
{
const int count_experiments = 10;
Mat input = imread(in_file, IMREAD_COLOR);
cout << "Run " << getQRModeString()
<< " on image: " << input.size() << " (" << typeToString(input.type()) << ")"
<< endl;
QRCodeDetector qrcode;
vector<Point> corners;
vector<cv::String> decode_info;
TickMeter timer;
for (size_t i = 0; i < count_experiments; i++)
{
corners.clear();
decode_info.clear();
timer.start();
runQR(qrcode, input, corners, decode_info);
timer.stop();
}
double fps = count_experiments / timer.getTimeSec();
cout << "FPS: " << fps << endl;
Mat result; input.copyTo(result);
drawQRCodeResults(result, corners, decode_info, fps);
imshow("QR", result); waitKey(1);
if (!g_out_file_name.empty())
{
string out_file = g_out_file_name + g_out_file_ext;
cout << "Saving result: " << out_file << endl;
imwrite(out_file, result);
}
cout << "Press any key to exit ..." << endl;
waitKey(0);
cout << "Exit." << endl;
return 0;
}
此程序检测摄像头拍到的二维码并显示二维码信息