python opencv鼠標畫點之cv2.drawMarker()函數

前言

這裡所謂畫點的意思是指在單一像素點上畫一個標記符,而不是畫小圓點。使用的函數是cv2.drawMarker(img, position, color, …)

關於鼠標回調函數的說明可以參考:opencv-python的鼠標交互操作

cv2.drawMarker()函數說明

參數說明

導入cv2後,通過help(cv2.drawMarker)可以看到函數的幫助文檔如下:

drawMarker(...)
    drawMarker(img, position, color[, markerType[, markerSize[, thickness[, line_type]]]]) -> img
    .   @brief Draws a marker on a predefined position in an image.
    .   
    .   The function cv::drawMarker draws a marker on a given position in the image. For the moment several
    .   marker types are supported, see #MarkerTypes for more information.
    .   
    .   @param img Image.
    .   @param position The point where the crosshair is positioned.
    .   @param color Line color.
    .   @param markerType The specific type of marker you want to use, see #MarkerTypes
    .   @param thickness Line thickness.
    .   @param line_type Type of the line, See #LineTypes
    .   @param markerSize The length of the marker axis [default = 20 pixels]

其中三個必選參數:img, position, color,其他參數是可選。三個必選參數說明如下:

  • img:底圖,uint8類型的ndarray,
  • position:坐標,是一個包含兩個數字的tuple(必需是tuple),表示(x, y)
  • color:顏色,是一個包含三個數字的tuple或list,表示(b, g, r)

其他參數說明如下:

  • markerType:點的類型。取值0-6,有相應的宏定義與之對應,具體的可參考下面的一個表。
  • markerSize:點的大小。大於0的整數,必需是整數。實際輸入<=0的數字也可,但是估計程序裡有判斷,<=0等同於1。默認值是20。
  • thickness:點的線寬。必需是大於0的整數,必需是整數,不能小於0,默認值是1。
  • line_type:線的類型。可以取的值有cv2.LINE_4,cv2.LINE_8,cv2.LINE_AA。其中cv2.LINE_AA的AA表示抗鋸齒,線會更平滑。

markerType取值說明

數值 宏定義 說明
0 cv2.MARKER_CROSS 十字線(橫豎兩根線)
1 cv2.MARKER_TILTED_CROSS 交叉線(斜著兩根線)
2 cv2.MARKER_STAR 米字線(橫豎加斜著共四根線)
3 cv2.MARKER_DIAMOND 旋轉45度的正方形
4 cv2.MARKER_SQUARE 正方形
5 cv2.MARKER_TRIANGLE_UP 尖角向上的三角形
6 cv2.MARKER_TRIANGLE_DOWN 尖角向下的三角形

markerType示例

下面是一個簡單的畫點程序

# -*- 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.drawMarker(image, (50, 50), color, markerType=0)
    cv2.drawMarker(image, (100, 50), color, markerType=1)
    cv2.drawMarker(image, (150, 50), color, markerType=2)
    cv2.drawMarker(image, (200, 50), color, markerType=3)
    cv2.drawMarker(image, (50, 100), color, markerType=4)
    cv2.drawMarker(image, (100, 100), color, markerType=5)
    cv2.drawMarker(image, (150, 100), color, markerType=6)
    cv2.namedWindow('marker_type', 1)
    cv2.imshow('marker_type', image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

請特別註意,opencv在調用這些畫圖函數後,image的內容會被這些畫圖函數改變,也就是說,函數調用之後,我們就拿不回原始的image瞭,除非另外保存一份原始image的副本。在寫一些交互畫圖函數時,這個特性需要格外註意。

程序執行結果如下。

利用鼠標回調函數交互式畫點

例1,簡單的例子

該例子與 中的例子相同

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

import cv2
import numpy as np

WIN_NAME = 'pick_points'


def onmouse_pick_points(event, x, y, flags, param):
    if event == cv2.EVENT_LBUTTONDOWN:
        print('x = %d, y = %d' % (x, y))
        cv2.drawMarker(param, (x, y), (0, 255, 0))


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

上面程序中有幾個註意點:

  • setMouseCallback()中的param參數我們傳遞瞭image進去,也就是說鼠標回調函數onmouse_pick_points()中的param就是image,畫點的操作在鼠標回調函數中,該參數在onmouse_pick_points中的變化可以保留到函數外,可以理解為C++的引用傳遞,或C語言的指針傳遞。
  • 需要一個無限循環來刷新圖像。
  • 無限循環的退出條件由鍵盤獲取,cv2.waitKey()用來獲取鍵盤的按鍵,當我們點ESC後就可以退出。

這裡點瞭三次左鍵,終端輸出以下內容:

x = 60, y = 55
x = 206, y = 113
x = 114, y = 192

並得到這樣一張圖像:

例2,刪除功能

如果需要刪除已經畫瞭的點的功能,那麼問題就變得略有些復雜瞭。

我們之前講過,opencv在畫瞭這些點之後,圖像的像素已經事實上被改變瞭,想要緊緊通過當前圖像將其恢復原狀是不行的。所以為瞭實現刪除功能,我們需要備份一張原始圖像,一張用來對外顯示的圖像,以及一個由點坐標組成的list。

每次做刪除點的操作後,我們都使用原始圖像重置對外顯示的圖像,然後再把list中所有的點都重新畫在對外顯示的圖像上,就可以實現刪除點的效果。如果是增加點的操作,則不用重置圖像。

實現代碼如下:

下面代碼中,左鍵實現增加一個點的操作,右鍵依次刪除後面畫上的點。

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

import cv2
import numpy as np

WIN_NAME = 'pick_points'


class DrawPoints(object):
    def __init__(self, image, color,
                 marker_type=cv2.MARKER_CROSS,
                 marker_size=20,
                 thickness=1):
        """
        Initialization of class DrawPoints

        Parameters
        ----------
        image: ndarray
            source image. shape is [height, width, channels]
        color: tuple
            a tuple containing uint8 integers, designating B, G, R values,
            separately
        marker_type: int
            marker type, between [0, 6]
        marker_size: int
            marker size, >=1
        thickness: int
            line thickness, >=1
        """
        self.original_image = image
        self.image_for_show = image.copy()
        self.color = color
        self.marker_type = marker_type
        self.marker_size = marker_size
        self.thickness = thickness
        self.pts = []

    def append(self, x, y):
        """
        add a point to points list

        Parameters
        ----------
        x, y: int, int
            coordinate of a point
        """
        self.pts.append((x, y))

    def pop(self):
        """
        pop a point from points list
        """
        pt = ()
        if self.pts:
            pt = self.pts.pop()
        return pt

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

    def draw(self):
        """
        draw points on image_for_show
        """
        for pt in self.pts:
            cv2.drawMarker(self.image_for_show, pt, color=self.color,
                           markerType=self.marker_type,
                           markerSize=self.marker_size,
                           thickness=self.thickness)


def onmouse_pick_points(event, x, y, flags, draw_pts):
    if event == cv2.EVENT_LBUTTONDOWN:
        print('add: x = %d, y = %d' % (x, y))
        draw_pts.append(x, y)
        draw_pts.draw()
    elif event == cv2.EVENT_RBUTTONDOWN:
        pt = draw_pts.pop()
        if pt:
            print('delete: x = %d, y = %d' % (pt[0], pt[1]))
            draw_pts.reset_image()
            draw_pts.draw()


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

終端輸出如下:

add: x = 54, y = 51
add: x = 215, y = 81
add: x = 123, y = 121
add: x = 57, y = 197
add: x = 168, y = 210
delete: x = 168, y = 210
delete: x = 57, y = 197

得到的結果如下:

總結

到此這篇關於python opencv鼠標畫點之cv2.drawMarker()函數的文章就介紹到這瞭,更多相關opencv鼠標畫點cv2.drawMarker()內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: