Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
3409395778 | |||
36392b3e34 | |||
726a55725a | |||
338c1dcf96 | |||
6dd78fbe21 | |||
665559d8ca | |||
8758d7801d | |||
fc4f04b9be |
@ -2,16 +2,38 @@ cmake_minimum_required(VERSION 3.12)
|
|||||||
|
|
||||||
project(match)
|
project(match)
|
||||||
find_package(OpenCV REQUIRED)
|
find_package(OpenCV REQUIRED)
|
||||||
add_executable(${PROJECT_NAME}
|
|
||||||
main.cpp
|
#==============================================================
|
||||||
|
#library
|
||||||
|
#==============================================================
|
||||||
|
add_library(algo SHARED
|
||||||
grayMatch.h
|
grayMatch.h
|
||||||
grayMatch.cpp
|
grayMatch.cpp
|
||||||
|
serialize.cpp
|
||||||
|
privateType.h
|
||||||
|
apiExport.h
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(algo PRIVATE ${OpenCV_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(algo ${OpenCV_LIBRARIES})
|
||||||
|
target_compile_options(algo PRIVATE
|
||||||
|
$<$<CXX_COMPILER_ID:MSVC>:/W4 /WX /external:W0>
|
||||||
|
$<$<STREQUAL:${CMAKE_SYSTEM_NAME},Linux>: -mlsx -fPIC -fvisibility=hidden -Wl,--exclude-libs,ALL -Wall -Wextra -Wpedantic -Wmisleading-indentation -Wunused -Wuninitialized -Wshadow -Wconversion -Werror>
|
||||||
|
$<$<AND:$<CXX_COMPILER_ID:Clang>,$<STREQUAL:${CMAKE_SYSTEM_NAME},Windows>>:/W4 /WX /external:W0>
|
||||||
|
)
|
||||||
|
target_compile_definitions(algo PUBLIC API_EXPORTS)
|
||||||
|
|
||||||
|
#==============================================================
|
||||||
|
#exe
|
||||||
|
#==============================================================
|
||||||
|
add_executable(${PROJECT_NAME}
|
||||||
|
main.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(${PROJECT_NAME} PRIVATE ${OpenCV_INCLUDE_DIRS})
|
target_include_directories(${PROJECT_NAME} PRIVATE ${OpenCV_INCLUDE_DIRS})
|
||||||
target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBRARIES})
|
target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBRARIES} algo)
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE
|
target_compile_options(${PROJECT_NAME} PRIVATE
|
||||||
$<$<CXX_COMPILER_ID:MSVC>:/W4 /WX /external:W0>
|
$<$<CXX_COMPILER_ID:MSVC>:/W4 /WX /external:W0>
|
||||||
$<$<STREQUAL:${CMAKE_SYSTEM_NAME},Linux>:-fPIC -fvisibility=hidden -Wall -Wextra -Wpedantic -Wmisleading-indentation -Wunused -Wuninitialized -Wshadow -Wconversion -Werror>
|
$<$<STREQUAL:${CMAKE_SYSTEM_NAME},Linux>: -fPIC -fvisibility=hidden -Wall -Wextra -Wpedantic -Wmisleading-indentation -Wunused -Wuninitialized -Wshadow -Wconversion -Werror>
|
||||||
$<$<AND:$<CXX_COMPILER_ID:Clang>,$<STREQUAL:${CMAKE_SYSTEM_NAME},Windows>>:/W4 /WX /external:W0>
|
$<$<AND:$<CXX_COMPILER_ID:Clang>,$<STREQUAL:${CMAKE_SYSTEM_NAME},Windows>>:/W4 /WX /external:W0>
|
||||||
)
|
)
|
||||||
|
31
apiExport.h
Normal file
31
apiExport.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__)
|
||||||
|
#define API_EXPORT __declspec(dllexport)
|
||||||
|
#define API_IMPORT __declspec(dllimport)
|
||||||
|
#define API_LOCAL
|
||||||
|
#elif defined(linux) || defined(__linux) || defined(__linux__)
|
||||||
|
#define API_EXPORT __attribute__((visibility("default")))
|
||||||
|
#define API_IMPORT __attribute__((visibility("default")))
|
||||||
|
#define API_LOCAL __attribute__((visibility("hidden")))
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
#define API_EXPORT __attribute__((visibility("default")))
|
||||||
|
#define API_IMPORT __attribute__((visibility("default")))
|
||||||
|
#define API_LOCAL __attribute__((visibility("hidden")))
|
||||||
|
#else
|
||||||
|
#define API_EXPORT
|
||||||
|
#define API_IMPORT
|
||||||
|
#define API_LOCAL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define API_DEMANGLED extern "C"
|
||||||
|
#else
|
||||||
|
#define API_DEMANGLED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef API_EXPORTS
|
||||||
|
#define API_PUBLIC API_DEMANGLED API_EXPORT
|
||||||
|
#else
|
||||||
|
#define API_PUBLIC API_DEMANGLED API_IMPORT
|
||||||
|
#endif
|
186
grayMatch.cpp
186
grayMatch.cpp
@ -1,6 +1,8 @@
|
|||||||
#include "grayMatch.h"
|
#include "grayMatch.h"
|
||||||
|
#include "privateType.h"
|
||||||
|
|
||||||
#include <opencv2/core/hal/intrin.hpp>
|
#include <opencv2/core/hal/intrin.hpp>
|
||||||
|
#include <opencv2/opencv.hpp>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
constexpr int MIN_AREA = 256;
|
constexpr int MIN_AREA = 256;
|
||||||
@ -8,37 +10,6 @@ constexpr double TOLERANCE = 0.0000001;
|
|||||||
constexpr int CANDIDATE = 5;
|
constexpr int CANDIDATE = 5;
|
||||||
constexpr double INVALID = -1.;
|
constexpr double INVALID = -1.;
|
||||||
|
|
||||||
struct Model {
|
|
||||||
std::vector<cv::Mat> pyramids;
|
|
||||||
std::vector<cv::Scalar> mean;
|
|
||||||
std::vector<double> normal;
|
|
||||||
std::vector<double> invArea;
|
|
||||||
std::vector<bool> equal1;
|
|
||||||
uchar borderColor = 0;
|
|
||||||
|
|
||||||
void clear() {
|
|
||||||
pyramids.clear();
|
|
||||||
normal.clear();
|
|
||||||
invArea.clear();
|
|
||||||
mean.clear();
|
|
||||||
equal1.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void resize(const std::size_t size) {
|
|
||||||
normal.resize(size);
|
|
||||||
invArea.resize(size);
|
|
||||||
mean.resize(size);
|
|
||||||
equal1.resize(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void reserve(const std::size_t size) {
|
|
||||||
normal.reserve(size);
|
|
||||||
invArea.reserve(size);
|
|
||||||
mean.reserve(size);
|
|
||||||
equal1.reserve(size);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BlockMax {
|
struct BlockMax {
|
||||||
struct Block {
|
struct Block {
|
||||||
cv::Rect rect;
|
cv::Rect rect;
|
||||||
@ -197,19 +168,10 @@ cv::Size computeRotationSize(const cv::Size &dstSize, const cv::Size &templateSi
|
|||||||
cv::Point2d min = trans[ 0 ];
|
cv::Point2d min = trans[ 0 ];
|
||||||
cv::Point2d max = trans[ 0 ];
|
cv::Point2d max = trans[ 0 ];
|
||||||
for (const auto &point : trans) {
|
for (const auto &point : trans) {
|
||||||
if (point.x < min.x) {
|
min.x = std::min(min.x, point.x);
|
||||||
min.x = point.x;
|
min.y = std::min(min.y, point.y);
|
||||||
}
|
max.x = std::max(max.x, point.x);
|
||||||
if (point.y < min.y) {
|
max.y = std::max(max.y, point.y);
|
||||||
min.y = point.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (point.x > max.x) {
|
|
||||||
max.x = point.x;
|
|
||||||
}
|
|
||||||
if (point.y > max.y) {
|
|
||||||
max.y = point.y;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (angle > 0 && angle < 90) {
|
if (angle > 0 && angle < 90) {
|
||||||
@ -299,7 +261,7 @@ void coeffDenominator(const cv::Mat &src, const cv::Size &templateSize, cv::Mat
|
|||||||
|
|
||||||
#ifdef CV_SIMD
|
#ifdef CV_SIMD
|
||||||
float convSimd(const uchar *kernel, const uchar *src, const int kernelWidth) {
|
float convSimd(const uchar *kernel, const uchar *src, const int kernelWidth) {
|
||||||
const auto blockSize = cv::VTraits<cv::v_uint8>::vlanes();
|
const auto blockSize = cv::v_uint8::nlanes;
|
||||||
auto vSum = cv::vx_setall_u32(0);
|
auto vSum = cv::vx_setall_u32(0);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (; i < kernelWidth - blockSize; i += blockSize) {
|
for (; i < kernelWidth - blockSize; i += blockSize) {
|
||||||
@ -338,7 +300,7 @@ void matchTemplate(cv::Mat &src, cv::Mat &result, const Model *model, int level)
|
|||||||
cv::matchTemplate(src, model->pyramids[ level ], result, cv::TM_CCORR);
|
cv::matchTemplate(src, model->pyramids[ level ], result, cv::TM_CCORR);
|
||||||
#endif
|
#endif
|
||||||
coeffDenominator(src, model->pyramids[ level ].size(), result, model->mean[ level ][ 0 ],
|
coeffDenominator(src, model->pyramids[ level ].size(), result, model->mean[ level ][ 0 ],
|
||||||
model->normal[ level ], model->invArea[ level ], model->equal1[ level ]);
|
model->normal[ level ], model->invArea[ level ], model->equal1[ level ] == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nextMaxLoc(const cv::Point &pos, const cv::Size templateSize, const double maxOverlap,
|
void nextMaxLoc(const cv::Point &pos, const cv::Size templateSize, const double maxOverlap,
|
||||||
@ -436,8 +398,9 @@ void filterOverlap(std::vector<Candidate> &candidates, const std::vector<cv::Rot
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto area = cv::contourArea(points);
|
const auto area = cv::contourArea(points);
|
||||||
const auto overlap = area / rect.size.area();
|
const auto overlap =
|
||||||
|
area / static_cast<double>(rect.size.width * rect.size.height);
|
||||||
if (overlap > maxOverlap) {
|
if (overlap > maxOverlap) {
|
||||||
(candidate.score > refCandidate.score ? refCandidate.score
|
(candidate.score > refCandidate.score ? refCandidate.score
|
||||||
: candidate.score) = INVALID;
|
: candidate.score) = INVALID;
|
||||||
@ -454,8 +417,8 @@ Model *trainModel(const cv::Mat &src, int level) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (level < 0) {
|
if (level <= 0) {
|
||||||
// level must greater than 1
|
// level must greater than 0
|
||||||
level = computeLayers(src.size().width, src.size().height, MIN_AREA);
|
level = computeLayers(src.size().width, src.size().height, MIN_AREA);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -731,3 +694,126 @@ std::vector<Pose> matchModel(const cv::Mat &dst, const Model *model, int level,
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Model_t trainModel(const unsigned char *data, int width, int height, int channels, int bytesPerline,
|
||||||
|
int roiLeft, int roiTop, int roiWidth, int roiHeight, int levelNum) {
|
||||||
|
if ((1 != channels && 3 == channels && 4 == channels) || nullptr == data) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto type = channels == 1 ? CV_8UC1 : (channels == 3 ? CV_8UC3 : CV_8UC4);
|
||||||
|
cv::Mat img(cv::Size(width, height), type, (void *)data, bytesPerline);
|
||||||
|
|
||||||
|
cv::Mat src;
|
||||||
|
if (1 == channels) {
|
||||||
|
src = img;
|
||||||
|
} else {
|
||||||
|
cv::cvtColor(img, src, channels == 3 ? cv::COLOR_RGB2GRAY : cv::COLOR_RGBA2GRAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::Rect rect(roiLeft, roiTop, roiWidth, roiHeight);
|
||||||
|
cv::Rect imageRect(0, 0, width, height);
|
||||||
|
auto roi = rect & imageRect;
|
||||||
|
if (roi.empty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return trainModel(src(roi), levelNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
void matchModel(const unsigned char *data, int width, int height, int channels, int bytesPerline,
|
||||||
|
int roiLeft, int roiTop, int roiWidth, int roiHeight, const Model_t model,
|
||||||
|
int *count, Pose *poses, int level, double startAngle, double spanAngle,
|
||||||
|
double maxOverlap, double minScore, int subpixel) {
|
||||||
|
if (nullptr == count) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nullptr == poses || nullptr == data) {
|
||||||
|
*count = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1 != channels && 3 != channels && 4 != channels) {
|
||||||
|
*count = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto type = channels == 1 ? CV_8UC1 : (channels == 3 ? CV_8UC3 : CV_8UC4);
|
||||||
|
cv::Mat img(cv::Size(width, height), type, (void *)data, bytesPerline);
|
||||||
|
|
||||||
|
cv::Mat dst;
|
||||||
|
if (1 == channels) {
|
||||||
|
dst = img;
|
||||||
|
} else {
|
||||||
|
cv::cvtColor(img, dst, channels == 3 ? cv::COLOR_RGB2GRAY : cv::COLOR_RGBA2GRAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::Rect rect(roiLeft, roiTop, roiWidth, roiHeight);
|
||||||
|
cv::Rect imageRect(0, 0, width, height);
|
||||||
|
auto roi = rect & imageRect;
|
||||||
|
if (roi.empty()) {
|
||||||
|
*count = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = matchModel(dst(roi), model, level, startAngle, spanAngle, maxOverlap, minScore,
|
||||||
|
*count, subpixel);
|
||||||
|
|
||||||
|
auto size = std::min(*count, static_cast<int>(result.size()));
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
const auto &pose = result[ i ];
|
||||||
|
poses[ i ] = {pose.x + static_cast<float>(roi.x), pose.y + static_cast<float>(roi.y),
|
||||||
|
pose.angle, pose.score};
|
||||||
|
}
|
||||||
|
|
||||||
|
*count = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void freeModel(Model_t *model) {
|
||||||
|
if (nullptr == model || nullptr == *model) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete *model;
|
||||||
|
*model = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int modelLevel(const Model_t model) {
|
||||||
|
if (nullptr == model) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<int>(model->pyramids.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void modelImage(const Model_t model, int level, unsigned char *data, int length, int *width,
|
||||||
|
int *height, int *channels) {
|
||||||
|
if (nullptr == model) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (level < 0 || level > static_cast<int>(model->pyramids.size() - 1)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &img = model->pyramids[ level ];
|
||||||
|
if (nullptr != width) {
|
||||||
|
*width = img.cols;
|
||||||
|
}
|
||||||
|
if (nullptr != height) {
|
||||||
|
*height = img.rows;
|
||||||
|
}
|
||||||
|
if (nullptr != channels) {
|
||||||
|
*channels = img.channels();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nullptr == data || length < img.cols * img.rows * img.channels()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int y = 0; y < img.rows; y++) {
|
||||||
|
const auto *ptr = img.ptr<unsigned char>(y);
|
||||||
|
memcpy(data + y * img.cols, ptr, img.cols);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
98
grayMatch.h
98
grayMatch.h
@ -1,10 +1,12 @@
|
|||||||
#ifndef GRAY_MATCH_H
|
#ifndef GRAY_MATCH_H
|
||||||
#define GRAY_MATCH_H
|
#define GRAY_MATCH_H
|
||||||
|
|
||||||
#include <opencv2/opencv.hpp>
|
#include "apiExport.h"
|
||||||
|
|
||||||
struct Model;
|
struct Model;
|
||||||
|
|
||||||
|
using Model_t = Model *;
|
||||||
|
|
||||||
struct Pose {
|
struct Pose {
|
||||||
float x;
|
float x;
|
||||||
float y;
|
float y;
|
||||||
@ -12,14 +14,94 @@ struct Pose {
|
|||||||
float score;
|
float score;
|
||||||
};
|
};
|
||||||
|
|
||||||
Model *trainModel(const cv::Mat &src, int level);
|
/**
|
||||||
|
* @brief train match model
|
||||||
|
* @param data image data
|
||||||
|
* @param width image width
|
||||||
|
* @param height image height
|
||||||
|
* @param channels image channels 1(gray)/3(rgb)/4(rgba)
|
||||||
|
* @param bytesPerline bytes per line
|
||||||
|
* @param roiLeft rectangle roi left
|
||||||
|
* @param roiTop rectangle roi top
|
||||||
|
* @param roiWidth rectangle roi width
|
||||||
|
* @param roiHeight rectangle roi height
|
||||||
|
* @param levelNum pyramid levels (> 0)
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
API_PUBLIC Model_t trainModel(const unsigned char *data, int width, int height, int channels,
|
||||||
|
int bytesPerline, int roiLeft, int roiTop, int roiWidth,
|
||||||
|
int roiHeight, int levelNum);
|
||||||
|
/**
|
||||||
|
* @brief match model
|
||||||
|
* @param data image data
|
||||||
|
* @param width image width
|
||||||
|
* @param height image height
|
||||||
|
* @param channels image channels 1(gray)/3(rgb)/4(rgba)
|
||||||
|
* @param bytesPerline bytes per line
|
||||||
|
* @param roiLeft rectangle roi left
|
||||||
|
* @param roiTop rectangle roi top
|
||||||
|
* @param roiWidth rectangle roi width
|
||||||
|
* @param roiHeight rectangle roi height
|
||||||
|
* @param model trained model
|
||||||
|
* @param count in(max detect count)/out(found count)
|
||||||
|
* @param poses pose array inited with size not less than count
|
||||||
|
* @param level match start at which level (level>=0 && level<modelLevel-1)
|
||||||
|
* @param startAngle rotation start angle
|
||||||
|
* @param spanAngle rotation angle range
|
||||||
|
* @param maxOverlap overlap threshold
|
||||||
|
* @param minScore minimum matched score
|
||||||
|
* @param subpixel compute subpixel result
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
API_PUBLIC void matchModel(const unsigned char *data, int width, int height, int channels,
|
||||||
|
int bytesPerline, int roiLeft, int roiTop, int roiWidth, int roiHeight,
|
||||||
|
const Model_t model, int *count, Pose *poses, int level,
|
||||||
|
double startAngle, double spanAngle, double maxOverlap, double minScore,
|
||||||
|
int subpixel);
|
||||||
|
|
||||||
std::vector<Pose> matchModel(const cv::Mat &dst, const Model *model, int level, double startAngle,
|
/**
|
||||||
double spanAngle, double maxOverlap, double minScore, int maxCount,
|
* @brief get trained model levels
|
||||||
int subpixel);
|
* @param model
|
||||||
|
* @return pyramid level
|
||||||
|
*/
|
||||||
|
API_PUBLIC int modelLevel(const Model_t model);
|
||||||
|
|
||||||
void serialize(Model *model, int &size, uint8_t *buffer);
|
/**
|
||||||
|
* @brief get trained model image
|
||||||
|
* @param model
|
||||||
|
* @param level pyramid level index(level>=0 && level<modelLevel-1)
|
||||||
|
* @param data image data buffer(need allocated), can input nullptr to query width/height/channels
|
||||||
|
* @param length buffer length not less than width*height*channels
|
||||||
|
* @param width image width, can input nullptr
|
||||||
|
* @param height image height, can input nullptr
|
||||||
|
* @param channels image channels, can input nullptr
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
API_PUBLIC void modelImage(const Model_t model, int level, unsigned char *data, int length,
|
||||||
|
int *width, int *height, int *channels);
|
||||||
|
|
||||||
Model *deserialize(int size, uint8_t *buffer);
|
/**
|
||||||
|
* @brief free model
|
||||||
|
* @param model
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
API_PUBLIC void freeModel(Model_t *model);
|
||||||
|
|
||||||
#endif // GRAY_MATCH_H
|
/**
|
||||||
|
* @brief serialize model to buffer
|
||||||
|
* @param model
|
||||||
|
* @param buffer need allocated, can input nullptr to query size
|
||||||
|
* @param size in(buffer size)/out(written size)
|
||||||
|
* @return true(success)false(failed)
|
||||||
|
*/
|
||||||
|
API_PUBLIC bool serialize(const Model_t model, unsigned char *buffer, int *size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief desrialize model
|
||||||
|
* @param buffer
|
||||||
|
* @param size buffer size
|
||||||
|
* @return model
|
||||||
|
*/
|
||||||
|
API_PUBLIC Model_t deserialize(unsigned char *buffer, int size);
|
||||||
|
|
||||||
|
#endif // GRAY_MATCH_H
|
||||||
|
29
main.cpp
29
main.cpp
@ -10,21 +10,38 @@ int main() {
|
|||||||
cv::imread("C:/Users/qiuyong/Desktop/test/template/model3_src1.bmp", cv::IMREAD_GRAYSCALE);
|
cv::imread("C:/Users/qiuyong/Desktop/test/template/model3_src1.bmp", cv::IMREAD_GRAYSCALE);
|
||||||
|
|
||||||
auto t0 = cv::getTickCount();
|
auto t0 = cv::getTickCount();
|
||||||
auto model = trainModel(src, -1);
|
auto model = trainModel(src.data, src.cols, src.rows, src.channels(), int(src.step), 0, 0,
|
||||||
|
src.cols, src.rows, -1);
|
||||||
auto t1 = cv::getTickCount();
|
auto t1 = cv::getTickCount();
|
||||||
auto poses = matchModel(dst, model, -1, 0, 360, 0, 0.5, 70, 1);
|
|
||||||
auto t2 = cv::getTickCount();
|
int size;
|
||||||
|
serialize(model, nullptr, &size);
|
||||||
|
std::vector<uchar> buffer(size);
|
||||||
|
serialize(model, buffer.data(), &size);
|
||||||
|
|
||||||
|
freeModel(&model);
|
||||||
|
|
||||||
|
model = deserialize(buffer.data(), int(buffer.size()));
|
||||||
|
|
||||||
|
int num = 70;
|
||||||
|
std::vector<Pose> poses(num);
|
||||||
|
|
||||||
|
auto t2 = cv::getTickCount();
|
||||||
|
matchModel(dst.data, dst.cols, dst.rows, dst.channels(), int(dst.step), 0, 0, dst.cols,
|
||||||
|
dst.rows, model, &num, poses.data(), -1, 0, 360, 0, 0.5, 1);
|
||||||
|
auto t3 = cv::getTickCount();
|
||||||
|
|
||||||
auto trainCost = double(t1 - t0) / cv::getTickFrequency();
|
auto trainCost = double(t1 - t0) / cv::getTickFrequency();
|
||||||
auto matchCost = double(t2 - t1) / cv::getTickFrequency();
|
auto matchCost = double(t3 - t2) / cv::getTickFrequency();
|
||||||
std::cout << "train(s):" << trainCost << " match(s):" << matchCost << std::endl;
|
std::cout << "train(s):" << trainCost << " match(s):" << matchCost << std::endl;
|
||||||
|
|
||||||
cv::Mat color;
|
cv::Mat color;
|
||||||
cv::cvtColor(dst, color, cv::COLOR_GRAY2RGB);
|
cv::cvtColor(dst, color, cv::COLOR_GRAY2RGB);
|
||||||
for (auto &pose : poses) {
|
for (int i = 0; i < num; i++) {
|
||||||
|
auto &pose = poses[ i ];
|
||||||
cv::RotatedRect rect(cv::Point2f(pose.x, pose.y), src.size(), -pose.angle);
|
cv::RotatedRect rect(cv::Point2f(pose.x, pose.y), src.size(), -pose.angle);
|
||||||
|
|
||||||
std::vector<cv::Point2f> pts;
|
cv::Point2f pts[ 4 ];
|
||||||
rect.points(pts);
|
rect.points(pts);
|
||||||
|
|
||||||
cv::line(color, pts[ 0 ], pts[ 1 ], cv::Scalar(255, 0, 0), 1, cv::LINE_AA);
|
cv::line(color, pts[ 0 ], pts[ 1 ], cv::Scalar(255, 0, 0), 1, cv::LINE_AA);
|
||||||
|
34
privateType.h
Normal file
34
privateType.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <opencv2/core.hpp>
|
||||||
|
|
||||||
|
struct Model {
|
||||||
|
std::vector<cv::Mat> pyramids;
|
||||||
|
std::vector<cv::Scalar> mean;
|
||||||
|
std::vector<double> normal;
|
||||||
|
std::vector<double> invArea;
|
||||||
|
std::vector<uchar> equal1;
|
||||||
|
uchar borderColor = 0;
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
pyramids.clear();
|
||||||
|
normal.clear();
|
||||||
|
invArea.clear();
|
||||||
|
mean.clear();
|
||||||
|
equal1.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void resize(const std::size_t size) {
|
||||||
|
normal.resize(size);
|
||||||
|
invArea.resize(size);
|
||||||
|
mean.resize(size);
|
||||||
|
equal1.resize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reserve(const std::size_t size) {
|
||||||
|
normal.reserve(size);
|
||||||
|
invArea.reserve(size);
|
||||||
|
mean.reserve(size);
|
||||||
|
equal1.reserve(size);
|
||||||
|
}
|
||||||
|
};
|
222
serialize.cpp
Normal file
222
serialize.cpp
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
#include "grayMatch.h"
|
||||||
|
#include "privateType.h"
|
||||||
|
|
||||||
|
class Buffer {
|
||||||
|
public:
|
||||||
|
Buffer(int size_, unsigned char *data_)
|
||||||
|
: m_size(size_)
|
||||||
|
, m_data(data_) {}
|
||||||
|
|
||||||
|
virtual void operator&(uchar &val) = 0;
|
||||||
|
virtual void operator&(std::vector<cv::Mat> &val) = 0;
|
||||||
|
virtual void operator&(std::vector<cv::Scalar> &val) = 0;
|
||||||
|
virtual void operator&(std::vector<double> &val) = 0;
|
||||||
|
virtual void operator&(std::vector<uchar> &val) = 0;
|
||||||
|
|
||||||
|
void operator&(Model &val) {
|
||||||
|
this->operator&(val.pyramids);
|
||||||
|
this->operator&(val.mean);
|
||||||
|
this->operator&(val.normal);
|
||||||
|
this->operator&(val.invArea);
|
||||||
|
this->operator&(val.equal1);
|
||||||
|
this->operator&(val.borderColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
int count() const {
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int m_size = 0;
|
||||||
|
unsigned char *m_data = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class WriteOperationBase {
|
||||||
|
public:
|
||||||
|
virtual void write(void *dst, void *src, int size) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void binWrite(void *dst, void *src, int size) {
|
||||||
|
memcpy(dst, src, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fakeWrite(void *dst, void *src, int size) {
|
||||||
|
(void)(dst);
|
||||||
|
(void)(src);
|
||||||
|
(void)(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
using Write = void (*)(void *, void *, int);
|
||||||
|
|
||||||
|
template <Write write> class OutBuffer : public Buffer {
|
||||||
|
public:
|
||||||
|
OutBuffer(unsigned char *data_)
|
||||||
|
: Buffer(0, data_) {}
|
||||||
|
|
||||||
|
void operator&(uchar &val) final {
|
||||||
|
write(m_data + m_size, &val, sizeof(val));
|
||||||
|
m_size += static_cast<int>(sizeof(val));
|
||||||
|
}
|
||||||
|
void operator&(std::vector<cv::Mat> &val) final {
|
||||||
|
int size = static_cast<int>(val.size());
|
||||||
|
write(m_data + m_size, &size, sizeof(size));
|
||||||
|
m_size += static_cast<int>(sizeof(size));
|
||||||
|
|
||||||
|
for (auto &element : val) {
|
||||||
|
writeElement(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void writeElement(cv::Mat &val) {
|
||||||
|
write(m_data + m_size, &val.cols, sizeof(int));
|
||||||
|
m_size += static_cast<int>(sizeof(int));
|
||||||
|
|
||||||
|
write(m_data + m_size, &val.rows, sizeof(int));
|
||||||
|
m_size += static_cast<int>(sizeof(int));
|
||||||
|
|
||||||
|
for (int i = 0; i < val.rows; i++) {
|
||||||
|
write(m_data + m_size, val.ptr<unsigned char>(i), val.cols);
|
||||||
|
m_size += val.cols;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void operator&(std::vector<cv::Scalar> &val) final {
|
||||||
|
int size = static_cast<int>(val.size());
|
||||||
|
write(m_data + m_size, &size, sizeof(size));
|
||||||
|
m_size += static_cast<int>(sizeof(size));
|
||||||
|
|
||||||
|
for (auto &element : val) {
|
||||||
|
writeElement(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void writeElement(cv::Scalar &val) {
|
||||||
|
write(m_data + m_size, val.val, sizeof(double) * 4);
|
||||||
|
m_size += static_cast<int>(sizeof(double)) * 4;
|
||||||
|
}
|
||||||
|
void operator&(std::vector<double> &val) final {
|
||||||
|
int size = static_cast<int>(val.size());
|
||||||
|
write(m_data + m_size, &size, sizeof(size));
|
||||||
|
m_size += static_cast<int>(sizeof(size));
|
||||||
|
|
||||||
|
write(m_data + m_size, val.data(), static_cast<int>(sizeof(double)) * size);
|
||||||
|
m_size += static_cast<int>(sizeof(double)) * size;
|
||||||
|
}
|
||||||
|
void operator&(std::vector<uchar> &val) final {
|
||||||
|
int size = static_cast<int>(val.size());
|
||||||
|
write(m_data + m_size, &size, sizeof(size));
|
||||||
|
m_size += static_cast<int>(sizeof(size));
|
||||||
|
|
||||||
|
write(m_data + m_size, val.data(), sizeof(uchar) * size);
|
||||||
|
m_size += static_cast<int>(sizeof(uchar)) * size;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using SizeCountBuffer = OutBuffer<fakeWrite>;
|
||||||
|
using WriteBuffer = OutBuffer<binWrite>;
|
||||||
|
|
||||||
|
class ReadBuffer : public Buffer {
|
||||||
|
public:
|
||||||
|
ReadBuffer(unsigned char *data_)
|
||||||
|
: Buffer(0, data_) {}
|
||||||
|
|
||||||
|
void operator&(uchar &val) final {
|
||||||
|
memcpy(&val, m_data + m_size, sizeof(uchar));
|
||||||
|
m_size += static_cast<int>(sizeof(uchar));
|
||||||
|
}
|
||||||
|
void operator&(std::vector<cv::Mat> &val) final {
|
||||||
|
int count = 0;
|
||||||
|
memcpy(&count, m_data + m_size, sizeof(int));
|
||||||
|
val.resize(count);
|
||||||
|
m_size += static_cast<int>(sizeof(count));
|
||||||
|
|
||||||
|
for (auto &element : val) {
|
||||||
|
read(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void read(cv::Mat &val) {
|
||||||
|
int width = 0;
|
||||||
|
memcpy(&width, m_data + m_size, sizeof(int));
|
||||||
|
m_size += static_cast<int>(sizeof(int));
|
||||||
|
|
||||||
|
int height = 0;
|
||||||
|
memcpy(&height, m_data + m_size, sizeof(int));
|
||||||
|
m_size += static_cast<int>(sizeof(int));
|
||||||
|
|
||||||
|
val = cv::Mat(cv::Size(width, height), CV_8UC1, m_data + m_size);
|
||||||
|
m_size += width * height;
|
||||||
|
}
|
||||||
|
void operator&(std::vector<cv::Scalar> &val) final {
|
||||||
|
int count = 0;
|
||||||
|
memcpy(&count, m_data + m_size, sizeof(int));
|
||||||
|
val.resize(count);
|
||||||
|
m_size += static_cast<int>(sizeof(count));
|
||||||
|
|
||||||
|
for (auto &element : val) {
|
||||||
|
read(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void read(cv::Scalar &val) {
|
||||||
|
memcpy(val.val, m_data + m_size, sizeof(double) * 4);
|
||||||
|
m_size += static_cast<int>(sizeof(double)) * 4;
|
||||||
|
}
|
||||||
|
void operator&(std::vector<double> &val) final {
|
||||||
|
int count = 0;
|
||||||
|
memcpy(&count, m_data + m_size, sizeof(int));
|
||||||
|
val.resize(count);
|
||||||
|
m_size += static_cast<int>(sizeof(count));
|
||||||
|
|
||||||
|
memcpy(val.data(), m_data + m_size, sizeof(double) * count);
|
||||||
|
m_size += static_cast<int>(sizeof(double)) * count;
|
||||||
|
}
|
||||||
|
void operator&(std::vector<uchar> &val) final {
|
||||||
|
int count = 0;
|
||||||
|
memcpy(&count, m_data + m_size, sizeof(int));
|
||||||
|
val.resize(count);
|
||||||
|
m_size += static_cast<int>(sizeof(count));
|
||||||
|
|
||||||
|
memcpy(val.data(), m_data + m_size, sizeof(bool) * count);
|
||||||
|
m_size += static_cast<int>(sizeof(uchar)) * count;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void operation(Buffer *buf, Model &model) {
|
||||||
|
(*buf) & (model);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool serialize(const Model_t model, unsigned char *buffer, int *size) {
|
||||||
|
if (nullptr == size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nullptr == model) {
|
||||||
|
*size = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SizeCountBuffer countor(buffer);
|
||||||
|
operation(&countor, *model);
|
||||||
|
*size = countor.count();
|
||||||
|
|
||||||
|
if (nullptr == buffer) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (countor.count() > *size) {
|
||||||
|
*size = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteBuffer writer(buffer);
|
||||||
|
operation(&writer, *model);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Model_t deserialize(unsigned char *buffer, int size) {
|
||||||
|
if (size < 1 || nullptr == buffer) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadBuffer reader(buffer);
|
||||||
|
auto *model = new Model;
|
||||||
|
operation(&reader, *model);
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
Reference in New Issue
Block a user