用opencv实现yolov4中的mosaic数据增强

简单看了一个yolov4的介绍,mosaic数据增强简单说就是四张图片合一,长宽随机变化。理想的实现是结合图片集和标签集,对单张图片标注过之后,四张合一的图片就不用再标注。这里只做一个简单的实现,仅仅把四张图片随机合一,生成mosaic图片集,后面需要对这个生成的图片标注。

c++程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <opencv2/opencv.hpp>
#include <ctime>
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
using namespace cv;

int main()
{
    //读入四幅图片
    string imageFile = "D:/work_place/第二批图片/";//图片集文件夹
    string imgName = imageFile + "imgName.txt";
    ifstream fin(imgName, ios::in);
    //char line[1024] = { 0 };
    string line;

    while (1)
    {
        vector<Mat> inputImg;
        for (int i = 0; i < 4; i++)
        {
            getline(fin, line);
            cout << "Image Name: " << line << endl;
            string imgRoad = imageFile + line;//图片的绝对路径名
            inputImg.push_back(imread(imgRoad));
        }
        Mat image_1 = inputImg[0];
        Mat image_2 = inputImg[1];
        Mat image_3 = inputImg[2];
        Mat image_4 = inputImg[3];

        Size sz = Size(image_1.cols, image_1.rows);      //最终要生成的图片大小,我设置成和原来一张图片大小相等
        srand((unsigned int)time(NULL));
        int randomNumX = (rand() % 3 + 4);//[4,6]中随机数
        int randomNumY = (rand() % 3 + 4);
        Size sz1 = Size(sz.width * randomNumX / 10, sz.height * randomNumY / 10);
        resize(image_1, image_1, sz1, 0, 0);
        Size sz2 = Size(sz.width - sz1.width, sz1.height);
        resize(image_2, image_2, sz2, 0, 0);
        Size sz3 = Size(sz1.width, sz.height - sz1.height);
        resize(image_3, image_3, sz3, 0, 0);
        Size sz4 = Size(sz.width - sz1.width, sz.height - sz1.height);
        resize(image_4, image_4, sz4, 0, 0);

        //创建连接后存入的图像
        Mat result(sz.height + 1, sz.width + 1, image_1.type());

        //第1幅,拷贝到左上角
        Rect roi_rect = Rect(0, 0, sz1.width, sz1.height);
        image_1.copyTo(result(roi_rect));

        //第2幅,拷贝到右上角
        roi_rect = Rect(sz1.width + 1, 0, sz2.width, sz2.height);
        image_2.copyTo(result(roi_rect));

        //第3幅,拷贝到左下角
        roi_rect = Rect(0, sz1.height + 1, sz3.width, sz3.height);
        image_3.copyTo(result(roi_rect));

        //第4幅,拷贝到右下角
        roi_rect = Rect(sz1.width + 1, sz1.height + 1, sz4.width, sz4.height);
        image_4.copyTo(result(roi_rect));

        //显示四幅图像连接后的图像
        namedWindow("result", WINDOW_NORMAL);
        imshow("result", result);
        //保存拼接后的图片
        static int imageName = 0;
        string imageRoad = "result/" + to_string(imageName) + ".jpg";
        imwrite(imageRoad, result);
        imageName++;
        waitKey(0);
    }
    return 0;
}

图片是从指定的文件夹中读取的,这里要先在图片集文件夹中生成一个txt文件,里面每一行是一个图片的名称。可运行下面这个python程序,自动生成:(图片集路径换成自己的),运行完这个程序,再运行上面的c++程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# -*- coding: cp936 -*-
import os

def ListFilesToTxt(dir, file, wildcard, recursion):
    exts = wildcard.split(" ")
    files = os.listdir(dir)
    for name in files:
        fullname = os.path.join(dir, name)
        if (os.path.isdir(fullname) & recursion):
            ListFilesToTxt(fullname, file, wildcard, recursion)
        else:
            for ext in exts:
                if (name.endswith(ext)):
                    file.write(name + "\n")
                    break

def Test():

    dir = "D:/work_place/第二批图片"    #在这里修改图片集路径
    outfile = "D:/work_place/第二批图片/imgName.txt"

    wildcard = ".txt .exe .dll .lib .bmp .jpg"

    file = open(outfile, "w")
    if not file:
        print ("cannot open the file %s for writing" % outfile)
    ListFilesToTxt(dir, file, wildcard, 1)

    file.close()

Test()

结果: