欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

python实现Nao机器人的单目测距

程序员文章站 2022-06-25 09:34:22
本文实例为大家分享了python实现nao机器人单目测距的具体代码,供大家参考,具体内容如下此代码适于用做对nao机器人做视觉识别和测距实验,只提供关键代码部分,尝试利用cv2去优化代码会更加简洁哟!...

 本文实例为大家分享了python实现nao机器人单目测距的具体代码,供大家参考,具体内容如下

此代码适于用做对nao机器人做视觉识别和测距实验,只提供关键代码部分,尝试利用cv2去优化代码会更加简洁哟!

此代码的主要功能:

1.初始姿态下,通过更换摄像头和转头去寻找目标
2.通过颜色阈值识别目标,计算目标与nao的距离和角度

可以扩展功能:

1.在运动过程中对方向和距离进行多次测量和校正,提高准确度
2.找到目标后,通过对目标的测量,选择使用哪个脚去踢目标

#!/usr/bin/python2.7
#-*- encoding: utf-8 -*-
import vision_definitions
#----------------------单目测距--------------------------------
#***********************************************
#@函数名:   distanddirect_cal(cxnum,rynum,colsum,rowsum,head_angle,cameraid)
#@参数:     (cxnum,rynum)是通过图像识别得到球心的像素点坐标
#           (colsum,rowsum)是图片总大小:640*480
#            cameraid=0,取上摄像头;cameraid=1,取下摄像头
#@返回值:   无
#@功能说明: 采用机器人的下摄像头进行测量球离机器人的相关角度与距离
def distanddirect_cal(cxnum,rynum,colsum,rowsum,head_angle,cameraid):
    distx=-(cxnum-colsum/2)
    disty=rynum-rowsu/2
    print distx,disty
    picture_angle=disty*47.64/480

    if cameraid ==0:
        h=0.62
        camera_angle=12
    else:
        h=0.57
        camera_angle=38
    #head_angle[0]机器人仰俯角度
    total_angle=math.pi*(picture_angle+camera_angle)/180+head_angle[0]
    d1=h/math.tan(total_angle)

    alpha=math.pi*(distx*60.92/640)/180
    d2=d1/math.cos(alpha)
    #head_angle[1]机器人左右角度
    forward_distance=d2*math.cos(alpha+head_angle[1])
    sideward_distance=-d2*math.sin(alpha+head_angle[1])
#***********************************************

#@函数名:   getnaoimage(ip,port,cameraid)
#@参数:     略
#@返回值:   无
#@功能说明: 采调用机器人内置摄像头控制模块,对当前场景进行拍摄并保持。
#           由于球距离机器人约小于0.6m时,机器人额头摄像头无法看到,
#           所以需要变换摄像头,cameraid=0,取上摄像头;
#           cameraid=1,取下摄像头
def get naoimage(ip,port,cameraid):
    camproxy=alproxy("alvideodevice",ip,port)
    resolition=2 #vga格式640*480
    colorspace=11#rgb

    #选择并启用摄像头
    camproxy.setparam(vision_definitions.kcameraselectid,cameraid)
    videoclient=camproxy.subscribe("python_client",resolition,colorspace,5)

    #获取摄像机图像。
    #image [6]包含以ascii字符数组形式传递的图像数据。
    naoimage=camproxy.getimageremote(videoclient)

    camproxy.unsubscribe(videoclient)
    #获取图像大小和像素阵列。
    imagewidth=naoimage[0]
    imageheight=naoimage[1]
    array=naoimage[6]
    #从我们的像素阵列创建一个pil图像。
    im=image.fromstring("rgb",(imagewidth,imageheight),array)
    #保存图像。
    im.save("temp.jpg","jpeg")

#***********************************************
#@函数名:   findcolorpattern(img,pattern)
#@参数:     略
#@返回值:   无
#@功能说明:  将rgb图像转化为二值图:此方法用的是cv,可以尝试用cv2代码会更加简洁
def  findcolorpattern(img,pattern):
    channels=[none,none,none]
    channels[0]=cv.createimage(cv.getsize(img),8,1)
    channels[1]=cv.createimage(cv.getsize(img),8,1)
    channels[2]=cv.createimage(cv.getsize(img),8,1)
    ch0=cv.createimage(cv.getsize(img),8,1)
    ch1=cv.createimage(cv.getsize(img),8,1)
    ch2=cv.createimage(cv.getsize(img),8,1)
    cv.split(img,ch0,ch1,ch2,none)
    dest=[none,none,none,none]
    dest[0]=cv.createimage(cv.getsize(img),8,1)
    dest[1]=cv.createimage(cv.getsize(img),8,1)
    dest[2]=cv.createimage(cv.getsize(img),8,1)
    dest[3]=cv.createimage(cv.getsize(img),8,1)
    cv.smooth(ch0,channels[0],cv.cv_gaussian,3,3,0)
    cv.smooth(ch1,channels[1],cv.cv_gaussian,3,3,0)
    cv.smooth(ch2,channels[2],cv.cv_gaussian,3,3,0)
    for i in range(3):
        k=2-i
        lower=pattern[k]-75#设置阈值
        upper=pattern[k]+75
        cv.inranges(channels[i],lower,upper,dest[i])

    cv.and(dest[0],dest[1],dest[3])
    temp=cv.createimage(cv.getsize(img),8,1)
    cv.and(dest[2],dest[3],temp)
    '''
    cv.namewindow("result",cv.cv_window_autosize)
    cv.showimage("result",temp)
    cv.waitkey(0)
    '''
    return temp

#***********************************************
#@函数名:   xyproject(matrix,imgaesize)
#@参数:     matrix
#           imgaesize
#@返回值:   无
#@功能说明: 利用二值图,计算球的像素坐标。其原理是:遍历各行各列
#           像素的数值的和,最大的组合即为球心坐标
def xyproject(matrix,imagesize):
    #声明一个数据类型为8位型单通道的imagessize[1]*1/1*imagessize[0]矩阵(初始值为 0)。
    colmask=cv.createmat(imagessize[1],1,cv.cv_8uc1)
    rowmask=cv.createmat(1,imagessize[0],cv.cv_8uc1)
    cv.set(colmask,1)
    cv.set(rowmask,1)

    colsum=[]
    for i in range(imagesize[0]):
        col=cv.getcol(matrix,i)
        #计算向量点积
        a=cv.dotproduct(colmask,col)
        colsum.append(a)

    rowsum=[]
    for i in range(imagesize[1]):
        row=cv.getrow(matrix,i)
        a=cv.dotproduct(rowmask,row)
        rowsum.append(a)

    return(colsum,rowsum)#得到各行各列“1”值的和

def crmax(colsum,rowsum):
    cx=max(colsum)
    ry=max(rowsum)
    for i in range(len(colsum)):
        if colsum[i]==cx:
            cxnum=i
    for i in range(len(rowsum)):
        if rowsum[i]==ry:
            rynum=i
    return(cxnum,rynum)
#***********************************************
#@函数名:  getheadangles(robotip,port)
#@参数:    略
#@返回值:   无
#@功能说明:
def getheadangles(robotip,port):
    motionproxy=alproxy("almotion",robotip,port)
    names=["headpitch","headyaw"]
    usesensors=1
    sensorangles=motionproxy.getangles(names,usesensors)
    return sensorangles
#***********************************************
#@函数名:  setheadangles(robotip,port,angles)
#@参数:    略
#@返回值:   无
#@功能说明:
def setheadangles(robotip,port,angles):
    motionproxy=alproxy("almotion",robotip,port)
    motionproxy.setstiffnesses("head",1.0)

    names=["headpitch","headyaw"]
    fractionmaxspeed=0.2
    motionproxy.setangles(names,angles,fractionmaxspeed)

    time.sleep(2.0)
    motionproxy.setstiffnesses("head",0.0)

#***********************************************
#@函数名:   capture_picture(ip,port,cameraid,angles,pattern_colors)
#@参数:     angles
#           pattern_colors
#@返回值:   无
#@功能说明: 将上面的一系列函数整合起来

def capture_picture(ip,port,cameraid,angles,pattern_colors):
    setheadangles(ip,port,angles)
    getnaoimage(ip,port,cameraid)
    image=cv.loadimage("temp.jpg")
    imagesize=cv.getsize(image) #返回数值,两个元素分别为列数和行数
    matrix=findcolorpattern(image,pattern_colors)
    (colsum,rowsum)=xyproject(matrix,imagesize)
    (cxnum,rynum)=crmax(colsum,rowsum)
    cv.saveimage("result.jpg",matrix)

    return (cxnum,rynum,colsum,rowsum)

 

#***********************************************
#@函数名:   target_detect_and_distance(ip,port)
#@参数:
#@返回值:   无
#@功能说明: 当上摄像头无法找到球时,切换到下摄像头,然后在左转右转。
#       在这个过程中,如果发现目标,则计算距离并输出距离
#       若始终未找到目标,则输出距离为0。

def target_detect_and_distance(ip,port):
    pattern_colors=(255,150,50)
    cameraid=0# 默认上摄像头
    angles=[0,0]
    (cxnum,rynum,colsum,rowsum)=capture_picture(ip,port,cameraid,angles)

    if(cxnum,rynum)==(639,479):
        cameraid=1
        (cxnum,rynum,colsum,rowsum)=capture_picture(ip,port,cameraid,angles)
    if(cxnum,rynum)==(639,479):
        cameraid=0
        angles=[0.0.7]
        (cxnum,rynum,colsum,rowsum)=capture_picture(ip,port,cameraid,angles)
    if(cxnum,rynum)==(639,479):
        cameraid=0
        angles=[0,-0.7]
        (cxnum,rynum,colsum,rowsum)=capture_picture(ip,port,cameraid,angles)
    headangles-getheadangles(ip,port)
    ###############
    (forward_distance,sideward_distance)=distanddirect_cal(cxnum,rynum,colsum,rowsum,head_angle,cameraid)
    if(cxnum,rynum)==(639,479):
        (forward_distance,sideward_distance)=(0,0)
    print "forward_distance=",forward_distance,"meters"
    print "sideward_distance="+sideward_distance+"meters"

#***********************************************
#@函数名:   target_detect_and_distance(ip,port)
#@参数:
#@返回值:   无
#@功能说明: 当找到球后,可能会存在一定的误差。
#           因此需要判断球位于机器人前方的哪一侧,再来确定用哪只脚踢球

def final_see(robotip,port):
    pattern_colors=(255,150,50)
    angles=[0.5,0]
    setheadangles(robotip,port,angles)

    cameraid=1

    getnaoimage(robotip,port,cameraid)
    image=cv.loadimage("temp.jpg")
    imagesize=cv.getnaoimage(image)

    matrix=findcolorpattern(image,pattern_colors)

    (colsum,rowsum)=xyproject(matrix,imgaesize)
    (cxnum,rynum)=crmax(colsum,rowsum)
    cv.saveimage("result.jpg",matrix)

    headangles=getheadangles(robotip,port)
    #########################
    (forward_distance,sideward_distance)=distanddirect_cal(cxnum,rynum,colsum,rowsum,head_angle,cameraid)

    if cxnum<len(colsum)/2:
        side=0#左脚
    else:
        side=1#右脚
    print "side=",side
    print "last distance=",forward_distance
    return (side,forward_distance)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。