目录
1. 修改检测网络
1.1 删除int8量化,使用摄像头等用不到的内容
1. 2 修改用到的参数
1.3 设置鼠标移动
1.4 将mian函数改为预测函数
2. 实现屏幕检测
3. 效果展示
4. 代码链接
5. 参考链接
一般情况下,目标检测的内容都是摄像头捕捉到的视频,但有时候我们可能需要检测屏幕画面是否存在某些内容,并在检测出后使用鼠标去指向它...
模型选用轻量化的yolov5-lite,源码见参考链接1,由于使用不是很顺手,对源码进行了少量修改
float unsig_pro;
float myprop = 0.30f;
const float prob_threshold = 0.31f;
const float nms_threshold = 0.60f;
// 获取屏幕长宽
int nWidth = GetSystemMetrics(SM_CXSCREEN);
int nHeight = GetSystemMetrics(SM_CYSCREEN);
const int target_size = 320;
float scale_x = nWidth / target_size;
float scale_y = nHeight / target_size;
// 将鼠标移动到置信度最高的目标的中心
if (i == 0) {
SetCursorPos(int((x0 + objects[i].rect.width / 2) * scale_x), int((y0 + objects[i].rect.height / 2) * scale_y));
Sleep(1); // 用于休眠,没啥用,可以删掉
}
void detect(cv::Mat mat1, cv::Mat &mat2){
std::vector
直接上代码,注释写的很详细
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// 定义鼠标宏
#define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)
using namespace std;
using namespace cv;
// 从yolov5-lite拿到预测函数
extern void detect(cv::Mat mat1, cv::Mat &mat2);
// 截屏
void Screen();
// hBitmap转IplImage
IplImage* hBitmapToIpl(HBITMAP hBmp);
// 定义变量和指针
HBITMAP hBmp;
HBITMAP hOld;
Mat dst;
Mat image;
IplImage* inter;
// 拿到屏幕尺寸
extern int nWidth;
extern int nHeight;
int main()
{
while (true)
{
// 捕捉鼠标右键休眠,滚轮退出,全局可用
if (KEY_DOWN(VK_RBUTTON)) { Sleep(5000); }
else if (KEY_DOWN(VK_MBUTTON)) {break; }
// 屏幕截取
Screen();
// hBitmap转IplImage
inter = hBitmapToIpl(hBmp);
// IplImage转Mat
image = cvarrToMat(inter);
// 图像处理
resize(image, image, cv::Size(320, 320));
// 检测
detect(image, dst);
// 缩放显示
resize(dst, dst, cv::Size(nWidth/4, nHeight/4));
// 窗口置顶
namedWindow("window");
HWND hWnd = (HWND)cvGetWindowHandle("window");
HWND hRawWnd = ::GetParent(hWnd);
if (NULL != hRawWnd)
{
BOOL bRet = ::SetWindowPos(hRawWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
//assert(bRet);
}
// 图像显示
cv::imshow("window", dst);
cv::waitKey(1);
// 释放内存
DeleteObject(hBmp);
cvReleaseImage(&inter);
}
return 0;
}
IplImage* hBitmapToIpl(HBITMAP hBmp)
{
BITMAP bmp;
GetObject(hBmp, sizeof(BITMAP), &bmp);
// 通道
int nChannels = bmp.bmBitsPixel == 1 ? 1 : bmp.bmBitsPixel / 8;
// 通道深度
int depth = bmp.bmBitsPixel == 1 ? IPL_DEPTH_1U : IPL_DEPTH_8U;
// 预分配空间
IplImage* img = cvCreateImage(cvSize(bmp.bmWidth, bmp.bmHeight), depth, nChannels);
// 申请内存
BYTE* pBuffer = new BYTE[bmp.bmHeight * bmp.bmWidth * nChannels*5];
// 将输入图片内容传入中间变量pBuffer
GetBitmapBits(hBmp, bmp.bmHeight * bmp.bmWidth * nChannels, pBuffer);
// 将图片内容从中间变量转到img
memcpy(img->imageData, pBuffer, bmp.bmHeight * bmp.bmWidth * nChannels);
// 释放内存
delete[] pBuffer;
pBuffer = nullptr;
// 创建目标图片
IplImage* dst = cvCreateImage(cvGetSize(img), img->depth, 3);
// 拷贝并转换颜色
cvCvtColor(img, dst, CV_BGRA2BGR);
// 释放内存
cvReleaseImage(&img);
return dst;
}
//抓取当前屏幕函数
void Screen() {
//创建画板
HDC hScreen = CreateDC(L"DISPLAY", NULL, NULL, NULL);
HDC hCompDC = CreateCompatibleDC(hScreen);
//取屏幕宽度和高度
int nWidth = GetSystemMetrics(SM_CXSCREEN);
int nHeight = GetSystemMetrics(SM_CYSCREEN);
//创建Bitmap对象
hBmp = CreateCompatibleBitmap(hScreen, nWidth, nHeight);
hOld = (HBITMAP)SelectObject(hCompDC, hBmp);
BitBlt(hCompDC, 0, 0, nWidth, nHeight, hScreen, 0, 0, SRCCOPY);
SelectObject(hCompDC, hOld);
//释放对象
DeleteDC(hScreen);
DeleteDC(hCompDC);
}
需要注意的是,鼠标右键-》显示设置界面,要将缩放与布局改为100%,不然只能检测部分屏幕;
当然,也可以不改,根据屏幕分辨率手动设置nWidth和nHeight就可以了,我这里是×2。
liuweixue001/screen_detect: 基于yolov5-lite对屏幕进行目标检测 (github.com)
ppogg/YOLOv5-Lite: YOLOv5-Lite: lighter, faster and easier to deploy. Evolved from yolov5 and the size of model is only 930+kb (int8) and 1.7M (fp16). It can reach 10+ FPS on the Raspberry Pi 4B when the input size is 320×320~ (github.com)