forked from acai66/opencv_matching
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 2090a6a
Showing
18 changed files
with
2,767 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[submodule "3rdParty/spdlog"] | ||
path = 3rdParty/spdlog | ||
url = https://github.com/gabime/spdlog |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
cmake_minimum_required(VERSION 3.9 FATAL_ERROR) | ||
|
||
project(matching VERSION 1.0.0) | ||
|
||
if(CMAKE_HOST_SYSTEM_NAME MATCHES "Windows") | ||
set(OpenCV_DIR ${PROJECT_SOURCE_DIR}/3rdParty/opencv) | ||
endif() | ||
|
||
find_package(OpenCV REQUIRED) | ||
include_directories(${OPENCV_INCLUDE_DIRS}) | ||
link_directories(${OPENCV_LIBRARY_DIRS}) | ||
|
||
set(CMAKE_CXX_STANDARD 17) | ||
|
||
find_package( OpenMP REQUIRED) | ||
if(OPENMP_FOUND) | ||
message("OPENMP FOUND") | ||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") | ||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") | ||
set(CMAKE_EXE_LINKER_FLAGS"${CMAKE_EXE_LINKER_FLAGS}${OpenMP_EXE_LINKER_FLAGS}") | ||
endif() | ||
|
||
if (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "aarch64") | ||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") | ||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3") | ||
endif() | ||
|
||
option(BUILD_SHARED_LIBS "Specifies the type of libraries (SHARED or STATIC) to build" ON) | ||
|
||
include_directories( | ||
${PROJECT_SOURCE_DIR}/3rdParty/spdlog/include | ||
include | ||
matcher | ||
) | ||
|
||
add_executable(demo "demo.cpp") | ||
target_link_libraries(demo ${OpenCV_LIBS}) | ||
if(UNIX) | ||
target_link_libraries(demo dl) | ||
endif() | ||
|
||
#安装规则 | ||
install(TARGETS demo | ||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} | ||
) | ||
install(FILES | ||
"demo.cpp" | ||
DESTINATION ${CMAKE_INSTALL_PREFIX} | ||
) | ||
|
||
add_subdirectory(matcher) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
BSD 2-Clause License | ||
|
||
Copyright (c) 2022, DennisLiu1993 | ||
All rights reserved. | ||
|
||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions are met: | ||
|
||
1. Redistributions of source code must retain the above copyright notice, this | ||
list of conditions and the following disclaimer. | ||
|
||
2. Redistributions in binary form must reproduce the above copyright notice, | ||
this list of conditions and the following disclaimer in the documentation | ||
and/or other materials provided with the distribution. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
## 模板匹配 | ||
|
||
- 基于[Fastest Image Pattern Matching](https://github.com/DennisLiu1993/Fastest_Image_Pattern_Matching) | ||
|
||
### 改进 | ||
|
||
1. 封装为更易用的库 | ||
2. 跨平台适配 | ||
|
||
### 计划 | ||
|
||
- [ ] 优化代码结构 | ||
- [x] 支持python |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
1 VERSIONINFO | ||
FILEVERSION ${PROJECT_VERSION_MAJOR}, ${PROJECT_VERSION_MINOR}, ${PROJECT_VERSION_PATCH} | ||
PRODUCTVERSION ${PROJECT_VERSION_MAJOR}, ${PROJECT_VERSION_MINOR}, ${PROJECT_VERSION_PATCH} | ||
FILEFLAGSMASK 0x17L | ||
#ifdef _DEBUG | ||
FILEFLAGS 0x1L | ||
#else | ||
FILEFLAGS 0x0L | ||
#endif | ||
FILEOS 0x4L | ||
FILETYPE 0x0L | ||
FILESUBTYPE 0x0L | ||
BEGIN | ||
BLOCK "StringFileInfo" | ||
BEGIN | ||
BLOCK "040904b0" | ||
BEGIN | ||
VALUE "FileDescription", "ģ��ƥ���" | ||
VALUE "FileVersion", "${PROJECT_VERSION_MAJOR}, ${PROJECT_VERSION_MINOR}, ${PROJECT_VERSION_PATCH}" | ||
VALUE "InternalName", "Matching" | ||
VALUE "LegalCopyright", " Copyright (C) 2024" | ||
VALUE "OriginalFilename", "templatematching.dll" | ||
VALUE "ProductName", "Matching" | ||
VALUE "ProductVersion", "${PROJECT_VERSION_MAJOR}, ${PROJECT_VERSION_MINOR}, ${PROJECT_VERSION_PATCH}" | ||
END | ||
END | ||
BLOCK "VarFileInfo" | ||
BEGIN | ||
VALUE "Translation", 0x409, 1200 | ||
END | ||
END |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,236 @@ | ||
#include <stdlib.h> | ||
#include <math.h> | ||
#include <filesystem> // C++17 标准库中的文件系统库 | ||
namespace fs = std::filesystem; | ||
|
||
#include "matcher.h" | ||
#ifdef _WIN32 | ||
#include "windows.h" | ||
#else | ||
#include <dlfcn.h> | ||
#endif // _WIN32 | ||
|
||
|
||
// 动态库函数指针 | ||
typedef template_matching::Matcher* (*InitMD)(const template_matching::MatcherParam); | ||
|
||
cv::Rect box; | ||
bool drawing_box = false; | ||
bool change_template = false; | ||
|
||
// 鼠标回调函数,用于绘制 ROI | ||
void mouse_callback(int event, int x, int y, int, void*) | ||
{ | ||
switch (event) | ||
{ | ||
case cv::EVENT_MOUSEMOVE: | ||
if (drawing_box) | ||
{ | ||
box.width = x - box.x; | ||
box.height = y - box.y; | ||
} | ||
break; | ||
case cv::EVENT_LBUTTONDOWN: | ||
drawing_box = true; | ||
box = cv::Rect(x, y, 0, 0); | ||
break; | ||
case cv::EVENT_LBUTTONUP: | ||
drawing_box = false; | ||
change_template = true; | ||
if (box.width < 0) | ||
{ | ||
box.x += box.width; | ||
box.width *= -1; | ||
} | ||
if (box.height < 0) | ||
{ | ||
box.y += box.height; | ||
box.height *= -1; | ||
} | ||
break; | ||
} | ||
} | ||
|
||
int main(int argc, char** argv) | ||
{ | ||
std::string templateImgPath = "C:\\Users\\acai1\\Desktop\\t2\\需求1-线扫相机图\\t2.png"; | ||
std::string imagePath = "C:\\Users\\acai1\\Desktop\\t2\\需求1-线扫相机图\\1.bmp"; | ||
|
||
if (argc == 3) | ||
{ | ||
templateImgPath = std::string(argv[1]); | ||
imagePath = std::string(argv[2]); | ||
} | ||
|
||
// 读图 | ||
cv::Mat templateImg = imread(templateImgPath, cv::IMREAD_GRAYSCALE); | ||
cv::Mat image = imread(imagePath, cv::IMREAD_GRAYSCALE); | ||
if (templateImg.empty() || image.empty()) { | ||
std::cout << "Image: empty." << std::endl; | ||
} | ||
|
||
// 匹配器参数 | ||
template_matching::MatcherParam param; | ||
param.angle = 0; | ||
param.iouThreshold = 0; | ||
param.matcherType = template_matching::MatcherType::PATTERN; | ||
param.maxCount = 1; | ||
param.minArea = 256; | ||
param.scoreThreshold = 0.5; | ||
|
||
// 匹配结果 | ||
std::vector<template_matching::MatchResult> matchResults; | ||
|
||
#ifdef _WIN32 | ||
// windows 动态加载dll | ||
HINSTANCE handle = nullptr; | ||
handle = LoadLibrary("templatematching.dll"); | ||
if (handle == nullptr) | ||
{ | ||
std::cerr << "Error : failed to load templatematching.dll!" << std::endl; | ||
return -2; | ||
} | ||
|
||
// 获取动态库内的函数 | ||
InitMD myGetMatcher; | ||
myGetMatcher = (InitMD)GetProcAddress(handle, "GetMatcher"); | ||
#else | ||
// linux 动态加载dll | ||
void* handle = nullptr; | ||
handle = dlopen("libtemplatematching.so", RTLD_LAZY); | ||
if (handle == nullptr) | ||
{ | ||
std::cerr << "Error : failed to load libtemplatematching.so!" << std::endl; | ||
return -2; | ||
} | ||
|
||
// 获取动态库内的函数 | ||
InitMD myGetMatcher; | ||
myGetMatcher = (InitMD)dlsym(handle, "GetMatcher"); | ||
#endif // _WIN32 | ||
// std::cout << "Load getDetector." << std::endl; | ||
|
||
// 初始化匹配器 | ||
std::cout << "initiating..." << std::endl; | ||
template_matching::Matcher* matcher = myGetMatcher(param); | ||
std::cout << "initialized." << std::endl; | ||
|
||
if (matcher) | ||
{ | ||
matcher->setMetricsTime(true); | ||
|
||
std::chrono::steady_clock::time_point startTime, endTime; | ||
std::chrono::duration<double> timeUse; | ||
|
||
// 打开0号摄像头 | ||
cv::VideoCapture cap(0); | ||
if (!cap.isOpened()) | ||
{ | ||
std::cerr << "Error: failed to open camera." << std::endl; | ||
return -1; | ||
} | ||
// 设置摄像头分辨率 | ||
//cap.set(cv::CAP_PROP_FRAME_WIDTH, 1920); | ||
//cap.set(cv::CAP_PROP_FRAME_HEIGHT, 1080); | ||
// 设置摄像头编码 | ||
//cap.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M', 'J', 'P', 'G')); | ||
|
||
cv::namedWindow("frame"); | ||
cv::setMouseCallback("frame", mouse_callback); | ||
|
||
// 读取摄像头图像 | ||
cv::Mat frame, drawFrame, roi; | ||
while (true) | ||
{ | ||
cap >> frame; | ||
if (frame.empty()) | ||
{ | ||
std::cerr << "Error: failed to read frame." << std::endl; | ||
break; | ||
} | ||
|
||
cv::Mat drawFrame = frame.clone(); | ||
if (drawFrame.channels() == 1) | ||
{ | ||
cv::cvtColor(drawFrame, drawFrame, cv::COLOR_GRAY2BGR); | ||
} | ||
|
||
if (drawing_box) | ||
cv::rectangle(drawFrame, box, cv::Scalar(0, 0, 255), 2); | ||
else if (box.area() > 0) | ||
{ | ||
if (change_template) | ||
{ | ||
//cv::rectangle(drawFrame, box, cv::Scalar(0, 255, 0), 2); | ||
roi = frame(box); | ||
//cv::imshow("ROI", roi); | ||
cv::cvtColor(roi, roi, cv::COLOR_BGR2GRAY); | ||
matcher->setTemplate(roi); | ||
change_template = false; | ||
} | ||
|
||
} | ||
|
||
startTime = std::chrono::steady_clock::now(); | ||
|
||
// 执行匹配,结果保存在 matchResults | ||
cv::Mat frame_gray; | ||
cv::cvtColor(frame, frame_gray, cv::COLOR_BGR2GRAY); | ||
matcher->match(frame_gray, matchResults); | ||
|
||
endTime = std::chrono::steady_clock::now(); | ||
timeUse = std::chrono::duration_cast<std::chrono::duration<double>>(endTime - startTime); | ||
std::cout << "match time: " << timeUse.count() << "s." << std::endl; | ||
|
||
// 可视化查看 | ||
|
||
for (int i = 0; i < matchResults.size(); i++) | ||
{ | ||
cv::Point2i temp; | ||
std::vector<cv::Point2i> pts; | ||
temp.x = std::round(matchResults[i].LeftTop.x); | ||
temp.y = std::round(matchResults[i].LeftTop.y); | ||
pts.push_back(temp); | ||
temp.x = std::round(matchResults[i].RightTop.x); | ||
temp.y = std::round(matchResults[i].RightTop.y); | ||
pts.push_back(temp); | ||
temp.x = std::round(matchResults[i].RightBottom.x); | ||
temp.y = std::round(matchResults[i].RightBottom.y); | ||
pts.push_back(temp); | ||
temp.x = std::round(matchResults[i].LeftBottom.x); | ||
temp.y = std::round(matchResults[i].LeftBottom.y); | ||
pts.push_back(temp); | ||
|
||
cv::polylines(drawFrame, pts, true, cv::Scalar(0, 255, 0), 1, cv::LINE_8); | ||
} | ||
|
||
|
||
// 显示图像,按ESC或q退出 | ||
cv::imshow("frame", drawFrame); | ||
char key = cv::waitKey(1); | ||
if (key == 27 || key == 'q' || key == 'Q') | ||
{ | ||
break; | ||
} | ||
} | ||
|
||
delete matcher; | ||
|
||
} | ||
else | ||
{ | ||
std::cerr << "Error: failed to get matcher." << std::endl; | ||
} | ||
|
||
// 释放 windows 动态库 | ||
if (handle != nullptr) | ||
{ | ||
#ifdef _WIN32 | ||
FreeLibrary(handle); | ||
#else | ||
dlclose(handle); | ||
#endif // _WIN32 | ||
} | ||
|
||
return 0; | ||
} |
Oops, something went wrong.