下面是详细的攻略:
概述
本文将介绍如何使用Python和OpenCV库,批量裁剪xml格式标注的图片,以及如何将裁剪好的图片和对应的标注信息保存在指定文件夹中。
环境
在使用本文中的代码前,需要安装以下环境:
- Python 3.x
- OpenCV-Python 库
- lxml 库
步骤
- 读取标注信息
首先要解析xml格式的标注文件,读取每张图片中目标的标注信息,使用lxml库可以轻松完成。
``` python
# 导入lxml库,解析xml文件
from lxml import etree
# 读取标注文件
def read_xml(xml_path):
xml = etree.parse(xml_path).getroot()
# 获取所有图片对象
items = xml.findall('object')
# 存储标注信息,每个元素是一个字典,包含坐标、类别等信息
objs = []
for obj in items:
obj_bbox = obj.find('bndbox')
# 存储xmin, ymin, xmax, ymax这四个坐标值
bbox = [int(obj_bbox.find('xmin').text),
int(obj_bbox.find('ymin').text),
int(obj_bbox.find('xmax').text),
int(obj_bbox.find('ymax').text)]
# 存储类别,这里默认是person
title = obj.find('name').text.lower().strip()
if title == '':
title = 'person'
objs.append({'bbox': bbox, 'title': title})
return objs
```
- 读取图片信息
读取图片信息可以使用OpenCV-Python库中的cv2.imread()方法,同时注意把图片大小调整为处理后的大小。
``` python
# 导入OpenCV-Python库,读取图片
import cv2
# 读取图片
def read_image(img_path):
img = cv2.imread(img_path)
# 处理后的图片大小,这里默认是100 * 100
dst = cv2.resize(img, (100, 100), interpolation=cv2.INTER_LINEAR)
return dst
```
- 裁剪图片
根据标注信息,将每个目标区域对应的原图切割出来。这里利用cv2库,使用函数cv2.rectangle()和cv2.crop()完成。
python
# 裁剪图片
def crop_image(image, bbox):
# 先画出bbox矩形框
xmin, ymin, xmax, ymax = bbox
cv2.rectangle(image, (xmin, ymin), (xmax, ymax), (0, 0, 255), 2)
# 再进行切割
cropped = image[ymin:ymax, xmin:xmax]
return cropped
- 保存图片和标注
将裁剪好的图片和对应的标注信息保存到指定文件夹中,可以使用Python自带的os模块。
``` python
# 导入os库,保存图片和标注
import os
# 保存图片和标注
def save_crop(image, objs, save_dir, img_name):
if not os.path.exists(save_dir):
os.makedirs(save_dir)
# 遍历所有目标,分别进行裁剪和保存
for idx, obj in enumerate(objs):
bbox = obj["bbox"]
title = obj["title"]
# 切割后的图片名称
new_img_name = f'{title}{idx}{img_name}'
# 保存crop_image函数返回的结果
cv2.imwrite(os.path.join(save_dir, new_img_name), crop_image(image, bbox))
# 保存标注信息到txt文件中
with open(os.path.join(save_dir, f"{title}_{img_name}.txt"), 'w') as f:
print(title, bbox, file=f)
```
- 批量裁剪
最后,使用以上方法读取并处理标注信息和图片,遍历所有图片并进行批量裁剪,详情请参考以下示例。
python
# 批量裁剪
def batch_crop(img_dir, xml_dir, save_dir):
for img_name in os.listdir(img_dir):
# 获取图片路径和对应的标注路径
img_path = os.path.join(img_dir, img_name)
xml_path = os.path.join(xml_dir, img_name.replace(".jpg", ".xml"))
# 读取图片和标注信息
image = read_image(img_path)
objs = read_xml(xml_path)
# 切割图片,并保存图片和标注
save_crop(image, objs, save_dir, img_name)
示例
我们可以使用VOC2007数据集中的一些图片和标注文件进行实验。以下是两个实例:
- 单张图片裁剪
如下代码是单张图片的裁剪,将图片命名为a.jpg,标注文件为a.xml。
``` python
img_dir = './VOC2007/JPEGImages'
xml_dir = './VOC2007/Annotations'
save_dir = './crop_image'
img_name = 'a.jpg'
xml_name = 'a.xml'
img_path = os.path.join(img_dir, img_name)
xml_path = os.path.join(xml_dir, xml_name)
image = read_image(img_path)
objs = read_xml(xml_path)
save_crop(image, objs, save_dir, img_name)
```
- 批量裁剪
如下代码是批量进行裁剪,将所有VOC2007数据集中的jpg图片进行裁剪。
``` python
img_dir = './VOC2007/JPEGImages'
xml_dir = './VOC2007/Annotations'
save_dir = './crop_image'
# 批量裁剪
batch_crop(img_dir, xml_dir, save_dir)
```
由于裁剪后的结果已经保存在指定文件夹中,我们可以使用其他的工具对这些裁剪后的图片进行分类训练等操作,不过这已经超出了本文的范畴。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:三分钟教会你用Python+OpenCV批量裁剪xml格式标注的图片 - Python技术站