鼠标绘制矩形
视频讲解如下:
当前系列所有demo下载地址:
https://github.com/GaoRenBao/OpenCv4-Demo
不同编程语言对应的OpenCv版本以及开发环境信息如下:
语言 | OpenCv版本 | IDE |
C# | OpenCvSharp4.4.8.0.20230708 | Visual Studio 2022 |
C++ | OpenCv-4.5.5-vc14_vc15 | Visual Studio 2022 |
Python | OpenCv-Python (4.6.0.66) | PyCharm Community Edition 2022.1.3 |
三个版本运行效果都差不多,效果如下:

C#版本代码如下:
C#版本需要安装“OpenCvSharp4”、“OpenCvSharp4.runtime.win”两个库才行。不然会报错。
如果需要使用“ BitmapConverter.ToBitmap”操作,则需要追加安装“OpenCvSharp4.Extensions”库。
OpenCv3版本的SetMouseCallback操作请参考:/Course?id=4743192000049
源码如下:
using OpenCvSharp;
using System;
namespace demo
{
internal class Program
{
public static string WINDOW_NAME = "【程序窗口】";
public static Mat srcImage = new Mat(600, 800, MatType.CV_8UC3, Scalar.All(0));
public static Rect g_rectangle;
public static bool g_bDrawingBox = false;//是否进行绘制
public static Random g_rng = new Random();
static void Main(string[] args)
{
//【1】准备参数
g_rectangle = new Rect(-1, -1, 0, 0);
Mat tempImage = new Mat();
//【2】设置鼠标操作回调函数
Cv2.NamedWindow(WINDOW_NAME);
MouseCallback GetRGBCvMouseCallback = new MouseCallback(on_MouseHandle);
Cv2.SetMouseCallback(WINDOW_NAME, GetRGBCvMouseCallback);
//【3】程序主循环,当进行绘制的标识符为真时,进行绘制
while (true)
{
srcImage.CopyTo(tempImage);//拷贝源图到临时变量
if (g_bDrawingBox)
{
DrawRectangle(ref tempImage, g_rectangle);//当进行绘制的标识符为真,则进行绘制
}
Cv2.ImShow(WINDOW_NAME, tempImage);
if (Cv2.WaitKey(10) == 27) break;//按下ESC键,程序退出
}
}
public static void on_MouseHandle(MouseEventTypes @event, int x, int y, MouseEventFlags flags, IntPtr userdata)
{
//鼠标移动消息
if (@event == MouseEventTypes.MouseMove)
{
if (g_bDrawingBox)//如果是否进行绘制的标识符为真,则记录下长和宽到RECT型变量中
{
g_rectangle.Width = x - g_rectangle.X;
g_rectangle.Height = y - g_rectangle.Y;
}
}
//左键按下消息
if (@event == MouseEventTypes.LButtonDown)
{
g_bDrawingBox = true;
g_rectangle = new Rect(x, y, 0, 0);//记录起始点
}
//左键抬起消息
if (@event == MouseEventTypes.LButtonUp)
{
g_bDrawingBox = false;//置标识符为false
//对宽和高小于0的处理
if (g_rectangle.Width < 0)
{
g_rectangle.X += g_rectangle.Width;
g_rectangle.Width *= -1;
}
if (g_rectangle.Height < 0)
{
g_rectangle.Y += g_rectangle.Height;
g_rectangle.Height *= -1;
}
//调用函数进行绘制
DrawRectangle(ref srcImage, g_rectangle);
}
}
public static void DrawRectangle(ref Mat img, Rect box)
{
if ((box.BottomRight.X > box.TopLeft.X) && (box.BottomRight.Y > box.TopLeft.Y))
Cv2.Rectangle(img, box.TopLeft, box.BottomRight, new Scalar(g_rng.Next(255), g_rng.Next(255), g_rng.Next(255)), 2);//随机颜色
}
}
}
C++版本
源码如下:
#include <opencv2/opencv.hpp>
using namespace cv;
//为窗口标题定义的宏
#define WINDOW_NAME "【程序窗口】"
void on_MouseHandle(int event, int x, int y, int flags, void* param);
void DrawRectangle(cv::Mat& img, cv::Rect box);
void ShowHelpText();
Rect g_rectangle;
bool g_bDrawingBox = false;//是否进行绘制
RNG g_rng(12345);
int main(int argc, char** argv)
{
//【0】改变console字体颜色
system("color 9F");
//【0】显示欢迎和帮助文字
ShowHelpText();
//【1】准备参数
g_rectangle = Rect(-1, -1, 0, 0);
Mat srcImage(600, 800, CV_8UC3), tempImage;
srcImage = Scalar::all(0);
//【2】设置鼠标操作回调函数
namedWindow(WINDOW_NAME);
setMouseCallback(WINDOW_NAME, on_MouseHandle, (void*)&srcImage);
//【3】程序主循环,当进行绘制的标识符为真时,进行绘制
while (1)
{
srcImage.copyTo(tempImage);//拷贝源图到临时变量
if (g_bDrawingBox) DrawRectangle(tempImage, g_rectangle);//当进行绘制的标识符为真,则进行绘制
imshow(WINDOW_NAME, tempImage);
if (waitKey(10) == 27) break;//按下ESC键,程序退出
}
return 0;
}
void on_MouseHandle(int event, int x, int y, int flags, void* param)
{
Mat& image = *(cv::Mat*)param;
switch (event)
{
//鼠标移动消息
case EVENT_MOUSEMOVE:
{
if (g_bDrawingBox)//如果是否进行绘制的标识符为真,则记录下长和宽到RECT型变量中
{
g_rectangle.width = x - g_rectangle.x;
g_rectangle.height = y - g_rectangle.y;
}
}
break;
//左键按下消息
case EVENT_LBUTTONDOWN:
{
g_bDrawingBox = true;
g_rectangle = Rect(x, y, 0, 0);//记录起始点
}
break;
//左键抬起消息
case EVENT_LBUTTONUP:
{
g_bDrawingBox = false;//置标识符为false
//对宽和高小于0的处理
if (g_rectangle.width < 0)
{
g_rectangle.x += g_rectangle.width;
g_rectangle.width *= -1;
}
if (g_rectangle.height < 0)
{
g_rectangle.y += g_rectangle.height;
g_rectangle.height *= -1;
}
//调用函数进行绘制
DrawRectangle(image, g_rectangle);
}
break;
}
}
void DrawRectangle(cv::Mat& img, cv::Rect box)
{
cv::rectangle(img, box.tl(), box.br(), cv::Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255), g_rng.uniform(0, 255)));//随机颜色
}
void ShowHelpText()
{
printf("当前使用的OpenCV版本为:" CV_VERSION);
printf("\n请在窗口中点击鼠标左键并拖动以绘制矩形");
}
Python版本
源码如下:
import numpy as np
import cv2
import random
g_rectangle = [0, 0, 0, 0] # x,y,w,h
g_bDrawingBox = False
srcImage = np.zeros((600, 800, 3), np.uint8)
tempImage = np.zeros((600, 800, 3), np.uint8)
def DrawRectangle(img, box):
cv2.rectangle(img, (box[0], box[1]), (box[0] + box[2], box[1] + box[3]),
(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)), 1)
return img
def GetRGBCvMouseCallback(event, x, y, flags, param):
global g_rectangle, g_bDrawingBox, srcImage
# 鼠标移动消息
if event == cv2.EVENT_MOUSEMOVE:
if g_bDrawingBox:
g_rectangle[2] = x - g_rectangle[0]
g_rectangle[3] = y - g_rectangle[1]
# 左键按下消息
if event == cv2.EVENT_LBUTTONDOWN:
# 记录起始点
g_bDrawingBox = True
g_rectangle[0] = x
g_rectangle[1] = y
g_rectangle[2] = 0
g_rectangle[3] = 0
elif event == cv2.EVENT_LBUTTONUP:
g_bDrawingBox = False
if g_rectangle[2] < 0:
g_rectangle[0] += g_rectangle[2]
g_rectangle[2] *= -1
if g_rectangle[3] < 0:
g_rectangle[1] += g_rectangle[3]
g_rectangle[3] *= -1
# 调用函数进行绘制
srcImage = DrawRectangle(srcImage, g_rectangle);
cv2.namedWindow('image')
cv2.setMouseCallback('image', GetRGBCvMouseCallback)
while (1):
np.copyto(tempImage, srcImage)
if g_bDrawingBox:
# 当进行绘制的标识符为真,则进行绘制
tempImage = DrawRectangle(tempImage, g_rectangle);
cv2.imshow('image', tempImage)
# 按下ESC键,程序退出
k = cv2.waitKey(10) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()