思路:绘制封闭曲线,获得轮廓, 对轮廓进行填充
因为在绘制曲线的时候,记录了起始点和最后一个点的坐标,用以使曲线封闭,所以绘制的时候只需要绘制到起点的附近区域即可,松开鼠标后,曲线连接起点和终点,实现封闭
注意:该代码不适合绘制复杂图形
import numpy as np
import matplotlib.pyplot as plt
from numpy.core.defchararray import count
import cv2 as cv
#step 1. 读取,预处理
img_source = cv.imread("duo.jpg") #原图(三通道)
img = cv.cvtColor(img_source, cv.COLOR_BGR2GRAY) #转为灰度图像(单通道),便于查找轮廓
img[:,:] = 0 #改成黑色图像,用于获取所绘制的闭合曲线的轮廓
cv.namedWindow('image', cv.WINDOW_AUTOSIZE) #在原图中显示
cv.namedWindow('test')
#step 2. 绘制任意形状的图形
drawing = False #开始鼠标移动绘图模式
ix, iy= -1, -1
px, py = -1, -1
#call back function
def drawCurve(event, x, y, flags, param):
global ix, iy, drawing, px, py
if event == cv.EVENT_LBUTTONDOWN:
drawing = True
print("start point")
ix, iy = x, y
px, py = x, y
elif event == cv.EVENT_MOUSEMOVE:
if drawing: #关键是如何记录相邻两次的坐标
print("mouse move")
#用于获得轮廓的图像
cv.circle(img, (x, y), 1, (255, 255, 255), -1) #注意灰度图像中的白色是全部255
cv.line(img, (ix, iy), (x,y), (255, 255, 255), 2) #关键是如何记录相邻两次的坐标
#在原图中显示
cv.circle(img_source, (x, y), 1, (0, 255, 255), -1)
cv.line(img_source, (ix, iy), (x,y), (0, 255, 255), 2)
ix, iy = x,y #用来记录上一个点的坐标
elif event == cv.EVENT_LBUTTONUP:
drawing = False
#使曲线闭合, 用于获取轮廓
cv.line(img, (x, y), (px, py), (255, 255, 255), 2) #将曲线补充成闭合曲线
#仅用于在原图中显示
cv.line(img_source, (x, y), (px, py), (0, 255, 255), 2) #将曲线补充成闭合曲线
cv.setMouseCallback("image", drawCurve) #可以在原图中直接绘制
cv.setMouseCallback('test', drawCurve) #可以在获得轮廓的图中直接绘制
while True:
k = cv.waitKey(1)
cv.imshow("image", img_source) #显示原图
cv.imshow("test", img) #显示获取轮廓的图像
if k == 27:
break
#step 3. 查找轮廓
#一般情形考虑先二值化,因为这里获取轮廓的图像在前两部的操作过程中只有黑白两种颜色(轮廓为白)
contours, hierarchy = cv.findContours(img, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
cv.drawContours(img_source, contours, -1, (0,255,0), -1)
print("congralations!")
#step 4. 给轮廓填充颜色
cv.fillPoly(img_source,[contours[1]],(255,0,0)) #填充内部
cv.imshow("result", img_source)
cv.waitKey(0)
cv.destroyAllWindows()
print('hello world')
测试图像:
因为在绘制曲线的时候,记录了起始点和最后一个点的坐标,用以使曲线封闭,所以绘制的时候只需要绘制到起点的附近区域即可,松开鼠标后,曲线连接起点和终点,实现封闭