在上一节中,讲解了大量的概念,比较零散,于是,在这一节,将通过一个绘图板的综合项目将上一节的知识汇总起来,此外,之前的课程主要讲解OpenCV中一些基本操作,并未涉及OpenCV的精髓内容,因此,尽量早些完成相关操作的讲解,尽快进入算法讲解的环节中。test
1.思路分析
类似于液晶触摸的书写,我们来研究下如何实现绘图功能。
本质上,绘图是绘制线条,曲线可以分解成很多直线,直线可以分解成很多点,因此,就先从绘制点开始。
绘制点时鼠标在移动,因此,要设置鼠标的回调函数,那当什么时候调用回调函数呢,显然,是鼠标左键按下并且鼠标在移动的时候。
因此,程序整体结构是:定义一个回调函数,这个回调函数用于画图;然后建立一个窗口,窗口绑定回调函数;最后将回调函数画的图显示在这个窗口上。
想法有了,可以开始着手了。
2.写出基本结构
由于Python的便捷性,先采用Python实现,不用太顾及语法问题。
下面先调出第一个版本的源码。
import cv2
import numpy as np
cv2.namedWindow('image')
img = np.zeros((800,600,3), np.uint8)
def draw_point(event,x,y,flags,param):
if event == cv2.EVENT_LBUTTONDOWN:
cv2.circle(img,(x,y),20,(255,0,0),-1)
cv2.setMouseCallback('image', draw_point)
while(True):
cv2.imshow('image',img)
if (cv2.waitKey(1) == ord('q')):
break
cv2.destroyAllWindows()
cv2.imwrite( "OpenCV_Paint.png",img)
第一个版本运行效果如下图所示:
3.总结,改进
在上一版本中,鼠标按下后,只能画一个点,在此情况下,需要改进为鼠标按下后,就一直画点,于是,改进后,就有了以下代码
import cv2
import numpy as np
isMouseLBDown = False
def draw_circle(event,x,y,flags,param):
print(event)
global isMouseLBDown
if event == cv2.EVENT_LBUTTONDOWN:
print("mouse down")
isMouseLBDown = True
cv2.circle(img,(x,y),5,(255,0,0),-1)
elif event == cv2.EVENT_LBUTTONUP:
isMouseLBDown = False
print("mouse up")
elif event == cv2.EVENT_MOUSEMOVE:
if isMouseLBDown:
print("drawing")
cv2.circle(img,(x,y),5,(255,0,0),-1)
img = np.zeros((512,512,3), np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_circle)
while(True):
cv2.imshow('image',img)
if cv2.waitKey(1) == ord('q'):
break
cv2.destroyAllWindows()
cv2.imwrite("OpenCV_Paint.png", img)
程序运行效果如下图所示:
程序运行后,在黑窗中,按下鼠标左键,并且移动鼠标,即可绘制图案。
3.再次总结,改进
经过一番改进,总算是能画图了,但是,画图过程中,如果画笔速度过快,那么,将会导致出现断点,并且使用上,不能调整画笔的颜色,画笔的宽度等一系列参数。为此做了以下改进:
import cv2
import numpy as np
isMouseLBDown = False
circleColor = (0, 0, 0)
circleRadius = 5
lastPoint = (0, 0)
def draw_circle(event,x,y,flags,param):
global img
global isMouseLBDown
global color
global lastPoint
if event == cv2.EVENT_LBUTTONDOWN:
isMouseLBDown = True
cv2.circle(img,(x,y), int(circleRadius/2), circleColor,-1)
lastPoint = (x, y)
elif event == cv2.EVENT_LBUTTONUP:
isMouseLBDown = False
elif event == cv2.EVENT_MOUSEMOVE:
if isMouseLBDown:
cv2.line(img, pt1=lastPoint, pt2=(x, y), color=circleColor, thickness=circleRadius)
lastPoint = (x, y)
def updateCircleColor(x):
global circleColor
global colorPreviewImg
r = cv2.getTrackbarPos('Channel_Red','image')
g = cv2.getTrackbarPos('Channel_Green','image')
b = cv2.getTrackbarPos('Channel_Blue','image')
circleColor = (b, g, r)
colorPreviewImg[:] = circleColor
def updateCircleRadius(x):
global circleRadius
global radiusPreview
circleRadius = cv2.getTrackbarPos('Circle_Radius', 'image')
radiusPreview[:] = (255, 255, 255)
cv2.circle(radiusPreview, center=(50, 50), radius=int(circleRadius / 2), color=(0, 0, 0), thickness=-1)
img = np.ones((512,512,3), np.uint8)
img[:] = (255, 255, 255)
colorPreviewImg = np.ones((100, 100, 3), np.uint8)
colorPreviewImg[:] = (0, 0, 0)
radiusPreview = np.ones((100, 100, 3), np.uint8)
radiusPreview[:] = (255, 255, 255)
cv2.namedWindow('image')
cv2.namedWindow('colorPreview')
cv2.namedWindow('radiusPreview')
cv2.setMouseCallback('image',draw_circle)
cv2.createTrackbar('Channel_Red','image',60,255,updateCircleColor)
cv2.createTrackbar('Channel_Green','image',120,255,updateCircleColor)
cv2.createTrackbar('Channel_Blue','image',180,255,updateCircleColor)
cv2.createTrackbar('Circle_Radius','image',2,20,updateCircleRadius)
while(True):
cv2.imshow('image',img)
cv2.imshow('colorPreview', colorPreviewImg)
cv2.imshow('radiusPreview', radiusPreview)
if cv2.waitKey(1) == ord('q'):
break
cv2.destroyAllWindows()
cv2.imwrite("OpenCV_Paint.png", img)
程序运行效如下图所示,通过该程序,即可比较方便地绘图,并且,可调整画笔的颜色以及画笔的粗细: