使用Python和OpenCV进行区域颜色填充:填充矩形的方法
基础到进阶,跨度有点大,我们还是先踏实基础吧。对图像的处理实际上还是对图像像素矩阵的处理,当然还需要点想象空间。上一篇文章我们介绍了opencv的最基本用法,能够实现图片的加载、生成、读取像素矩阵、三通道分解等,详见:
peter.cao:图像处理之OpenCV的基础使用zhuanlan.zhihu.com
下面继续基础知识的应用实践。需要说明一下的是,在写下这些文字的过程中主要参考的是opencv的官方文档,如下为其链接:
OpenCV-Python Tutorialsdocs.opencv.org
- 给图形增添简单元素
这里添加简单元素不是改变某一个范围的像素值,而是在已有图形上来添加线、矩形、园等元素。在添加的时候应该就是改变元素轨迹上的原有点像素值。
案例1:添加一条直线,使用cv2.line()函数
cv2.line(img,sp,ep,color,thickness,linetype): img就是目标图,sp为起始坐标,ep为终点坐标,color为颜色,thickness为线的粗细,linetype为线型。
import numpy as np
import cv2
img0= np.array(np.ones((300,300,3),dtype=np.uint8)) #构建一个三通道都是1的像素矩阵
cv2.line(img0,pt1=(10,10),pt2=(200,200),color=(255,0,0)) #在img0上绘制一条直线
cv2.imshow('line',img0)
cv2.waitKey(0)
执行效果为:
案例2:添加一个矩形,使用cv2.rectangle函数
cv2.rectangle(img,sp,ep,color,thickness,linetype): img就是目标图,sp为起始坐标,ep为终点坐标,color为颜色,thickness为线的粗细,linetype为线型。参数与line函数一样。
import numpy as np
import cv2
img0= np.array(np.ones((300,300,3),dtype=np.uint8))
cv2.line(img0,pt1=(10,10),pt2=(200,200),color=(255,0,0))
cv2.rectangle(img0,pt1=(40,40),pt2=(200,200),color=(0,255,0)) #绘制一个矩形框
cv2.imshow('line',img0)
cv2.waitKey(0)
执行效果为:
案例3:添加一个园,使用cv2.circle函数
cv2.circle(img,center,radius,color,thickness,linetype): img就是目标图,center为园中心坐标,radius为园半径,color为边界颜色,thickn为边界粗细,linetype为边界线型。
import numpy as np
import cv2
img0= np.array(np.ones((300,300,3),dtype=np.uint8))
cv2.line(img0,pt1=(10,10),pt2=(200,200),color=(255,0,0))
cv2.rectangle(img0,pt1=(40,40),pt2=(200,200),color=(0,255,0))
cv2.circle(img0,center=(50,50),radius=20,color=(0,0,255)) #绘制一个圆形
cv2.imshow('line',img0)
cv2.waitKey(0)
执行效果如下:
从上述执行效果看到,对于cv2的颜色模型,三通道顺序为BGR,而不是RGB,这一点需要注意一下。
案例4:添加标注,可以使用putText函数
putText(img,text,org,fontFace,fontScale,color,thickness,lineType): text为标注的文字内容,org为起始的坐标,fontFace为字体类型,fontScale为字体比例倍数,color为颜色,thickness为字体线型宽度,lineType为线型。
import numpy as np
import cv2
img0= np.array(np.ones((300,300,3),dtype=np.uint8))
cv2.line(img0,pt1=(10,10),pt2=(200,200),color=(255,0,0))
cv2.rectangle(img0,pt1=(40,40),pt2=(200,200),color=(0,255,0))
cv2.circle(img0,center=(50,50),radius=20,color=(0,0,255))
cv2.putText(img0,text='topher',org=(50,100),fontFace=cv2.FONT_HERSHEY_COMPLEX,fontScale=2,color=(255,0,0),thickness=2,lineType=cv2.LINE_AA)
cv2.imshow('line',img0)
cv2.waitKey(0)
执行效果如下:
2. 给鼠标添加事件
鼠标主要是点击事件和滑动,比如左键点击、左键双击、右键点击、中键滑动等,可以在代码里输入cv2.EVENT,根据pycharm的代码补全功能,就会将后续的函数全称显示出来,如下:
如图大概有十几个鼠标事件,包括了左键、中键和右键三个部分。
可以写一个专门用于鼠标测试的函数,对各个点击事件进行测试说明:
# mouse callback function
def mouse_event(event, x, y, flags, param):
'''
:param event: 点击事件标识
:param x: 坐标x
:param y: 坐标y
:param flags:按键事件标识
:param param: 携带参数
:return:
'''
if flags == cv2.EVENT_FLAG_ALTKEY:
print('摁住Alt')
if flags == cv2.EVENT_FLAG_CTRLKEY:
print('摁住Ctrl')
if flags == cv2.EVENT_FLAG_SHIFTKEY:
print('摁住Shift')
if flags == cv2.EVENT_FLAG_LBUTTON:
print('摁住左键')
if flags == cv2.EVENT_FLAG_MBUTTON:
print('摁住中键')
if flags == cv2.EVENT_FLAG_RBUTTON:
print('摁住右键')
if event == cv2.EVENT_LBUTTONDBLCLK:
print('左键双击')
if event == cv2.EVENT_MBUTTONDBLCLK:
print('中键双击')
if event == cv2.EVENT_RBUTTONDBLCLK:
print('右键双击')
if event == cv2.EVENT_LBUTTONDOWN:
print('左键击下')
if event == cv2.EVENT_LBUTTONUP:
print('左键弹起')
if event == cv2.EVENT_MBUTTONDOWN:
print('中键击下')
if event == cv2.EVENT_MBUTTONUP:
print('中键弹起')
if event == cv2.EVENT_RBUTTONDOWN:
print('右键击下')
if event == cv2.EVENT_RBUTTONUP:
print('右键弹起')
if event == cv2.EVENT_MOUSEWHEEL:
if flags > 0:
print('向前滚动')
else:
print('向后滚动')
if event == cv2.EVENT_MOUSEHWHEEL:
if flags > 0:
print('向左滚动') # 按住Alt
else:
print('向右滚动')
if __name__ == '__main__':
img = np.mat(np.zeros((300, 300, 3), np.uint8)) # 构造一个像素值全为1的图形
cv2.namedWindow('mouse') #命名窗口为mouse
cv2.setMouseCallback('mouse', mouse_event) # 窗口与回调函数绑定
while True:
cv2.imshow('mouse', img)
if cv2.waitKey(1) & 0xFF == ord('q'): # 摁下q退出
break
cv2.destroyAllWindows() #销毁所有窗口
执行程序后,就可以在弹出的黑色窗口里对鼠标事件进行测试,测试时会在终端打印鼠标事件名称。下面结合添加简单元素效果进行示例。
案例1:鼠标左键双击时绘制一个圆形
使用函数cv2.EVENT_LBUTTONDBLCLK触发,我们可以直接将上述代码修改一下:
def draw_circle(event,x,y,flags,param):
if event == cv2.EVENT_LBUTTONDBLCLK: #鼠标为左键双击时
cv2.circle(img,(x,y),100,(255,0,0)) #画一个半径为100,边界颜色为蓝色的园,后面如果增加-1参数,表示填充
if __name__ == '__main__':
img = np.zeros((300, 300, 3), np.uint8) # 构建一个300x300黑色背景图
cv2.namedWindow('test')
cv2.setMouseCallback('test', draw_circle) # 窗口与回调函数绑定
while(1):
cv2.imshow('test', img)
if cv2.waitKey(10)& 0xFF == 27: #按ESC键退出
break
cv2.destroyAllWindows()
这段代码中,draw_circle函数参数里x和y默认取得鼠标当前所在的位置,
cv2.waitKey(10)& 0xFF == 27: 其中waitKey前面介绍过,等待按键,参数10表示读帧间隔时间,当为10时表示每隔10s读一下图,因为这里只有一张图,实际上这个取值变化影响不大,而本身waiKey是一个动作,等待按键期间如果没有按键,返回-1,如果有按键,返回按键的ASCII码;0xFF是十六进制表示,cv2.waitKey(10)& 0xFF是一个逻辑与运算,waitKey()是有返回值的,当这个返回值与0xFF进行逻辑与操作时,得到的值如果为27,对应的按键就是ESC。
执行代码后,当鼠标在任意位置双击时就可以绘制出圆形来。这里点击了4次,效果如下:
案例2:在案例1基础上增加一个右键点击按钮事件,绘制一个矩形
增加右键单击函数cv2.EVENT_RBUTTONDOWN,如下:
def draw_circle(event,x,y,flags,param):
if event == cv2.EVENT_LBUTTONDBLCLK:
cv2.circle(img,(x,y),100,(255,0,0))
elif event == cv2.EVENT_RBUTTONDOWN:
cv2.rectangle(img,(x,y),(x+100,y+50),color=(0, 255, 0))
if __name__ == '__main__':
img = np.zeros((500, 500, 3), np.uint8) # 500x500黑色背景
cv2.namedWindow('test')
cv2.setMouseCallback('test', draw_circle)
while(1):
cv2.imshow('test', img)
if cv2.waitKey(10)& 0xFF == 27: #按ESC键退出
break
cv2.destroyAllWindows()
执行后效果如下:
上一篇: 在Matlab中实现图像区域填充的方法
下一篇: Java中的OAEP填充方式有哪些?