这是我们小学升初中的一道考试题,题目要求如下:
题目给了我们一个视频,要求我们通过计算机视觉基元检测的方式,判断上面视频中画圈的这根机械臂是否在晃动。因为是小升初题目,所以我尽可能用简单的方式来解决这个问题。
我的思路是,将视频按帧提取出来,对每一帧图片,我们可以将目标机械臂的大体范围划分出来,然后可以使用一个直线检测函数HoughLines确定机械臂边缘位置,从而可以计算得到每一时刻机械臂的斜率,将每一帧中机械臂的斜率与前一帧的斜率比较,如果斜率改变超过某一阈值,我们就可以认定为机械臂在晃动,我们将警报信息标在该帧图片上,然后再进行输出播放。
在这个程序中,数据处理量较小,所以我们可以选择实时播放,如果处理信息较多,实时播放会比较卡,就可以选择将处理后的每一帧保存下来,最后重组为视频进行播放。另外,我们也可以选择不对每一帧都作处理和判断,可以选择每隔多少帧处理一次。
下面是我实现的代码,运行中可以通过敲击键盘“q”然后回车,手动停止播放。
# -*- coding: utf-8 -*-
"""
Created on Fri Nov 12 22:16:22 2021
@author: 2540817538(有问题请联系此QQ)
python3.8.8
"""
import cv2 as cv
import numpy as np
from PIL import ImageFont, ImageDraw, Image
def add(img):#在图片上添加文字
font = ImageFont.truetype("font/simsun.ttc", 32)
img_pil = Image.fromarray(img)
draw = ImageDraw.Draw(img_pil)
draw.text((1200, 800), "机械臂在晃动", font = font, fill = (0, 0, 255))
bk_img = np.array(img_pil)
return bk_img
def HoughLine_s(img):#通过直线检测函数检测出图中的直线,并给出直线的坐标和斜率
gray = cv.cvtColor(np.array(img), cv.COLOR_BGR2GRAY)
lines = cv.HoughLines(black(cv.Canny(gray, 10, 200)), 1, np.pi/180, 100)
for line in lines:
rho, theta = line[0]
x1 = int(np.cos(theta)*rho -480 * (-np.sin(theta)))
y1 = int( np.sin(theta)*rho- 480 * (np.cos(theta)))
x2 = int(np.cos(theta)*rho - 800 * (-np.sin(theta)))
y2 = int( np.sin(theta)*rho - 800 * (np.cos(theta)))
cv.line(img, (x1, y1), (x2, y2), (2, 200, 200), 7)
k=(y2-y1)/(x2-x1)
return img,k,x1,x2,y1,y2
def black(edges):#处理边缘图,使目标区域以外区域全部为黑色
#这一部分主要是划分出机械臂所在的那一小部分区域,方便直线检测函数处理
#像素点坐标的获取方式可以参考我的另一篇水文《python获取图像中像素点坐标》
edges[0:1080, 0:1370]=edges[0:720, 0:1920]=edges[0:840, 0:1440]=edges[0:800, 0:1470]= edges[0:820, 0:1460]=edges[0:1080, 1600:1920]=edges[890:1080, 0:1920]=edges[0:825, 0:1460]=edges[0:820, 0:1460]=0
return edges
def main():
k1=(852+406)/(-596-957)#y原始斜率
cap = cv.VideoCapture('C:/Users/25408/Desktop/sp2.mp4') # 参数表示获取视频
while True:
success,frame = cap.read()# 读取视频流
if success:#这里是对每一帧都进行判断,可以根据实际修改
hough_s,k,x1,x2,y1,y2 = HoughLine_s(frame)
if(k!=k1):
frame=add(hough_s)
cv.line(frame, (x1, y1), (x2, y2), (0, 0, 256), 7)
k1=k
cv.namedWindow('asd', cv.WINDOW_NORMAL)
cv.imshow('asd', frame)
key = cv.waitKey(5) & 0xFF
if key == ord('q'):
print ('手动停止')
break
else:
print ('播放完成')
break
cap.release()
cv.destroyAllWindows()
if __name__=="__main__":
main()
运行效果如下:
我使用的视频如下,大家可以下载用来测试代码,记得更改代码中的路径。
链接:https://pan.baidu.com/s/1yUuUcjQEWTkwDYMKFqRvvA
提取码:rgdk