首页 > 编程语言 >C++调用opencv使用透明遮罩进行模板匹配定位——以梦幻西游鼠标为例

C++调用opencv使用透明遮罩进行模板匹配定位——以梦幻西游鼠标为例

时间:2023-12-17 23:45:16浏览次数:45  
标签:遮罩 鼠标 maskMat mask C++ opencv cv 模板

目录

程序简介

项目调用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);

源图,目标是找到对话框里那个手型鼠标的位置

source

模板图 即直接从其他源图中截取得到的鼠标图,没有做任何处理

template

掩膜图,即用PS扣下的带透明通道的图,只留下了鼠标主体

mask

处理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();

withoutmask

withmask

标签:遮罩,鼠标,maskMat,mask,C++,opencv,cv,模板
From: https://www.cnblogs.com/boom-meal/p/17910109.html

相关文章

  • 60道C++STL高频题整理(附答案背诵版)
    1.请解释vector容器和它的特点。在C++中,vector是标准模板库(STL)的一部分,它是一个动态数组。与普通数组相比,它的大小可以在运行时动态改变。下面是vector的一些主要特点和应用场景:动态大小:与传统的数组不同,vector可以根据需要动态地扩展或缩减大小。这意味着你不需要事先知道数......
  • C++ 基础高频题整理(附答案背诵版)
    1.C和C++有什么区别?C++是C语言的超集(我看网上很多文章说这是不对的),这意味着几乎所有的C程序都可以在C++编译器中编译和运行。然而,C++引入了许多新的概念和特性,使得两种语言在一些关键点上有显著的区别。以下是C和C++的一些主要区别:面向对象编程:C++支持面向对象编程(OOP),包括类......
  • C和C++练习
    要点:1、数组2、冒泡排序BubbleSort3、带指针的结构体(malloc,free)4、字符串操作(拷贝、逆序、比较)5、格式化输出printf,sprintf6、格式化输入,scanf,sscanf7、文件操作fopen,feof,EOF,fputc,fgetc,fputs,fgets,stdin,stdout8、数组传参(需要指定长度)、字符串传参(不需指定长度......
  • C++ Qt开发:自定义Dialog对话框组件
    Qt是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍自定义Dialog组件的常用方法及灵活运用。在之前的文章中笔者已经为大家展示了默认Dialog组件的使......
  • C++中SQLite数据库操作实例:查询、增加、修改、删除一网打尽
     在C++中使用SQLite数据库需要使用SQLite的C/C++接口。以下是一个简单的示例,演示如何在C++中使用SQLite,并提供了常见的查询、增加、修改和删除功能。为了使用SQLite,你需要下载SQLite的C/C++接口,并链接到你的项目中。首先,确保你已经下载了SQLite的C/C++接口,然后将头文件和库文......
  • C++ Qt开发:标准Dialog对话框组件
    Qt是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍标准对话框QInputDialog、QFileDialog这两种对话框组件的常用方法及灵活运用。在Qt中,标准对话......
  • Qt/C++音视频开发60-坐标拾取/按下鼠标获取矩形区域/转换到视频源真实坐标
    一、前言通过在通道画面上拾取鼠标按下的坐标,然后鼠标移动,直到松开,根据松开的坐标和按下的坐标,绘制一个矩形区域,作为热点或者需要电子放大的区域,拿到这个坐标区域,用途非常多,可以直接将区域中的画面放大,也可以将该圈起来的区域位置发给设备,由设备设定对应的热点区域作为集中观察点......
  • C++常用STL容器
    1.queue#include<queue>usingnamespacestd;queue<int>q;常用方法1.size()q.size()值为所包含的元素的个数2.front()q.front()头元素3.back()q.back()尾元素4.push()q.push(value)将value加入队列q中5.pop()q.pop()将头元素弹出队列q中测试代码:#include<i......
  • C++ AOP 编程介绍
    AOP(Aspect-OrientedProgramming)是一种编程范式,将程序的非核心逻辑都“横切”处理,实现非核心逻辑与核心逻辑的分离【1】在日常工作中,会遇到一类需求:统计业务处理的耗时或者加锁,业务函数可以动态替换而非侵入式修改业务函数;简单粗暴的方法是:RetProcess(...)//业务函数{......
  • c++单词排序。
    --START--读入n个英文单词,将这n个单词按字典序升序排序后,重新输出。第1行,一个正整数n。(0<n<100)第2行,n个英文单词。单词之间用空格隔开。一行,n个按字典序升序排序后的英文单词。单词之间用空格隔开。in:5hiIamastudentout:Iamahistudent#include<iostream>......