OpenCV中cv2.rectangle()函数详解与鼠标交互绘制矩形框实战

不晚
不晚
发布时间:2026-10-14| 4人浏览过
原创

本文详细解析OpenCV中cv2.rectangle()函数的参数用法,包括顶点坐标、颜色、线宽及抗锯齿选项。通过非交互式示例展示不同对角点组合的绘制效果,并深入讲解如何利用鼠标回调函数实现交互式矩形框绘制,涵盖状态标志管理、边界限制及实时刷新机制,提供完整Python代码实现。

关于鼠标回调函数的具体说明,可参考文章:opencv-python的鼠标交互操作。

cv2.rectangle()函数说明

参数说明

导入cv2模块后,执行help(cv2.rectangle)可查看该函数的帮助文档,内容如下:


rectangle(...)
    rectangle(img, pt1, pt2, color[, thickness[, lineType[, shift]]]) -> img
    .   @brief Draws a simple, thick, or filled up-right rectangle.
    .   
    .   The function cv::rectangle draws a rectangle outline or a filled rectangle whose two opposite corners
    .   are pt1 and pt2.
    .   
    .   @param img Image.
    .   @param pt1 Vertex of the rectangle.
    .   @param pt2 Vertex of the rectangle opposite to pt1 .
    .   @param color Rectangle color or brightness (grayscale image).
    .   @param thickness Thickness of lines that make up the rectangle. Negative values, like #FILLED,
    .   mean that the function has to draw a filled rectangle.
    .   @param lineType Type of the line. See #LineTypes
    .   @param shift Number of fractional bits in the point coordinates.
    
    
    
    rectangle(img, rec, color[, thickness[, lineType[, shift]]]) -> img
    .   @overload
    .   
    .   use `rec` parameter as alternative specification of the drawn rectangle: `r.tl() and
    .   r.br()-Point(1,1)` are opposite corners

其中四个参数为必选参数:

  • img:指定底图,类型必须为uint8类型的ndarray。
  • pt1:矩形框的一个顶点坐标,必须为包含两个数字的tuple,表示(x, y)。
  • pt2:pt1的对角线顶点坐标,类型与pt1保持一致。
  • color:指定颜色,为包含三个数字的tuple或list,表示(b, g, r)顺序;若处理灰度图,color可简化为单个数字。

其他可选参数说明如下:

  • thickness:指定线宽,默认值为1,数值越大线条越粗;若取值为负数或cv2.FILLED,则绘制填充矩形。
  • lineType:可选值包括cv2.LINE_4、cv2.LINE_8和cv2.LINE_AA。其中cv2.LINE_AA表示抗锯齿,能使线条更平滑。

注意:pt1和pt2代表任意一对对角线上的点,不强制要求pt1为左上角、pt2为右下角。此外,pt1和pt2的顺序互换不影响绘制结果。

以下是一个非交互式程序示例:


# -*- coding: utf-8 -*-

import cv2
import numpy as np

if __name__ == '__main__':
    image = np.zeros((256, 256, 3), np.uint8)
    color = (0, 255, 0)
    cv2.rectangle(image, (20, 20), (60, 60), (0, 255, 0))
    cv2.rectangle(image, (120, 120), (80, 80), (255, 0, 0), thickness=-1)
    cv2.rectangle(image, (140, 200), (200, 140), (0, 0, 255), thickness=5)
    cv2.namedWindow('rect', 1)
    cv2.imshow('rect', image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

第一个矩形框中,pt1为左上角,pt2为右下角。

第二个矩形框中,pt1为右下角,pt2为左上角。

第三个矩形框中,pt1为右上角,pt2为左下角。

得到的结果如下:

利用鼠标回调函数交互式画矩形框

为了便于理解后续程序,建议先参考文章中的例2。

opencv-python鼠标画点:cv2.drawMarker()。

下面程序的操作方法如下:

  • 鼠标左键按下时,开始绘制当前矩形框。
  • 移动鼠标以进行绘画操作。
  • 左键弹起时,当前矩形框绘制结束,并将其加入矩形框列表。
  • 鼠标右键按下时,删除矩形框列表中的最后一个对象。

编程注意事项:

  • 在矩形框绘画过程中,需记录一个鼠标左键按下的状态标志。常规状态下该标志设为False,此时移动鼠标不进行绘画;当鼠标左键按下后,标志设为True,进入绘画状态;左键弹起后,标志恢复为False。
  • 为了在鼠标移动过程中实时显示绘画状态,需不断重置用于显示的图像,并重新绘制所有已保存的矩形框。
  • 矩形框的第二个点通过shrink_point获取,以确保不超出图像边界。

# -*- coding: utf-8 -*-

import copy
import cv2
import numpy as np

WIN_NAME = 'draw_rect'


class Rect(object):
    def __init__(self):
        self.tl = (0, 0)
        self.br = (0, 0)

    def regularize(self):
        """
        make sure tl = TopLeft point, br = BottomRight point
        """
        pt1 = (min(self.tl[0], self.br[0]), min(self.tl[1], self.br[1]))
        pt2 = (max(self.tl[0], self.br[0]), max(self.tl[1], self.br[1]))
        self.tl = pt1
        self.br = pt2


class DrawRects(object):
    def __init__(self, image, color, thickness=1):
        self.original_image = image
        self.image_for_show = image.copy()
        self.color = color
        self.thickness = thickness
        self.rects = []
        self.current_rect = Rect()
        self.left_button_down = False

    @staticmethod
    def __clip(value, low, high):
        """
        clip value between low and high

        Parameters
        ----------
        value: a number
            value to be clipped
        low: a number
            low limit
        high: a number
            high limit

        Returns
        -------
        output: a number
            clipped value
        """
        output = max(value, low)
        output = min(output, high)
        return output

    def shrink_point(self, x, y):
        """
        shrink point (x, y) to inside image_for_show

        Parameters
        ----------
        x, y: int, int
            coordinate of a point

        Returns
        -------
        x_shrink, y_shrink: int, int
            shrinked coordinate
        """
        height, width = self.image_for_show.shape[0:2]
        x_shrink = self.__clip(x, 0, width)
        y_shrink = self.__clip(y, 0, height)
        return (x_shrink, y_shrink)

    def append(self):
        """
        add a rect to rects list
        """
        self.rects.append(copy.deepcopy(self.current_rect))

    def pop(self):
        """
        pop a rect from rects list
        """
        rect = Rect()
        if self.rects:
            rect = self.rects.pop()
        return rect

    def reset_image(self):
        """
        reset image_for_show using original image
        """
        self.image_for_show = self.original_image.copy()

    def draw(self):
        """
        draw rects on image_for_show
        """
        for rect in self.rects:
            cv2.rectangle(self.image_for_show, rect.tl, rect.br,
                          color=self.color, thickness=self.thickness)

    def draw_current_rect(self):
        """
        draw current rect on image_for_show
        """
        cv2.rectangle(self.image_for_show,
                      self.current_rect.tl, self.current_rect.br,
                      color=self.color, thickness=self.thickness)


def onmouse_draw_rect(event, x, y, flags, draw_rects):
    if event == cv2.EVENT_LBUTTONDOWN:
        # pick first point of rect
        print('pt1: x = %d, y = %d' % (x, y))
        draw_rects.left_button_down = True
        draw_rects.current_rect.tl = (x, y)
    if draw_rects.left_button_down and event == cv2.EVENT_MOUSEMOVE:
        # pick second point of rect and draw current rect
        draw_rects.current_rect.br = draw_rects.shrink_point(x, y)
        draw_rects.reset_image()
        draw_rects.draw()
        draw_rects.draw_current_rect()
    if event == cv2.EVENT_LBUTTONUP:
        # finish drawing current rect and append it to rects list
        draw_rects.left_button_down = False
        draw_rects.current_rect.br = draw_rects.shrink_point(x, y)
        print('pt2: x = %d, y = %d' % (draw_rects.current_rect.br[0],
                                       draw_rects.current_rect.br[1]))
        draw_rects.current_rect.regularize()
        draw_rects.append()
    if (not draw_rects.left_button_down) and event == cv2.EVENT_RBUTTONDOWN:
        # pop the last rect in rects list
        draw_rects.pop()
        draw_rects.reset_image()
        draw_rects.draw()


if __name__ == '__main__':
    image = np.zeros((256, 256, 3), np.uint8)
    draw_rects = DrawRects(image, (0, 255, 0), 2)
    cv2.namedWindow(WIN_NAME, 0)
    cv2.setMouseCallback(WIN_NAME, onmouse_draw_rect, draw_rects)
    while True:
        cv2.imshow(WIN_NAME, draw_rects.image_for_show)
        key = cv2.waitKey(30)
        if key == 27:  # ESC
            break
    cv2.destroyAllWindows()

终端输出:

pt1: x = 55, y = 68 pt2: x = 0, y = 0 pt1: x = 195, y = 60 pt2: x = 256, y = 0 pt1: x = 59, y = 192 pt2: x = 0, y = 256 pt1: x = 194, y = 190 pt2: x = 256, y = 256 pt1: x = 94, y = 111 pt2: x = 170, y = 168

结果如下:

总结

到此这篇关于python opencv鼠标画矩形框之cv2.rectangle()函数的文章就介绍到这了,更多相关opencv鼠标画矩形框cv2.rectangle()内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。