一、问题背景
要使用yolo框架进行目标检测步骤如下:1、数据标注 ,生成对应的txt文档 2、对现有数据进行扩充,生成相应的txt文档 3、根据txt文档 在图片上绘制目标框 4、训练 。此文档主要解决前三个问题。
1、数据标注后生成的txt文档的格式如下:
注:第一个数字代表目标类别 第2-5个数字代表 x_center(目标框中心位置的x坐标)/原本图片的宽度, y_center(目标框中心位置的y坐标)/原本图片的高度 , width(目标框的宽度)/原本图片的宽度, height(目标框的高度)/原本图片的高度 。
yolo以及其他图片的坐标形式参考此文档
2、对现有数据扩充(对图片水平、垂直、水平垂直翻转 扩充三倍,具体见另一篇文档图片扩充
图片扩充完成之后需要生成对应的txt文档。也就是原txt文档中的第二个数字 和第三个数字需要发生变化,即目标框的中心位置。可由数学推理得出
水平翻转之后 现目标框的x=1-原目标框的x坐标 现目标框的y=原目标框y。
垂直翻转之后 现目标框的y=1-原目标框的y坐标 现目标框的x=原目标框x。
水平垂直翻转之后 现目标框的x=1-原目标框的x坐标,现目标框的y=1-原目标框的y坐标。
python代码为:(以水平垂直翻转举例,前两中稍加更改即可。
import glob
import os
import copy
from array import array
def main():
txt_path = 'E:/home/home/test/' #原txt文档
txt_out_path = 'E:/ver_mir/' #水平垂直翻转后的txt
if not os.path.exists(txt_out_path):
os.mkdir(txt_out_path)
filelist = os.listdir(txt_path)
for file in filelist:
f = open(txt_path + file, 'r') #以只读形式打开txt文档
lines = f.readlines() #按行读取
t = []
out_txt_name = os.path.splitext(file)[0] #取.txt之前
for i in lines:
line_object = i.split(' ')
#print(line_object)
line_object[1] = float(1- float(line_object[1])) #新目标框 x的值
line_object[2] = float(1-float(line_object[2]) ) #新目标框 y的值
t.append(line_object)
out_path = txt_out_path + out_txt_name + '_ver_mir.txt' #新保存入的txt文档
with open(out_path, 'w') as f:
for i in t:
str_array = " ".join(map(str, i)) #将i转为str类型,并用空格连接
print(str_array)
f.write(str_array)
if __name__ == '__main__':
main()
运行之后生成的txt文档如下:
3、根据txt文档在原图片上绘制目标框。
绘制矩形框需要用到opencv 的是rectabgle函数。
cv2.rectangle(image,(xmin,ymin),(xmax,ymax),(0,0,255),2) #image要画框的图片
#(xmin,ymin)框的左上角坐标
#(xmax,ymax)框的右下角坐标
#(0,255,255)框的颜色
#2 边框厚度
为了得到检测框的坐上以及右下的坐标,首先需要进行坐标的转换,详情见yolo坐标与普通坐标的转换具体参见这篇文章yolo坐标转换问题。为了方便我直接贴出图片。
目标转化以及绘制目标框的代码如下:
#原始图片宽为 w,高为h,bounding box(xmin,ymin,xmax,ymax)
#归一化后的图片:宽为w1,高为h1,中心点坐标为(x,y)
#由归一化到原始图片:xmin=w*(x-w1/2) xmax=w*(x+w1/2) ymin=h*(y-h1/2) ymax=h*(y+h1/2)
import os
import cv2
image_path='E:/new4' #图片路径
txt_path ='E:/home/home/test' #txt文档路径
image_out_path=r'E:\new4kuang' #绘制框之后的图片保存路径
if not os.path.exists(image_out_path):
os.mkdir(image_out_path)
list = os.listdir(image_path) #返回指定路径下文件列表
list2=os.listdir(txt_path)
#print(list)
for i in range(0,len(list)):
out_image_name = os.path.splitext(list[i])[0]
#读出原始图片的高 宽
pathimage = os.path.join(image_path, list[i])
#print(list[i])
image=cv2.imread(pathimage)
imginfo=image.shape
h=imginfo[0]
w=imginfo[1]
print(h,w)
imageNamelist='.jpg'
#print(h)
#txt文档操作
pathtxt = os.path.join(txt_path, list2[i])
#print(pathtxt)
f = open(pathtxt, 'r')
lines = f.readlines() #按行读取
for i in lines:
line_object = i.split(' ') #用空格分开
x=float(line_object[1])
y=float(line_object[2])
w1=float(line_object[3])
h1=float(line_object[4])
print(x,y,w1,h1)
#坐标系的转换
xmin=int(w*(x-(w1/2.0)))
ymin=int(h*(y-(h1/2.0)))
xmax = int(w* (x + (w1 / 2.0)))
ymax = int(h * (y + (h1 / 2.0)))
ptLeftTop =(xmin,ymin)
ptRightBottom = (xmax, ymax)
point_color=(0,255,0)
thickness = 1
lineType = 4
#cv2.rectangle(image,ptLeftTop,ptRightBottom,point_color,thickness,lineType)
#ptLeftTop =(xmin,ymin)左上角
#ptRightBottom=(xmax,ymax)右下角
#point_color=(0,255,0)绿色 (0,0,255)红色
#thickness=1
#lineType=4
if (float(line_object[0])==0):
point_color = (0, 0, 255) #蓝色
elif (float(line_object[0])==1):
point_color = (0, 255, 0) #绿色
elif (float(line_object[0])==2):
point_color = (0, 255, 255) #青色
elif (float(line_object[0])==3):
point_color = (255, 255, 0) #红色
else:
point_color = (200, 10, 10) #白色
cv2.rectangle(image, ptLeftTop,ptRightBottom, point_color,1,4)
#cv2.imshow('AlanWang', image)
#cv2.waitKey(1000) # 显示 10000 ms 即 10s 后消失
#cv2.destroyAllWindows()
path_out = os.path.join(image_out_path, out_image_name+'.jpg')
print(path_out)
cv2.imwrite(path_out,image)
效果图: