w15-小工具
功能
该工具可以完成检测图像中鼠标点击位置像素点的rgb值或者hsv值等的颜色像素值,并能够用鼠标在图像中画出一个封闭的轮廓,可以求出轮廓的面积和周长要求将结果显示在控制台或者图像上合适的位置(将结果显示在图像上时注意调整字体和大小合适)。
思路
由于opencv貌似没有可以直接绘制曲线的函数,所以我采用了化曲为直的思想,使用若干段直线拼接而成。在具体实现的过程中,我只需要记录当前时刻的鼠标坐标点(x, y),并保存上一次访问的点(ix, iy),最后一个点同第一个点连接成一个闭合的轮廓即可。
在识别轮廓方面,我先描述一下我的一个错误的做法:我在起初绘制完封闭轮廓后,想要通过先转灰度->简单阈值处理,使得图像二值化,进而提取轮廓。但是我疏忽了我起初的图像不是二值图像,在简单阈值处理之后会出现轮廓直接缺了一半的情况,所以我尝试通过自适应阈值的方法进行处理。这次的想法不错,效果也不错,从thresh图像可以基本地看出完整的轮廓,但是家人们,我尝试了用contourArea
和arcLength
函数对轮廓contours[0]
进行计算,结果两个输出均为0,这让我进一步陷入思考。经过分析,我觉得可能是findcontours
函数识别到了其他的轮廓,比如人脸等,所以我输出了contours
的长度,171这个数字也验证的我的想法是正确的。所以我不得不再次思考识别轮廓的想法。终于,我想到了可以直接创建另外一个二值化的图像,用白色的线条在上面和图像一样同步绘制就行,然后从这里识别并计算出响应的周长和面积,进行输出即可。
实验代码
import cv2 as cv
import numpy as np
ix, iy = -1, -1
sx, sy = -1, -1
def test(event, x, y, flags, param):
global drawing, ix, iy, sx, sy, click, img
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
if event == cv.EVENT_LBUTTONDOWN:
ix, iy = x, y
sx, sy = x, y
click = True
drawing = True
elif event == cv.EVENT_MOUSEMOVE:
if drawing:
cv.line(img, (ix, iy), (x, y), (0, 255, 0), 2, cv.LINE_AA)
cv.line(background, (ix, iy), (x, y), 255, 2)
ix = x
iy = y
elif event == cv.EVENT_LBUTTONUP:
if click:
print("BGR[{},{}]: {}".format(ix, iy, img[ix, iy]))
print("HSV[{},{}]: {}".format(ix, iy, hsv[ix, iy]))
print()
click = False
drawing = False
cv.line(img, (sx, sy), (ix, iy), (0, 255, 0), 2, cv.LINE_AA)
cv.line(background, (sx, sy), (ix, iy), 255, 2)
contours, hierarchy = cv.findContours(background, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
area = cv.contourArea(contours[0], False)
perimeter = cv.arcLength(contours[0], True)
print("area: {}".format(area))
print("perimeter: {}\n".format(perimeter))
# 在画布上绘制结果
cv.putText(img, "Area: {:.2f}".format(area), (10, 30), cv.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
cv.putText(img, "Perimeter: {:.2f}".format(perimeter), (10, 60), cv.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
# 创建一个窗口和图像,然后将回调函数与窗口绑定
img = cv.imread('iu.jpg')
img = cv.resize(img, None, fx=0.5, fy=0.5, interpolation=cv.INTER_CUBIC)
cv.namedWindow('iu')
cv.namedWindow('thresh')
cv.setMouseCallback('iu', test)
cv.setMouseCallback('thresh', test)
drawing = False # 是否正在绘制
click = False # 是否进行了点击
rows, cols, channels = img.shape
background = np.zeros((rows, cols), np.uint8)
while True:
cv.imshow('iu', img)
cv.imshow('thresh', background)
k = cv.waitKey(1) & 0xFF
if k == 27: # 按下ESC键退出
break
cv.destroyAllWindows()
结果会在控制台和图像中打印。