一、环境搭建

环境搭建推荐肆十二的文章:手把手教你使用YOLOV5训练自己的目标检测模型-口罩检测-视频教程
里面有关YOLO v5前期的环境搭建讲解十分详细,且与本项目的YOLO v5前期环境搭建大差不差,这里不再赘述。

二、编码标记物数据集

编码标记物数据集采用labelimg手动标注的方法,详细数据集见:环形编码标记物数据集
编码标记物及相关数据集(部分)展示如下图:
编码标记物智能识别系统(YOLO v5+Opencv实现)-LMLPHP
编码标记物智能识别系统(YOLO v5+Opencv实现)-LMLPHP

三、编码标记物识别

通过YOLO v5网络实现编码标记物的智能识别与定位,即通过训练后的网络实现对编码标记物的识别,训练好的模型详见:best与last模型
识别结果如图所示,可见即使是对小而密集的编码标记物也有较好的识别效果:
编码标记物智能识别系统(YOLO v5+Opencv实现)-LMLPHP

四、编码标记物的解码

在完成了编码标记物的定位与识别之后,再需要在预测框图片的基础上完成编码标记物的解码工作,这里采用Opencv的辅助方法。

1. 循环识别图像获得码值

def getcode():
    debug=True
    img = cv2.imread('./images/tmp/test/tmp_upload.png') #图片路径
    gray_all=img
    contours_all=[]
    contours_circle=[]
    hierarchy_all=[]
    gray_all = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    #gray_all=cv2.GaussianBlur(gray_all,)
    ret,binary=cv2.threshold(gray_all,100,255,cv2.THRESH_BINARY)
    gray_show=binary
    # 使用findcontours函数对二值化后的图像进行轮廓提取,第三个参数为轮廓点的存储方式,这里选返回所有轮廓点,方便后面做筛选
    contours_all,hierarchy_all= cv2.findContours(binary,cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
    vec_center=[]
    vec_radius=[]
    vec_rrect=[]
    #连续采样,计算码值,预设三个扫描起点,进行顺时针扫描,若三个扫描值相同,即为初步码值。
    for i in range(0,len(contours_all)):
        (x, y), radius = cv2.minEnclosingCircle(contours_all[i])
        center = (int(x), int(y))
        radius = int(radius)+0.0000001
        contorarea=cv2.contourArea(contours_all[i])
        ratiol=contorarea/(3.1415*radius*radius)
        if (ratiol>0.9) and len(contours_all[i])>50:
            contours_circle.append(contours_all[i])
            vec_center.append(center)
            vec_radius.append(radius)
        if len(contours_all[i])>50:
            fitelliprect=cv2.fitEllipse(contours_all[i])
            (fitelliprectw,fitelliprecth)=fitelliprect[1]
            minarearect=cv2.minAreaRect(contours_all[i])
            (minarearectw,minarearecth)=minarearect[1]
            fitrectarea=fitelliprectw*fitelliprecth
            minarea=minarearectw*minarearecth
            radio2=fitrectarea/minarea
            if radio2>0.95 and radio2<1.05:
                vec_rrect.append(fitelliprect)


    for i in range(0,len(vec_center)):
        rect=gray_show[int(vec_center[i][1] - 3 * vec_radius[i]):int(vec_center[i][1] + 3 * vec_radius[i]),
                int(vec_center[i][0] - 3 * vec_radius[i]):int(vec_center[i][0] + 3 * vec_radius[i]) ]
        t=rect
        codenew=0
        for scanpoint in range(0,3):
            code=0
            for range0 in range(0,8):
                count=0
                starpoint=range0*45+scanpoint*15
                endpoint=(range0+1)*45+scanpoint*15
                angle=starpoint
                while angle<endpoint:
                    pointx=3*vec_radius[i]+(vec_radius[i] / 150 * 350) * math.cos(angle / 180.0 * 3.1415)
                    pointy=3*vec_radius[i] + (vec_radius[i] / 150 * 350) * math.sin(angle / 180.0 * 3.1415)
                    x=(t[int(pointx)][int(pointy)])
                    if x==255:
                        count=count+1
                    angle=angle+3
                if count<=8:
                    code=code+math.pow(2,range0)
            codenew=findmincode(int(code))
        print(codenew)
    if debug:
        title=str(codenew)
        cv2.imshow(title,t)
        cv2.waitKey(0)

2. 码值后处理

因为环形编码标记物并没有固定起点,所以要对得到的码值进行循环移位以得到最小码值,即为最后的结果码值。

#码值选择函数(找到最小码值)
def findmincode(code):
    minresult=255
    for i in range(1,8):
        left=circular_shift_left(code,i,8)
        right=circular_shift_right(code,i,8)
        result=min(left,right)
        if(result<minresult):
            minresult=result
    return minresult

#辅助码值选择函数(左移位函数)
# int_value是输入的整数,k是位移的位数,bit是整数对应二进制的位数
def circular_shift_left(int_value, k, bit=8):
    bit_string = '{:0%db}' % bit
    bin_value = bit_string.format(int_value)  # 8 bit binary
    bin_value = bin_value[k:] + bin_value[:k]
    int_value = int(bin_value, 2)
    return int_value

#辅助码值选择函数(右移位函数)
# right circular shift
def circular_shift_right(int_value, k, bit=8):
    bit_string = '{:0%db}' % bit
    bin_value = bit_string.format(int_value)  # 8 bit binary
    bin_value = bin_value[-k:] + bin_value[:-k]
    int_value = int(bin_value, 2)
    return int_value
07-06 09:22