本文只讨论目标检测。
VOC数据集
VOC数据集由五个部分构成:JPEGImages,Annotations,ImageSets,SegmentationClass以及SegmentationObject.
- JPEGImages:存放的是训练与测试的所有图片。
- Annotations:里面存放的是每张图片打完标签所对应的XML文件
- ImageSets:ImageSets文件夹下本次讨论的只有Main文件夹,此文件夹中存放的主要又有四个文本文件test.txt,train.txt,trainval.txt,val.txt,其中分别存放的是测试集图片的文件名、训练集图片的文件名、训练验证集图片的文件名、验证集图片的文件名。
- SegmentationClass与SegmentationObject:存放的都是图片,且都是图像分割结果图,对目标检测任务来说没有用。class segmentation 标注出每一个像素的类别 。object segmentation 标注出每一个像素属于哪一个物体。
XML标注格式
<annotation>
<folder>17</folder> # 图片所处文件夹
<filename>77258.bmp</filename> # 图片名
<path>~/frcnn-image/61/ADAS/image/frcnn-image/17/77258.bmp</path>
<source> #图片来源相关信息
<database>Unknown</database>
</source>
<size> #图片尺寸
<width>640</width>
<height>480</height>
<depth>3</depth>
</size>
<segmented>0</segmented> #是否有分割label
<object> 包含的物体
<name>car</name> #物体类别
<pose>Unspecified</pose> #物体的姿态
<truncated>0</truncated> #物体是否被部分遮挡(>15%)
<difficult>0</difficult> #是否为难以辨识的物体, 主要指要结体背景才能判断出类别的物体。虽有标注, 但一般忽略这类物体
<bndbox> #物体的bound box
<xmin>2</xmin>
<ymin>156</ymin>
<xmax>111</xmax>
<ymax>259</ymax>
</bndbox>
</object>
</annotation>
重点注意:bounding box是由xmin,ymin,xmax,ymax定义的。start from 1.
转换成VOC标注格式所需信息:
- 图片名
- 图片中包函的物体框以及对应的物体类别。
转成VOC的代码:
import os
import parser
import csv
import cv2
from lxml.etree import Element, SubElement, tostring
from xml.dom.minidom import parseString
import shutil
def check_make_dir(path):
if not os.path.exists(path):
os.makedirs(path)
def make_voc_dir(root):
check_make_dir(os.path.join(root, 'VOC2007/ImageSets'))
check_make_dir(os.path.join(root, 'VOC2007/ImageSets/Main'))
check_make_dir(os.path.join(root, 'VOC2007/JPEGImages'))
check_make_dir(os.path.join(root, 'VOC2007/Annotations'))
if __name__ == "__main__":
ROOT = "/PATH/TO/YOUR/GENERATED/DATASET/"
img_path = "/IMAGE/SOURCE/DIR/"
make_voc_dir(ROOT)
# create two dict, use file names as keys.
obj_label = {}
obj_name = {}
FOR ALL IMAGE:
FOR ALL BOX:
obj_name[f'{i}.jpg'].append(single_label['label'])
obj_label[f'{i}.jpg'].append({'xmin': min(geo[0], geo[2]), 'ymin': min(geo[1], geo[3]),
'xmax': max(geo[0], geo[2]), 'ymax': max(geo[1], geo[3])})
for img_file in obj_label:
image_path = os.path.join(img_path, img_file)
img = cv2.imread(image_path)
# print(img_path)
height, width, channel = img.shape
new_img_path = os.path.join(ROOT, 'VOC2007/JPEGImages')
shutil.copy(ima除了ge_path, os.path.join(new_img_path, img_file))
node_root = Element('annotation')
node_folder = SubElement(node_root, 'folder')
node_folder.text = 'JPEGImages'
node_filename = SubElement(node_root, 'filename')
node_filename.text = os.path.basename(image_path)
node_size = SubElement(node_root, 'size')
node_width = SubElement(node_size, 'width')
node_width.text = '%s' % width
node_height = SubElement(node_size, 'height')
node_height.text = '%s' % height
node_depth = SubElement(node_size, 'depth')
node_depth.text = '%s' % channel
for class_name, obj in zip(obj_name[img_file], obj_label[img_file]):
xmin, ymin, xmax, ymax = obj['xmin'], obj['ymin'], obj['xmax'], obj['ymax']
node_object = SubElement(node_root, 'object')
node_name = SubElement(node_object, 'name')
node_name.text = class_name
node_difficult = SubElement(node_object, 'difficult')
node_difficult.text = '0'
node_bndbox = SubElement(node_object, 'bndbox')
node_xmin = SubElement(node_bndbox, 'xmin')
node_xmin.text = '%s' % xmin
node_ymin = SubElement(node_bndbox, 'ymin')
node_ymin.text = '%s' % ymin
node_xmax = SubElement(node_bndbox, 'xmax')
node_xmax.text = '%s' % xmax
node_ymax = SubElement(node_bndbox, 'ymax')
node_ymax.text = '%s' % ymax
node_name = SubElement(node_object, 'pose')
node_name.text = 'Unspecified'
node_name = SubElement(node_object, 'truncated')
node_name.text = '0'
xml = tostring(node_root, pretty_print=True) # 'annotation'
dom = parseString(xml)
# save_dir = 'VOC2007/Annotations'
xml_name = img_file.replace('.jpg', '.xml')
xml_path = ROOT + 'VOC2007/Annotations/' + xml_name
with open(xml_path, 'wb') as f:
f.write(xml)
separate data:
import os
import random
trainval_percent = 0.8
train_percent = 0.7
xmlfilepath = '/PATH/TO/VOC2007/Annotations'
txtsavepath = '/PATH/TO/VOC2007/ImageSets/Main'
total_xml = os.listdir(xmlfilepath)
num=len(total_xml)
list=range(num)
tv=int(num*trainval_percent)
tr=int(tv*train_percent)
trainval= random.sample(list,tv)
train=random.sample(trainval,tr)
ftrainval = open(txtsavepath+'/trainval.txt', 'w')
ftest = open(txtsavepath+'/test.txt', 'w')
ftrain = open(txtsavepath+'/train.txt', 'w')
fval = open(txtsavepath+'/val.txt', 'w')
for i in list:
name=total_xml[i][:-4]+'n'
if i in trainval:
ftrainval.write(name)
if i in train:
ftrain.write(name)
else:
fval.write(name)
else:
ftest.write(name)
ftrainval.close()
ftrain.close()
fval.close()
ftest .close()
CHECK VOC:
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
import cv2
import matplotlib.pyplot as plt
from math import sqrt as sqrt
# 需要检查的数据
sets=[('2007', 'train'), ('2007', 'val')]
# 需要检查的类别
classes = ['TAG','PROMOTION']
if __name__ == '__main__':
# GT框宽高统计
width = []
height = []
for year, image_set in sets:
# 图片ID不带后缀
image_ids = open('VOC%s/ImageSets/Main/%s.txt'%(year, image_set)).read().strip().split()
for image_id in image_ids:
# 图片的路径
img_path = 'VOC%s/JPEGImages/%s.jpg'%(year, image_id)
# 这张图片的XML标注路径
label_file = open('VOC%s/Annotations/%s.xml' % (year, image_id))
tree = ET.parse(label_file)
root = tree.getroot()
size = root.find('size')
img_w = int(size.find('width').text)
img_h = int(size.find('height').text)
img = cv2.imread(img_path)
for obj in root.iter('object'):
difficult = obj.find('difficult').text
cls = obj.find('name').text
if cls not in classes or int(difficult) == 2:
continue
cls_id = classes.index(cls)
xmlbox = obj.find('bndbox')
xmin = int(xmlbox.find('xmin').text)
ymin = int(xmlbox.find('ymin').text)
xmax = int(xmlbox.find('xmax').text)
ymax = int(xmlbox.find('ymax').text)
w = xmax - xmin
h = ymax - ymin
# width.append(w)
# height.append(h)
img = cv2.rectangle(img, (int(xmin), int(ymin)), (int(xmax), int(ymax)), (0, 255, 0), 8)
w_change = (w / img_w) * 416
h_change = (h / img_h) * 416
# width.append(w_change)
# height.append(h_change)
s = w_change * h_change
width.append(sqrt(s))
height.append(w_change / h_change)
print(img_path)
img = cv2.resize(img, (608, 608))
cv2.imshow('result', img)
cv2.waitKey()
plt.plot(width, height, 'ro')
plt.show()
除了代码部分的介绍选自:
Pascal Voc 数据集格式解释www.jianshu.comCOCO数据集
Gemfield:COCO数据集的标注格式zhuanlan.zhihu.com从voc到coco
generate xml list
import xml.etree.ElementTree as ET
import os
import json
import shutil
def check_make_dir(path):
if not os.path.exists(path):
os.makedirs(path)
def make_coco_dir(root):
check_make_dir(os.path.join(root, 'Annotations'))
check_make_dir(os.path.join(root, 'Annotations_xml'))
check_make_dir(os.path.join(root, 'Annotations_xml'))
check_make_dir(os.path.join(root, 'Annotations_xml'))
check_make_dir(os.path.join(root, 'Annotations_xml'))
check_make_dir(os.path.join(root, 'Annotations_xml'))
check_make_dir(os.path.join(root, 'xml_list'))
check_make_dir(os.path.join(root, 'images'))
# check_make_dir(os.path.join(root, 'VOC2007/Annotations'))
if __name__ == '__main__':
ROOT = "/PATH/TO/VOC2007/"
img_dir = os.path.join(ROOT, "JPEGImages")
xml_dir = os.path.join(ROOT, "Annotations")
division_dir = os.path.join(ROOT, "ImageSets/Main")
#
target_dir = "/PATH/TO/COCO"
make_coco_dir(target_dir)
file_list = ['test.txt', 'trainval.txt', 'train.txt', 'val.txt']
# 'train.txt', 'val.txt'
for file_name in file_list:
path = os.path.join(division_dir, file_name)
# divide xml into different set: train, test, val
file = open(path)
for line in file.readlines():
line = line[:-1]
img_path = os.path.join(img_dir, line+'.jpg')
target_path = os.path.join(target_dir, 'images', file_name[:-4], line+'.jpg')
# shutil.copy(img_path, target_path)
# shutil.copy(os.path.join(xml_dir, line+'.xml'), os.path.join(target_dir, 'Annotations_xml', 'xml_' + file_name[:-4], line+'.xml'))
shutil.copy(os.path.join(xml_dir, line + '.xml'), os.path.join(target_dir, 'Annotations_xml', line+'.xml'))
#!/usr/bin/python
# pip install lxml
import sys
import os
import json
import xml.etree.ElementTree as ET
import shutil
START_BOUNDING_BOX_ID = 1
PRE_DEFINE_CATEGORIES = {}
# If necessary, pre-define category and its id
# PRE_DEFINE_CATEGORIES = {"aeroplane": 1, "bicycle": 2, "bird": 3, "boat": 4,
# "bottle":5, "bus": 6, "car": 7, "cat": 8, "chair": 9,
# "cow": 10, "diningtable": 11, "dog": 12, "horse": 13,
# "motorbike": 14, "person": 15, "pottedplant": 16,
# "sheep": 17, "sofa": 18, "train": 19, "tvmonitor": 20}
PRE_DEFINE_CATEGORIES = {"TAG": 1, "PROMOTION": 2}
def get(root, name):
vars = root.findall(name)
return vars
def get_and_check(root, name, length):
vars = root.findall(name)
if len(vars) == 0:
raise NotImplementedError('Can not find %s in %s.'%(name, root.tag))
if length > 0 and len(vars) != length:
raise NotImplementedError('The size of %s is supposed to be %d, but is %d.'%(name, length, len(vars)))
if length == 1:
vars = vars[0]
return vars
def get_filename_as_int(filename):
try:
filename = os.path.splitext(filename)[0]
return int(filename)
except:
raise NotImplementedError('Filename %s is supposed to be an integer.'%(filename))
def convert(xml_list, xml_dir, json_file):
list_fp = open(xml_list, 'r')
json_dict = {"images":[], "type": "instances", "annotations": [],
"categories": []}
categories = PRE_DEFINE_CATEGORIES
bnd_id = START_BOUNDING_BOX_ID
for line in list_fp:
line = line.strip()
print("Processing %s"%(line))
xml_f = os.path.join(xml_dir, line)
tree = ET.parse(xml_f)
root = tree.getroot()
path = get(root, 'path')
if len(path) == 1:
filename = os.path.basename(path[0].text)
elif len(path) == 0:
filename = get_and_check(root, 'filename', 1).text
else:
raise NotImplementedError('%d paths found in %s'%(len(path), line))
## The filename must be a number
image_id = get_filename_as_int(filename)
size = get_and_check(root, 'size', 1)
width = int(get_and_check(size, 'width', 1).text)
height = int(get_and_check(size, 'height', 1).text)
image = {'file_name': filename, 'height': height, 'width': width,
'id':image_id}
json_dict['images'].append(image)
## Cruuently we do not support segmentation
# segmented = get_and_check(root, 'segmented', 1).text
# assert segmented == '0'
for obj in get(root, 'object'):
category = get_and_check(obj, 'name', 1).text
if category not in categories:
new_id = len(categories)
categories[category] = new_id
category_id = categories[category]
bndbox = get_and_check(obj, 'bndbox', 1)
xmin = int(get_and_check(bndbox, 'xmin', 1).text) - 1
ymin = int(get_and_check(bndbox, 'ymin', 1).text) - 1
xmax = int(get_and_check(bndbox, 'xmax', 1).text)
ymax = int(get_and_check(bndbox, 'ymax', 1).text)
assert(xmax > xmin)
assert(ymax > ymin)
o_width = abs(xmax - xmin)
o_height = abs(ymax - ymin)
ann = {'area': o_width*o_height, 'iscrowd': 0, 'image_id':
image_id, 'bbox':[xmin, ymin, o_width, o_height],
'category_id': category_id, 'id': bnd_id, 'ignore': 0,
'segmentation': []}
json_dict['annotations'].append(ann)
bnd_id = bnd_id + 1
for cate, cid in categories.items():
cat = {'supercategory': 'none', 'id': cid, 'name': cate}
json_dict['categories'].append(cat)
json_fp = open(json_file, 'w')
json_str = json.dumps(json_dict)
json_fp.write(json_str)
json_fp.close()
list_fp.close()
def generate_xml_txt(src_dir, dst_dir):
file = open(src_dir,'r')
xml_file = open(dst_dir, 'w')
for line in file.readlines():
xml_file.write(line[:-1] + '.xml'+'n')
def get_img(src, dst, txt_dir):
type = os.path.basename(txt_dir)[:-4]
if not os.path.exists(os.path.join(dst, type)):
os.mkdir(os.path.join(dst, type))
file = open(txt_dir, 'r')
for line in file.readlines():
line = line[:-1] + '.jpg'
shutil.copy(os.path.join(src, line), os.path.join(dst, type, line))
if __name__ == '__main__':
# if len(sys.argv) <= 1:
# print('3 auguments are need.')
# print('Usage: %s XML_LIST.txt XML_DIR OUTPU_JSON.json'%(sys.argv[0]))
# exit(1)
argv = {}
file_list = ['train','test', 'val', 'trainval']
for file in file_list:
source_dir = '/PATH/TO/VOC2007/ImageSets/Main/{}.txt'.format(file)
argv[1] = '/PATH/TO/COCO/xml_list/{}.txt'.format(file)
generate_xml_txt(source_dir, argv[1])
src_img = '/PATH/TO/VOC2007/JPEGImages'
dst_img = '/PATH/TO/COCO/images'
get_img(src_img, dst_img, source_dir)
argv[2] = '/PATH/TO/COCO/Annotations_xml'
argv[3] = '/PATH/TO/COCO/Annotations/{}.json'.format(file)
convert(argv[1], argv[2], argv[3])
注意点:xmin,ymin,w,h. start from 1.
coco数据集合check
from pycocotools.coco import COCO
import shutil
import os
import cv2
if __name__ == '__main__':
dataDir = '/PATH/TO
/COCO/images'
dataType = 'val' # 要转换的COCO数据集的子集名
annFile = '/PATH/TO/COCO/Annotations/val.json' # COCO数据集的标注文件路径
coco = COCO(annFile) # 加载解析标注文件
imgIds = coco.getImgIds() # 获取标注文件中所有图片的COCO Img ID [0, 1, 2...]
catIds = coco.getCatIds() # 获取标注文件总所有的物体类别的COCO Cat ID [1]
for imgId in imgIds:
objCount = 0 # 一个标志位,用来判断该img是否包含我们需要的标注
print('imgId :%s' % imgId)
Img = coco.loadImgs(imgId)[0] # 加载图片信息
print('Img :%s' % Img)
filename = Img['file_name'] # 获取图片名 red_dragon_hefei_shop_shoes_20200606_1872.jpg'
width = Img['width'] # 获取图片尺寸 2976
height = Img['height'] # 获取图片尺寸 3968
print('filename :%s, width :%s ,height :%s' % (filename, width, height))
annIds = coco.getAnnIds(imgIds=imgId, catIds=catIds, iscrowd=None) # 获取该图片对应的所有COCO物体类别标注ID
print('annIds :%s' % annIds)
# filename = filename.replace(".xml", ".jpg")
img = cv2.imread('%s/%s/%s' % (dataDir, dataType, filename))
for annId in annIds:
anns = coco.loadAnns(annId)[0] # 加载标注信息
catId = anns['category_id'] # 获取该标注对应的物体类别的COCO Cat ID 1
cat = coco.loadCats(catId)[0]['name'] # 获取该COCO Cat ID对应的物体种类名 ''SHOE''
objCount = objCount + 1
box = anns['bbox'] # <class 'list'>: [339.88, 22.16, 153.88, 300.73]
size = [width, height]
xmin = int(box[0]) + 1
ymin = int(box[1]) + 1
obj_width = int(box[2])
obj_height = int(box[3])
xmax = xmin + obj_width
ymax = ymin + obj_height
img = cv2.rectangle(img, (int(xmin), int(ymin)), (int(xmax), int(ymax)), (0, 255, 0), 8)
#img = cv2.resize(img, (800, 800))
cv2.namedWindow('check', cv2.WINDOW_NORMAL)
cv2.imshow('check', img)
cv2.waitKey(0)
参考
https://github.com/shiyemin/voc2coco.gitgithub.comcoco转yolo
# coding=utf-8
from pycocotools.coco import COCO
import shutil
import os
from tqdm import tqdm
# 将ROI的坐标转换为yolo需要的坐标
# size是图片的w和h
# box里保存的是ROI的坐标(x,y的最大值和最小值)
# 返回值为ROI中心点相对于图片大小的比例坐标,和ROI的w、h相对于图片大小的比例
def convert(size, box):
dw = 1. / size[0]
dh = 1. / size[1]
x = box[0] + box[2] / 2.0
y = box[1] + box[3] / 2.0
w = box[2]
h = box[3]
x = x * dw
w = w * dw
y = y * dh
h = h * dh
return (x, y, w, h)
# 获取所需要的类名和id
# path为类名和id的对应关系列表的地址(标注文件中可能有很多类,我们只加载该path指向文件中的类)
# 返回值是一个字典,键名是类名,键值是id
def get_classes_and_index(path):
D = {}
f = open(path)
for line in f:
temp = line.rstrip().split(',', 2)
print("temp[0]:" + temp[0] + "n")
print("temp[1]:" + temp[1] + "n")
D[temp[1]] = temp[0]
return D
if __name__ == '__main__':
lists = ['train','test','trainval','val']
for dataType in lists:
dst_dir = '/PATH/TO/yolo'
images_dir = os.path.join(dst_dir, 'images') # data/images
labels_dir = os.path.join(dst_dir, 'labels') # data/labels
dataDir = '/PATH/TO/COCO' # COCO数据集所在的路径
# dataType = 'trainval' # 要转换的COCO数据集的子集名
annFile = '%s/annotations/%s.json' % (dataDir, dataType) # COCO数据集的标注文件路径
classes = {'TAG': '1', 'PROMOTION':'2'}
# 创建YOLO这俩文件夹images_dir labels_dir
if not os.path.exists(images_dir):
os.makedirs(images_dir)
if not os.path.exists(labels_dir):
os.makedirs(labels_dir)
coco = COCO(annFile) # 加载解析标注文件
list_file = open('%s/%s.txt' % (dst_dir, dataType), 'w') # YOLO数据集训练验证txt
imgIds = coco.getImgIds() # 获取标注文件中所有图片的COCO Img ID
catIds = coco.getCatIds() # 获取标注文件总所有的物体类别的COCO Cat ID
for imgId in tqdm(imgIds):
objCount = 0 # 一个标志位,用来判断该img是否包含我们需要的标注
Img = coco.loadImgs(imgId)[0] # 加载图片信息
filename = Img['file_name'] # 获取图片名
width = Img['width'] # 获取图片尺寸
height = Img['height'] # 获取图片尺寸
annIds = coco.getAnnIds(imgIds=imgId, catIds=catIds, iscrowd=None) # 获取该图片对应的所有COCO物体类别标注ID
for annId in annIds:
anns = coco.loadAnns(annId)[0] # 加载标注信息
catId = anns['category_id'] # 获取该标注对应的物体类别的COCO Cat ID
cat = coco.loadCats(catId)[0]['name'] # 获取该COCO Cat ID对应的物体种类名
# 如果该类名在我们需要的物体种类列表中,将标注文件转换为YOLO需要的格式
if cat in classes:
objCount = objCount + 1
out_file = open(os.path.join(labels_dir, filename[:-4] + '.txt'), 'a')
cls_id = classes[cat] # 获取该类物体在yolo训练中的id
box = anns['bbox']
size = [width, height]
bb = convert(size, box)
out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + 'n')
out_file.close()
if objCount > 0:
# list_file.write('data/images/%sn' % filename) # 相对路径
list_file.write('images/%sn' % filename)
src_img = os.path.join(dataDir, 'images/{}/{}'.format(dataType,filename))
dst_img = os.path.join(images_dir, filename)
shutil.copy(src_img, dst_img)
list_file.close()
yolo check; draw scale, ratio figure.
import os
import cv2
import matplotlib.pyplot as plt
from math import sqrt as sqrt
from tqdm import tqdm
img_formats = ['.bmp', '.jpg', '.jpeg', '.png', '.tif']
sets = ['trainval']
# , 'val', 'test'
if __name__ == '__main__':
classes = ['', '', ''] # 需要检查的类别
yolo_root = '/PATH/TO/yolo'
# GT框宽高统计
width = []
height = []
for set in sets:
txt_path = yolo_root + '/%s.txt' % set
with open(txt_path, 'r') as f:
img_files = [x for x in f.read().splitlines() if os.path.splitext(x)[-1].lower() in img_formats]
for img_path in tqdm(img_files):
img_path = os.path.join(yolo_root, img_path)
# img_path = os.path.join(yolo_root, 'images/14784.jpg')
img = cv2.imread(img_path)
im_h = img.shape[0]
im_w = img.shape[1]
label_path = img_path.replace('images', 'labels').replace(os.path.splitext(img_path)[-1], '.txt')
with open(label_path) as file:
line = file.readline()
while line:
cls = int(line.split(' ')[0])
x = float(line.split(' ')[1])
y = float(line.split(' ')[2])
w = float(line.split(' ')[3])
h = float(line.split(' ')[4].split('n')[0])
# print(cls,x,y,w,h)
real_w = im_w * w
real_h = im_h * h
xmin = ((x * im_w + 1.0) * 2.0 - real_w) / 2.0
xmax = ((x * im_w + 1.0) * 2.0 + real_w) / 2.0
ymin = ((y * im_h + 1.0) * 2.0 - real_h) / 2.0
ymax = ((y * im_h + 1.0) * 2.0 + real_h) / 2.0
img = cv2.rectangle(img, (int(xmin), int(ymin)), (int(xmax), int(ymax)), (0, 255, 0), 4)
r = min(800 / im_w, 800 / im_h)
w_change = (real_w / im_w) * (r * im_w)
h_change = (real_h / im_h) * (r * im_h)
s = w_change * h_change
width.append(sqrt(s))
if not os.path.exists('./strange_img/'):
os.mkdir('./strange_img/')
if not os.path.exists('./long_img/'):
os.mkdir('./long_img/')
# print(img.shape[0], img.shape[1])
if img.shape[1] / img.shape[0] > 5:
cv2.imwrite('./long_img/' + str(w_change) + '_' + str(h_change) + '.jpg', img)
if sqrt(s) > 150:
cv2.imwrite('./strange_img/s'+str(sqrt(s))+'.jpg',img)
height.append(w_change / h_change)
if(w_change / h_change > 5):
cv2.imwrite('./strange_img/r' + str(sqrt(s)) + '.jpg', img)
line = file.readline()
# img = cv2.resize(img, (1000, 1000))
# cv2.imshow('result', img)
# cv2.waitKey(0)
plt.plot(width, height, 'ro')
plt.show()