PYTHON实现机械臂运动检测

文章目录

  • 实验内容简介

  • 大致思路介绍

  • 结合代码实现算法

  • 总结与思考


一、实验内容简介

本文借鉴某学长思路,并添加上自己的理解,问题大致是,给定一段机械臂运动视频,通过边缘检测、直线检测,检测机械臂运动状况,并在图中标定出机械臂边缘与运动状态文字说明

二、大致思路介绍

将图片逐帧处理,对于每一帧图片,我们进行以下下操作:

1、确定机械臂所在矩形域

2、利用高斯平滑化进行降噪处理

3、转化为灰度图并利用Canny边缘检测进行边缘图生成

4、将不感兴趣区域(除机械臂所在区域以外的区域)涂黑

5、进行直线检测判断是否运动

可以通过建立缓存区域进行该实现优化,后文会有具体算法与实现

三、结合代码实现算法

1、获取机械臂所在区域坐标

PYTHON实现机械臂运动检测_第1张图片

先获得第一帧图片,获取图片中两点坐标(两个点确定一个矩形区域)

PYTHON实现机械臂运动检测_第2张图片PYTHON实现机械臂运动检测_第3张图片

2、利用高斯平滑进行降噪处理

代码如下

#高斯滤波
def clean_img(img):
    return cv.GaussianBlur(img,(5,5),0)

对于每一帧图片,为了使得边缘更加清晰,先对图片进行滤波处理,读者可以比较不同滤波方式的差异

3、图片添加文字

#图片添加文字, state=0:静止, state=1:运动
def addword(img,state):
    font = ImageFont.truetype("font/simsun.ttc", 32)
    img_pil = Image.fromarray(img)
    draw = ImageDraw.Draw(img_pil)
    if state == 0:
        draw.text((0, 0),  "机械臂在静止", font = font, fill = (0, 2, 255))
    else:
        draw.text((0, 0), "机械臂在晃动", font=font, fill=(0, 2, 255))
    img = np.array(img_pil)
    return img

4、将不感兴趣区域涂黑

[x1, y1] = [288, 135]
[x2, y2] = [358, 166]

#边缘图中只显示感兴趣的部分
def black(edges):
    global x1, y1, x2, y2
    wide, length = edges.shape
    edges[0:wide, 0:x1] = 0
    edges[ 0:y1, 0:length] = 0
    edges[0:wide, x2:length] = 0
    edges[y2:wide, 0:length] = 0
    return edges

 大致效果如下:

PYTHON实现机械臂运动检测_第4张图片

5、直线检测并绘制直线

#检测并绘制直线
def draw_line(img):
    img = clean_img(img)
    gray = cv.cvtColor(np.array(img), cv.COLOR_BGR2GRAY)
    edges = cv.Canny(gray, 60, 200)#转化为边缘图
    lines = cv.HoughLines(black(edges), 1, np.pi / 180, 20)
    global a, b
    for line in lines:
        rho, theta = line[0]
        x1 = int(np.cos(theta) * rho - b * (-np.sin(theta)))
        y1 = int(np.sin(theta) * rho - b * (np.cos(theta)))
        x2 = int(np.cos(theta) * rho - a * (-np.sin(theta)))
        y2 = int(np.sin(theta) * rho - a * (np.cos(theta)))
        cv.line(img, (x1, y1), (x2, y2), (0, 0, 200), 3)#在图片上绘制直线
        k = (y2-y1)/(x2-x1)
        return img, k#输出第一条直线的斜率

可以通过调整Canny算子阈值,使得边缘检测灵敏度下降,使得直线检测效果更好

PYTHON实现机械臂运动检测_第5张图片PYTHON实现机械臂运动检测_第6张图片

6、优化方案

逐帧处理会使得机械臂运动状态改变速度太快,为了使得降低改变速度,可以将逐帧处理改变为每次处理多帧信息,实现思路是建立一个缓存列表用于存储待处理的图片,伪代码如下:

1、

建立缓存数组list

2、

#IMG:需要处理的图片集合, img:其中一张图片, M:缓存数组容量

        for img in IMG:

                if len(list) < M:

                        将img添加到list

                else:

                        处理list中相关信息

                        将list中图片输出

                        清空list

                        添加img到list中

        

while True:
    ret, frame = cap.read()
    if ret:
        if len(list) < M:
            list.append(frame)
        else:

            list.append(frame)
            sum_k = 0
            count = 0
            for i in list:
                img, k = draw_line(i)
                sum_k += k
                list[count] = img
                count += 1
            avr_k = sum_k/M
            if abs(avr_k-k0) > ep:
                state = 1
            else:
                state = 0
            for i in list:
                img = addword(i, state)
                out.write(img)
                cv.namedWindow('jpg', cv.WINDOW_NORMAL)
                cv.imshow('jpg', img)
            list = []
        if cv.waitKey(1) & 0xFF == ord('q'):
            break

    else:
        break

7、完整代码

import cv2 as cv
import numpy as np
from PIL import ImageFont, ImageDraw, Image

#均值滤波
def clean_img(img):
    return cv.GaussianBlur(img,(5,5),0)

#边缘图中只显示感兴趣的部分
def black(edges):
    global x1, y1, x2, y2
    wide, length = edges.shape
    edges[0:wide, 0:x1] = 0
    edges[ 0:y1, 0:length] = 0
    edges[0:wide, x2:length] = 0
    edges[y2:wide, 0:length] = 0
    return edges

#图片添加文字, state=0:静止, state=1:运动
def addword(img,state):
    font = ImageFont.truetype("font/simsun.ttc", 32)
    img_pil = Image.fromarray(img)
    draw = ImageDraw.Draw(img_pil)
    if state == 0:
        draw.text((0, 0),  "机械臂在静止", font = font, fill = (0, 2, 255))
    else:
        draw.text((0, 0), "机械臂在晃动", font=font, fill=(0, 2, 255))
    img = np.array(img_pil)
    return img

#检测并绘制直线
def draw_line(img):
    img = clean_img(img)
    gray = cv.cvtColor(np.array(img), cv.COLOR_BGR2GRAY)
    edges = cv.Canny(gray, 60, 200)
    lines = cv.HoughLines(black(edges), 1, np.pi / 180, 20)
    global a, b
    for line in lines:
        rho, theta = line[0]
        x1 = int(np.cos(theta) * rho - b * (-np.sin(theta)))
        y1 = int(np.sin(theta) * rho - b * (np.cos(theta)))
        x2 = int(np.cos(theta) * rho - a * (-np.sin(theta)))
        y2 = int(np.sin(theta) * rho - a * (np.cos(theta)))
        cv.line(img, (x1, y1), (x2, y2), (0, 0, 200), 3)
        k = (y2-y1)/(x2-x1)
        return img, k






cap = cv.VideoCapture('D:/computer_view_exercise1/flapping_demo_video.avi')
[x1, y1] = [288, 135]
[x2, y2] = [358, 166]
b = 300
a = 375
k0 = (y2-y1)/(x2-x1)#初始斜率
ep = 0.05#判断是否运动的斜率阈值
count = 0#计数器
state = 0#运动标志变量

fourcc = cv.VideoWriter_fourcc(*'XVID')
fps = cap.get(cv.CAP_PROP_FPS)
# 设置视频大小
size = (int(cap.get(cv.CAP_PROP_FRAME_WIDTH)),int(cap.get(cv.CAP_PROP_FRAME_HEIGHT)))
out = cv.VideoWriter('D:/computer_view_exercise1/out.avi',fourcc ,fps, size)
k = k0
list = []
M = 12#缓存最多图片张数

while True:
    ret, frame = cap.read()
    if ret:
        if len(list) < M:
            list.append(frame)
        else:

            list.append(frame)
            sum_k = 0
            count = 0
            for i in list:
                img, k = draw_line(i)
                sum_k += k
                list[count] = img
                count += 1
            avr_k = sum_k/M
            if abs(avr_k-k0) > ep:
                state = 1
            else:
                state = 0
            for i in list:
                img = addword(i, state)
                out.write(img)
                cv.namedWindow('jpg', cv.WINDOW_NORMAL)
                cv.imshow('jpg', img)
            list = []
        if cv.waitKey(1) & 0xFF == ord('q'):
            break

    else:
        break

sum_k = 0
count = 0
for i in list:
    img, k = draw_line(i)
    sum_k += k
    list[count] = img
    count += 1
    avr_k = sum_k/M
if abs(avr_k-k0) > ep:
    state = 1
else:
    state = 0
for i in list:
    img = addword(i, state)
    out.write(img)
    cv.namedWindow('jpg', cv.WINDOW_NORMAL)
    cv.imshow('jpg', img)
list = []

cap.release()
out.release()
cv.destroyAllWindows()

总结

本实验遇到最大问题就是检测到的直线乱飞,进行思考发现原因是:转化为边缘图片后,发现除了要检测的目标(机械臂)外,还存在另外的边缘,因此我们采取滤波降噪处理,检测效果略好一些,但仍就不如意,我进行了将Canny算子替换成Sobel算子,企图降低边缘检测灵敏度,但Sobel算子也存在问题,会使得边缘不明显,因此我们通过改变Canny检测阈值,降低边缘检测灵敏度,取得不错效果

你可能感兴趣的:(python,计算机视觉)