Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
acai66 committed Apr 8, 2024
0 parents commit 2090a6a
Show file tree
Hide file tree
Showing 18 changed files with 2,767 additions and 0 deletions.
457 changes: 457 additions & 0 deletions .gitignore

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions .gitmodules
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
1 change: 1 addition & 0 deletions 3rdParty/spdlog
Submodule spdlog added at a2b426
51 changes: 51 additions & 0 deletions CMakeLists.txt
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)
25 changes: 25 additions & 0 deletions LICENSE
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.
13 changes: 13 additions & 0 deletions README.md
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
31 changes: 31 additions & 0 deletions VersionInfo.rc.in
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
236 changes: 236 additions & 0 deletions demo.cpp
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;
}
Loading

0 comments on commit 2090a6a

Please sign in to comment.