python实现视频抽帧,文件批量操作,文件批量处理(数据集制作的工具箱)

数据集制作的工具箱

目录

  1. 环境准备
  2. 数据集制作
  3. 文件批量重命名
  4. 文件批量移动
  5. 将文件批量按照一定格式进行重命名
  6. 修改xml文件内容的方法
  7. Pathlib库的常用接口

引言

在计算机视觉项目中,文件批量操作和文件批量预处理是必不可少的步骤。它们涉及处理大量的图像文件,包括读取、处理、保存和预处理。本文将介绍一些常见的技术和方法,以帮助您在计算机视觉项目中有效地进行文件批量操作和文件批量预处理。

环境准备

from pathlib import Path, PurePath
import xml.etree.ElementTree as ET
from typing import Union
import numpy as np
from tqdm import tqdm
import time
import cv2
import os

数据集制作

人工智能就是有多少人工产生多少智能,在计算机视觉项目中,数据集至关重要,下面是如何使用视频抽帧技术实现数据集的制作。以下代码中_videoPlay函数是实时显示导入的视频,CutVideo函数实现手动抽帧,在显示时按c键则抽取当前帧,按Esc键关闭视频。ExtractAll函数是自动抽帧功能,frameGap参数是隔多少帧进行自动抽取。

class ExtractImg(object):
    def __init__(self, videopath: Path, savepath: Path, delay: int = 1) -> None:
        self.spath = savepath
        self.vpath = videopath
        self.delay = delay
        cv2.namedWindow("cv", cv2.WINDOW_NORMAL)
        cv2.resizeWindow("cv", 640, 480)
        self.cap = cv2.VideoCapture(str(self.vpath))
        self._timeflag = 0
        if not savepath.exists():
            os.mkdir(Path(savepath))

    def _videoPlay(self, size: list) -> None:
        self.cap.set(3, size[0])
        self.cap.set(4, size[1])
        while self.cap.isOpened():
            ret, frame = self.cap.read()
            # frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            cv2.imshow("cv", frame)
            if cv2.waitKey(self.delay) & 0xFF == ord('c'):
                cv2.imwrite(str(PurePath.joinpath(self.spath,
                                                  "{}.jpg".format(str(time.time())))), frame)
                print("保存成功")
                time.sleep(1)
            elif cv2.waitKey(self.delay) & 0xFF == 27:
                break

    def ExtractAll(self, frameGap: int = 3) -> None:
        """
        这是将视频流中的帧全部抽出
        :frame: 跳帧
        :return:
        """
        while self.cap.isOpened():
            self._timeflag += 1

            ret, frame = self.cap.read()
            if ret:
                cv2.imshow("cv", frame)
                if self._timeflag % frameGap == 0:
                    cv2.imwrite(str(PurePath.joinpath(self.spath,
                                                      "{}.jpg".format(str(time.time())))), frame)
                    print("保存成功")
            if (cv2.waitKey(self.delay) & 0xFF == 27) or not ret:
                break
        cv2.destroyAllWindows()
        self.cap.release()
        self._timeflag = 0

    def CutVideo(self) -> None:
        """
        这是手动抽帧
        :return:
        """
        ifm = input("文件中已经存在{}张图片,是否有继续添加"
                    "(Y or N):".format(len(os.listdir(self.spath))))
        if self.spath.exists() and ifm == 'Y':
            self._videoPlay(size=[640, 480])
        elif self.spath.exists() and ifm == 'N':
            return None
        else:
            print("\n请输入Y(yes)或者N(no)")
        cv2.destroyAllWindows()
        self.cap.release()

文件批量重命名

将文件夹下的图片进行升序的重命名。

  def statistics(path: Union[str, Path], dstpath: Union[Path, str], count: int = 0, random: bool = False) -> None:
        """
        这是存放图片的文件夹安升序重命名
        :param path:需要重命名的文件文件
        :param count:观察图片总数添加使用
        """
        assert isinstance(path, (Path, str)), print("请输入的路径")
        l = os.listdir(str(path))
        if not Path.exists(dstpath):
            Path.mkdir(dstpath)
        # l = sorted(l)
        print(l)
        # print(l)
        print("存在文件{}张!".format(len(l)))
        if random:
            np.random.shuffle(l)
        # print(l)
        # 将保存图片文件中的图片按照升序的方法重命名

        suffix = Path(l[0]).suffix
        for file in tqdm(l):
            src = PurePath.joinpath(path, file)
            dst = PurePath.joinpath(dstpath, Path(str(count + int(Path(file).stem))).with_suffix(suffix))
            os.rename(src, dst)

文件批量移动

下面的是将文件批量按照一定规则挑选出来放到目标文件夹下。

    def choosen(src: Union[str, Path] , folder: Union[Path,str] ,dst: Union[str, Path] , suffix: str) -> None:
        """
        1.将xml/jpg文件夹中的文件名字拿出来并且在jpg/xml对应的文件夹中将名称相同的文件挑出来
        2.将文件夹中的文件随取出
        :param xmlsrc:目标xml文件
        :param imgsrc:frameImg文件
        :param dst:根据xml挑选出的img文件
        :return: None
        """
        # l = os.listdir(str(xmlsrc))
        if not isinstance(folder,Path):
            pa = Path(folder)
        if not isinstance(src,Path):
            l = Path(src)

        # parent = src.parent
        for i in l.iterdir():
            file = Path(i.name).with_suffix(suffix)
            (pa / file).rename(Path(dst) / file)

将文件批量按照一定格式进行重命名

下面将文件按照5位数字的格式进行重命名 1.jpg->00001.jpg

    def batchrenames(src: Union[str, Path], dst: Union[str, Path], sorted: bool = False) -> None:
        """
        进行特定格式的重命名
        :param src:原文件
        :param dst: 存储文件
        :param sorted: 是否已经有顺序,若有学按照1.jpg ->00001.jpg
        :return: None
        """

        d = {
    
    1: "0000",  # 这是命名格式的字典
             2: "000",
             3: "00",
             4: "0",
             5: ""}
        l = os.listdir(src)
        suffix = Path(l[0]).suffix
        l.sort(key=lambda x: int(x.split('.')[0]))
        if sorted:
            for obj in tqdm(l):
                old = PurePath.joinpath(src, obj)
                new = PurePath.joinpath(dst, d[len(obj.split('.')[0])] + obj.split('.')[0] + suffix)
                os.rename(old, new)
        else:
            # for c, i in tqdm(enumerate(l)):
            pass

修改xml文件内容的方法

这是修改xml文件内容的代码。

    def revampXml(xml_path: Union[Path, str], update_content: str) -> None:
        """
        这是一个修改xml文件内容的方法,将xml文件爱中的类别改称另一个类别
        :param xml_path: 存放xml文件的路径
        :param xml_dw: xpath关键字
        :param update_content: 更新的内容
        :return:None
        """
        # 打开xml文档
        if not isinstance(xml_path, Path):
            xml_path = Path(xml_path)
        for i in tqdm(xml_path.iterdir()):
            xmlfile = xml_path / f"{
      
      i}"
            doc = ET.parse(xmlfile)
            root = doc.getroot()
            # 查找修改路劲
            for obj in root.iter("object"):
                sub1 = obj.find("name")
                if sub1.text == "motorboat":
                    # 修改标签内容
                    sub1.text = update_content
                    # 保存修改
                    doc.write(xmlfile)

Pathlib库以及os库的常用文件操作API

pathlib是 标准库之一,用于操作文件系统路径。该库可以方便地进行路径的拼接、文件/目录的创建、复制/移动、删除等操作。

功能描述 pathlib操作 os及os.path操作
获得绝对路径 Path.resolve() os.path.abspath()
修改文件权限和时间戳 Path.chmod() os.chmod()
创建目录 Path.mkdir() os.mkdir()
文件或文件夹重命名,如果路径不同,会移动并重新命名 Path.rename() os.rename()
文件或文件夹重命名,如果路径不同,会移动并重新命名,如果存在,则破坏现有目标 Path.replace() os.replace()
删除目录 Path.rmdir() os.rmdir()
删除一个文件 Path.unlink() os.remove()
删除一个文件 Path.unlink() os.unlink()
获得当前工作目录 Path.cwd() os.getcwd()
判断是否存在文件或目录name Path.exists() os.path.exists()
返回电脑的用户目录 Path.home() os.path.expanduser()
检验给出的路径是一个文件 Path.is_dir() os.path.isdir()
检验给出的路径是一个目录 Path.is_file() os.path.isfile()
检验给出的路径是一个符号链接 Path.is_symlink() os.path.islink()
获得文件属性 Path.stat() os.stat()
判断是否为绝对路径 PurePath.is_absolute() os.path.isabs()
连接目录与文件名或目录 PurePath.joinpath() os.path.join()
返回文件名 PurePath.name os.path.basename()
返回文件路径 PurePath.parent os.path.dirname()
判断两个路径是否相同 Path.samefile() os.path.samefile()
分离文件名和扩展名 PurePath.suffix os.path.splitext()

总结

本文介绍了计算机视觉项目中的文件批量操作与文件批量预处理技术。 掌握这些技术将使您能够高效地处理大规模的图像数据,并为计算机视觉项目的成功实施提供强大的支持。

希望本文对您在计算机视觉项目中的文件批量操作与文件批量预处理有所启发!

以下是完整代码

# -*- coding: utf-8 -*-
# @Author  : cvYouTian
# @Software: PyCharm

from pathlib import Path, PurePath
import xml.etree.ElementTree as ET
from typing import Union
import numpy as np
# import torch
from tqdm import tqdm
import time
import cv2
import os


class ExtractImg(object):
    def __init__(self, videopath: Path, savepath: Path, delay: int = 1) -> None:
        self.spath = savepath
        self.vpath = videopath
        self.delay = delay
        cv2.namedWindow("cv", cv2.WINDOW_NORMAL)
        cv2.resizeWindow("cv", 640, 480)
        self.cap = cv2.VideoCapture(str(self.vpath))
        self._timeflag = 0
        if not savepath.exists():
            os.mkdir(Path(savepath))

    def _videoPlay(self, size: list) -> None:
        self.cap.set(3, size[0])
        self.cap.set(4, size[1])
        while self.cap.isOpened():
            ret, frame = self.cap.read()
            # frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            cv2.imshow("cv", frame)
            if cv2.waitKey(self.delay) & 0xFF == ord('c'):
                cv2.imwrite(str(PurePath.joinpath(self.spath,
                                                  "{}.jpg".format(str(time.time())))), frame)
                print("保存成功")
                time.sleep(1)
            elif cv2.waitKey(self.delay) & 0xFF == 27:
                break

    def ExtractAll(self, frameGap: int = 3) -> None:
        """
        这是将视频流中的帧全部抽出
        :frame: 跳帧
        :return:
        """
        while self.cap.isOpened():
            self._timeflag += 1

            ret, frame = self.cap.read()
            if ret:
                cv2.imshow("cv", frame)
                if self._timeflag % frameGap == 0:
                    cv2.imwrite(str(PurePath.joinpath(self.spath,
                                                      "{}.jpg".format(str(time.time())))), frame)
                    print("保存成功")
            if (cv2.waitKey(self.delay) & 0xFF == 27) or not ret:
                break
        cv2.destroyAllWindows()
        self.cap.release()
        self._timeflag = 0

    def CutVideo(self) -> None:
        """
        这是手动抽帧
        :return:
        """
        ifm = input("文件中已经存在{}张图片,是否有继续添加"
                    "(Y or N):".format(len(os.listdir(self.spath))))
        if self.spath.exists() and ifm == 'Y':
            self._videoPlay(size=[640, 480])
        elif self.spath.exists() and ifm == 'N':
            return None
        else:
            print("\n请输入Y(yes)或者N(no)")
        cv2.destroyAllWindows()
        self.cap.release()

    @staticmethod
    def statistics(path: Union[str, Path], dstpath: Union[Path, str], count: int = 5305, random: bool = False) -> None:
        """
        这是存放图片的文件夹安升序重命名
        :param path:需要重命名的文件文件
        :param count:观察图片总数添加使用
        """
        assert isinstance(path, (Path, str)), print("请输入的路径")
        l = os.listdir(str(path))
        if not Path.exists(dstpath):
            Path.mkdir(dstpath)
        # l = sorted(l)
        print(l)
        # print(l)
        print("存在文件{}张!".format(len(l)))
        if random:
            np.random.shuffle(l)
        # print(l)
        # 将保存图片文件中的图片按照升序的方法重命名

        suffix = Path(l[0]).suffix
        for file in tqdm(l):
            src = PurePath.joinpath(path, file)
            dst = PurePath.joinpath(dstpath, Path(str(count + int(Path(file).stem))).with_suffix(suffix))
            os.rename(src, dst)

    @staticmethod
    def choosen(src: Union[str, Path]="/home/you/Desktop/2023海上高速目标检测/val", folder: Union[Path,str]="/home/you/Desktop/2023海上高速目标检测/annotations",dst: Union[str, Path]="/home/you/Desktop/2023海上高速目标检测/train", suffix: str=".xml") -> None:
        """
        1.将xml/jpg文件夹中的文件名字拿出来并且在jpg/xml对应的文件夹中将名称相同的文件挑出来
        2.将文件夹中的文件随取出
        :param xmlsrc:目标xml文件
        :param imgsrc:frameImg文件
        :param dst:根据xml挑选出的img文件
        :return: None
        """
        # l = os.listdir(str(xmlsrc))
        if not isinstance(folder,Path):
            pa = Path(folder)
        if not isinstance(src,Path):
            l = Path(src)

        # parent = src.parent
        for i in l.iterdir():
            file = Path(i.name).with_suffix(suffix)
            (pa / file).rename(Path(dst) / file)

    @staticmethod
    def batchrenames(src: Union[str, Path], dst: Union[str, Path], sorted: bool = False) -> None:
        """
        进行特定格式的重命名
        :param src:原文件
        :param dst: 存储文件
        :param sorted: 是否已经有顺序,若有学按照1.jpg ->00001.jpg
        :return: None
        """

        d = {
    
    1: "0000",  # 这是命名格式的字典
             2: "000",
             3: "00",
             4: "0",
             5: ""}
        l = os.listdir(src)
        suffix = Path(l[0]).suffix
        l.sort(key=lambda x: int(x.split('.')[0]))
        if sorted:
            for obj in tqdm(l):
                old = PurePath.joinpath(src, obj)
                new = PurePath.joinpath(dst, d[len(obj.split('.')[0])] + obj.split('.')[0] + suffix)
                os.rename(old, new)
        else:
            # for c, i in tqdm(enumerate(l)):
            pass

    @staticmethod
    def text(file: Union[Path, str]):
        l = []
        f = open(file)
        for i in f.readlines():
            i = i.strip()
            stem = Path(i).stem
            suffix = Path(i).suffix
            n1, n2 = int(stem) - 1, int(stem) + 1
            l.append(str(n1) + ".xml")
            l.append(str(n2) + ".xml")
        print(l)

    @staticmethod
    def revampXml(xml_path: Union[Path, str], update_content: str) -> None:
        """
        这是一个修改xml文件内容的方法,将xml文件爱中的类别改称另一个类别
        :param xml_path: 存放xml文件的路径
        :param xml_dw: xpath关键字
        :param update_content: 更新的内容
        :return:None
        """
        # 打开xml文档
        if not isinstance(xml_path, Path):
            xml_path = Path(xml_path)
        for i in tqdm(xml_path.iterdir()):
            xmlfile = xml_path / f"{
      
      i}"
            doc = ET.parse(xmlfile)
            root = doc.getroot()
            # 查找修改路劲
            for obj in root.iter("object"):
                sub1 = obj.find("name")
                if sub1.text == "motorboat":
                    # 修改标签内容
                    sub1.text = update_content
                    # 保存修改
                    doc.write(xmlfile)

    @staticmethod
    def movefile(folder_path: Union[Path, str], dst: Union[Path, str], suffix: str) -> None:
        """
        批量移动剪切文件
        :param folder_path: 原文件夹路径
        :param dst: 目标文件夹路径
        :param suffix: 移动的文件格式/后缀
        :return:
        """
        if not isinstance(folder_path, Path):
            folder_path = Path(folder_path)
        # for i in folder_path.iterdir():
        #     if i.is_dir():
        #         ExtractImg.movefile(folder_path / i, suffix, res)
        #     else:
        #         if i.suffix == suffix:
        #             res.append(str(i))
        # # return res if suffix is None or suffix == "" else list(filter(lambda x: str(x).endswith(suffix),res))
        # return res
        for i in tqdm(folder_path.rglob(f"*{
      
      suffix}")):
            i.rename(dst / i.name)
    @staticmethod
    def convert_box(size, box):
            dw, dh = 1. / size[0], 1. / size[1]
            x, y, w, h = (box[0] + box[1]) / 2.0 - 1, (box[2] + box[3]) / 2.0 - 1, box[1] - box[0], box[3] - box[2]
            return x * dw, y * dh, w * dw, h * dh

  

if __name__ == "__main__":
    # 目标视频文件
    videopath = Path("videoSet/seabird6.mp4")
    # 图片保存文件
    savepath = Path("./dataset/imgs")
    # xin = Path("./VOC6detect/imgss")
    # savepath = Path("frameSave")
    # 目标xml文件
    # xmlpath = Path("./VOC6detect/annotations")
    # old = Path("/home/you/Desktop/dateset/20(pass)/seabird5")
    # new = Path("/home/you/Desktop/dateset/11(pass)/temp")
    # pa = Path("./labels/")
    # xin = Path()
    # renamepath = Path("/home/you/Desktop/dateset/4(pass)/a-1")
    # 实例化
    a = ExtractImg(videopath=videopath, savepath=savepath)
    a.choosen()
    # VOC2YOLO
    # a.convert_label()


    # 将帧全部抽出
    # a.ExtractAll(frameGap=8)

    # 手动抽帧
    # a.CutVideo()

    # 根据xml文选出对应的文件
    # a.choosen(xmlsrc=xmlpath, imgsrc=savepath, dst=xin)

    # 将数字命名的图片按照加上一个数字的方式命名
    # a.statistics(path=Path("./DATA/xml"), dstpath=Path("./DATA/t"), count=5305)

    # 对已经有顺序或者没顺序的文件进行特定格式的重命名78.jpg -> 00078.jpg
    # a.batchrenames(src=new, dst=old, sorted=True)
    # a.text("./data1.txt")
    # 对xml文件进行修改
    # a.revampXml(xml_path= "/home/you/Desktop/tools/dataset/annotations", update_content="speedboat")

    # 批量拿到文件夹中的某格式的文件
    # a.movefile(folder_path="/home/you/Desktop/网上快艇", dst=pa, suffix=".jpg")

猜你喜欢

转载自blog.csdn.net/m0_46114594/article/details/131956883