小白菜的opencv学习(3)在图像上绘制和写字
我们知道,机器视觉在识别后最直接观察的办法就是画出来,把人物、图形描述出来。今天就学习如何在图像上绘制和写字。文章最后会尝试在摄像头采集的视频中绘制写字。
在图片上绘图的库可以想象有很多很多,我之前用单片机做的一个tft显示屏的库里都有比较成熟的绘图命令。opencv也提供了这样的命令,接下来介绍几个简单比较常用。
cv2.line(img,(0,0),(500,500),(0,255,0),15)
最基础的,画一条线。
在《学习opencv3(中文版)》中,是这样写的:
cv::line()
void line(
cv::Mat& img, //Image to be drawn on
cv::Point pt1, // First endpoint of line
cv::Point pt2 // Second endpoint of line
const cv::Scalar& color, // Color, BGR form
int lineType = 8, // Connectedness, 4 or 8
int shift = 0 // Bits of radius to treat as fract
);
cv:line()函数在图像img上绘制一条从pt1到pt2的直线。直线自动被图像边缘截断。
可能是版本不对,该函数实际上有7个参数。
前五个参数很好理解,img图片或者帧,pt1线段开始坐标,pt2线段结束坐标,color线段颜色,thickness线段宽度。这几个参数在上面的参数中都写到了,剩下的两个lineType和shift两个参数不常用。
lineType是线条类型,只能有三种数值(4 or 8 or cv::lineAA),三种类型表示着不同斜线绘制的时候不同算法,可以自行尝试。
shift是亚像素对齐,我没听懂什么意思,看了下注释,相当于缩放了2shift倍,比如(2.5,2.5)像素处画一个点,由于2.5是浮点型,所以程序会报错,而写(5,5)像素并将shift设置为shift=2,那么会将设定的像素点缩小到原来的21倍,就变成了想要的(2.5,2.5)。
第二个绘制矩形。
cv2.rectangle(img,(0,200),(500,150),(0,0,255),10)
几个参数很好理解,图片,两个对角线的坐标,然后是颜色、线宽。同样,矩形的函数中也有lineType,shift两个参数,基本上所有绘图命令都是以这两个参数结尾,下面不再赘述。
第三个绘制圆形。
cv2.circle(img,(500,100),55,(0,255,0),-1)
这里可以发现,线宽变成了-1,像矩形、多边形、圆形这类封闭图形,都可以把线宽改成-1,使图形内部填充满相同颜色。
第四个多边形的绘制。
pts = np.array([[100,5],[100,50],[70,200],[200,100]],np.int32)
cv2.polylines(img, [pts], True, (0,255,255), 3)
多边形的绘制这里是采用将多个像素坐标直线连接的方法。pts变量将多个坐标“打包”,然后用cv2.polylines()命令绘画,这里多了一个实参True,对应的形参是isClosed。如果为真,那么就把第一个点和最后一点连起来,否则就不连接,那么就是is Closed?False!
最后一个,写字。
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img,'OpenCV Tuts!',(0,130), font, 1, (200,255,155), 2, cv2.LINE_AA)
font是定义的字体类型,opencv提供了以下几种字体:
标识符 | 描述 |
---|---|
CV::FONT_HERSHEY_SIMPLEX | 普通大小无衬线字体 |
CV::FONT_HERSHEY_PLAIN | 小号无衬线字体 |
CV::FONT_HERSHEY_DUPLEX | 普通大小无衬线字体 |
CV::FONT_HERSHEY_COMPLEX | 比CV::FONT_HERSHEY_SIMPLEX更复杂 |
CV::FONT_HERSHEY_TRIPLEX | 普通大小无衬线字体,比cv::FONT_HERSHEY_DUPLEX更复杂 |
CV::FONT_HERSHEY_COMPLEX_SMALL | 普通大小无衬线字体,比CV::FONT_HERSHEY_COMPLEX更复杂 |
CV::FONT_HERSHEY_SCRIPT_SIMPLEX | 小号版本的CV::FONT_HERSHEY_COMPLEX手写体 |
CV::FONT_HERSHEY_SCRIPT_COMPLEX | 比CV::FONT_HERSHEY_SCRIPT_SIMPLEX更复杂的变体 |
个人感觉最后两种真漂亮
这里的像素点坐标是指字体左上角的像素点。
参数font后面跟的1是fontScale,即字体的高度大小。
接下来的2是字体的粗细。
最后可以发现这里用到的lineType是cv2.LINE_AA型,这个类型是“使用高斯滤波平滑处理的直线”。这个线条类型用来写字看起来会有深有浅,同样画直线时可以使用这种类型来试试看。
最后一个参数bottomLeftOrigin是bool型,默认为False。当这个bool参数为True时,第三个参数的坐标便变成字体右下角的像素点而不是左上角。
现在我们将这些命令画到一张图上面
import numpy as np
import cv2
img = cv2.imread('watch.jpeg',cv2.IMREAD_COLOR)
cv2.rectangle(img,(0,200),(500,150),(0,0,255),10)
cv2.line(img,(0,0),(500,500),(0,255,0),15,8,0)
cv2.circle(img,(500,100),55,(0,255,0),-1)
pts = np.array([[100,5],[100,50],[70,200],[200,100]],np.int32)
cv2.polylines(img, [pts], True, (0,255,255), 3)
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img,'OpenCV Tuts!',(0,130), font, 1, (200,255,155), 2, cv2.LINE_AA)
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.imwrite('watchgray.png',img)
cv2.destroyAllWindows()
可以看到我们的手表变得特别丑了。
接下来我们尝试在使用摄像头录制的时候加上这些丑丑的线条。
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480),True)
font = cv2.FONT_HERSHEY_SCRIPT_COMPLEX
while(True):
ret, frame = cap.read()
cv2.putText(frame,'OpenCV!',(0,130), font, 2, (200,255,155), 2, cv2.LINE_AA)
out.write(frame)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()
通过之前的视频录制可以写出这样的程序,这里我换了一种更好看的字体。可以自己运行尝试以下。
最后吐槽ubuntu的中文输入法,一堆名词联想不出来……