目录
程序简介
项目调用C++的opencv模块进行模板匹配,即在一张源图上找到对应模板图最相似的位置,网上大多数使用matchTemplate方法并没有使用到mask遮罩(也可以叫掩膜),而在现实情况中不规则的模板更为常见,而模板加遮罩则可以实现不规则模板,本文以梦幻西游鼠标为例,展示了用遮罩和不使用遮罩的差异。
程序输入:需要定位模板的原图、模板图、遮罩图
程序输出:模板图在原图中的位置
程序/数据集下载
本文章只发布于博客园、CSDN和爆米算法,被抄袭后可能排版错乱或下载失效,作者:爆米LiuChen
代码分析
载入图片
#include <opencv2/opencv.hpp>
#include <string>
cv::Mat sourceMat = cv::imread("2号鼠标测试.png");
cv::Mat templateMat = cv::imread("2号鼠标模板.png");
cv::Mat maskMat = cv::imread("2号鼠标遮罩.png", -1);
源图,目标是找到对话框里那个手型鼠标的位置
模板图 即直接从其他源图中截取得到的鼠标图,没有做任何处理
掩膜图,即用PS扣下的带透明通道的图,只留下了鼠标主体
处理mask遮罩,先读取mask的透明通道,如果同道值为0,则将mask像素值置0,随后转为灰度图,然后二值化,最后将二值图叠加成3通道的图,因为每个通道都可以有自己的遮罩,可以自行处理,但本文是3个通道用一样的遮罩
int maskWidth = maskMat.cols;
int maskHeight = maskMat.rows;
// 根据透明通道修改像素值 透明通道值为0 则像素值置0
for (int y = 0; y < maskHeight; ++y) {
for (int x = 0; x < maskWidth; ++x) {
// 获取像素值,注意通道顺序是BGR(A)而不是RGBA
cv::Vec4b pixel = maskMat.at<cv::Vec4b>(y, x);
if (pixel[3] == 0) {
maskMat.at<cv::Vec4b>(y, x) = cv::Vec4b(0, 0, 0, 0);
}
}
}
// 转换为3通道图片 因为每个通道有单独的遮罩
cv::cvtColor(maskMat, maskMat, cv::COLOR_BGRA2BGR);
cv::cvtColor(maskMat, maskMat, cv::COLOR_BGR2GRAY);
cv::threshold(maskMat, maskMat, 1, 255, cv::THRESH_BINARY);
std::vector<cv::Mat> channels = { maskMat, maskMat, maskMat };
cv::merge(channels, maskMat);
调用matchTemplate定位模板,这里使用mask和不使用mask进行对比,可以看出不使用mask很容易误判位置,定位到了右下角类似木桩的位置,使用mask后精准定位到了鼠标
cv::Mat result;
//cv::matchTemplate(sourceMat, templateMat, result, cv::TM_SQDIFF_NORMED);//不用mask的对比
cv::matchTemplate(sourceMat, templateMat, result, cv::TM_SQDIFF_NORMED,maskMat);//mask的对比
double minVal, maxVal;
cv::Point minLoc, maxLoc;
cv::minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc);
cv::rectangle(sourceMat, minLoc, cv::Point(minLoc.x + maskWidth, minLoc.y + maskHeight), cv::Scalar(0, 0, 255), 3);
cv::resize(sourceMat, sourceMat, cv::Size(800, 600));
cv::imshow("", sourceMat);
cv::waitKey(0);
cv::destroyAllWindows();
标签:遮罩,鼠标,maskMat,mask,C++,opencv,cv,模板
From: https://www.cnblogs.com/boom-meal/p/17910109.html