103 lines
2.7 KiB
C++
103 lines
2.7 KiB
C++
#include "matcher.h"
|
|
|
|
#include <Log.h>
|
|
|
|
#include "util.h"
|
|
|
|
std::string Matcher::pathbase;
|
|
|
|
void Matcher::setPathBase(const std::string& pa) {
|
|
pathbase = pa;
|
|
}
|
|
|
|
Matcher::Matcher(const std::string& filename) {
|
|
templ = cv::imread(pathbase + filename, cv::IMREAD_UNCHANGED); // unchanged so alpha channel does not get dropped
|
|
maskFromTemplate();
|
|
}
|
|
Matcher::Matcher(const cv::Mat& templ) {
|
|
templ.copyTo(this->templ);
|
|
maskFromTemplate();
|
|
}
|
|
Matcher::~Matcher() {}
|
|
|
|
void Matcher::setOffset(int32_t x, int32_t y) {
|
|
posx = x;
|
|
posy = y;
|
|
}
|
|
|
|
|
|
bool Matcher::Match::operator==(const Match& other) const {
|
|
return doesMatch == other.doesMatch && x == other.x && y == other.y && width == other.width && height == other.height;
|
|
}
|
|
|
|
bool Matcher::Match::operator!=(const Match& other) const {
|
|
return !(*this == other);
|
|
}
|
|
|
|
|
|
Matcher::Match Matcher::match(const cv::Mat& img) {
|
|
// remove Alpha channel from input
|
|
cv::Mat converted;
|
|
cv::cvtColor(img, converted, cv::COLOR_RGBA2RGB);
|
|
|
|
if(posx < 0 || posy < 0) {
|
|
return matchAll(converted);
|
|
}
|
|
return matchPos(converted);
|
|
}
|
|
|
|
// https://stackoverflow.com/a/43133263/4399859
|
|
Matcher::Match Matcher::matchAll(const cv::Mat& img) {
|
|
// create out mat
|
|
int result_cols = img.cols - templ.cols + 1;
|
|
int result_rows = img.rows - templ.rows + 1;
|
|
cv::Mat out(result_rows, result_cols, CV_32FC1);
|
|
Log::info << "match size: " << result_cols << " " << result_cols;
|
|
|
|
// match
|
|
cv::matchTemplate(img, templ, out, cv::TM_CCORR_NORMED, mask);
|
|
|
|
double minVal; double maxVal;
|
|
cv::Point minLoc; cv::Point maxLoc;
|
|
cv::minMaxLoc( out, &minVal, &maxVal, &minLoc, &maxLoc, cv::Mat());
|
|
|
|
Log::debug << "pixelcount: " << (templ.cols * templ.rows) << " minVal: " << minVal << " maxVal: " << maxVal << " minLoc: " << minLoc.x << " " << minLoc.y << " maxLoc: " << maxLoc.x << " " << maxLoc.y;
|
|
|
|
bool matched = maxVal > 0.95;
|
|
|
|
return {matched, maxLoc.x, maxLoc.y, templ.cols, templ.rows};
|
|
}
|
|
|
|
Matcher::Match Matcher::matchPos(const cv::Mat& img) {
|
|
cv::Mat matchpart = img(cv::Range(posy, posy + templ.rows), cv::Range(posx, posx + templ.cols));
|
|
|
|
// create out mat (only one pxl)
|
|
cv::Mat out(1, 1, CV_32FC1);
|
|
|
|
// match
|
|
cv::matchTemplate(matchpart, templ, out, cv::TM_CCORR_NORMED, mask);
|
|
|
|
float val = out.at<float>({0, 0});
|
|
bool matched = val > 0.95;
|
|
|
|
Log::debug << "val: " << val;
|
|
|
|
return {matched, posx, posy, templ.cols, templ.rows};
|
|
}
|
|
|
|
void Matcher::maskFromTemplate() {
|
|
if(templ.channels() == 4) {
|
|
// split channels
|
|
std::vector<cv::Mat> split;
|
|
cv::split(templ, split);
|
|
|
|
// template without alpha channel
|
|
cv::merge(std::vector(split.begin(), split.end()-1), templ);
|
|
|
|
// 3*alpha channel
|
|
cv::Mat alphaChannel = split.at(3);
|
|
alphaChannel.convertTo(alphaChannel, CV_8U);
|
|
cv::merge(std::vector(3, alphaChannel), mask);
|
|
}
|
|
}
|