训练数据不够怎么办?卷积神经网络数据扩充详解

扩充方法

在进行卷积神经网络计算时,很多情况下我们无法获得足够的数据,可以通过人工数据合成的方法进行扩充.本人的扩充方法如下:
具体为将原图像分别水平,竖直和水平竖直翻转扩充至原来的4倍;然后对获得图像分别-30°,-15°,15°,30°进行旋转扩充至原来的20倍;然后随机添加高斯噪声扩充至原来的40倍.
运行环境:QT+C+++OPENCV

代码

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;

void Resize(int i,cv::Mat image1);
void imageRotate(const cv::Mat &src,  double degree, const double scale,int i, float height, float width );
double generateGaussianNoise(double mu, double sigma);
Mat addGaussianNoise(Mat &srcImag,int i);

int main()
{
    //用void glob(String pattern, std::vector<String>& result, bool recursive = false);当recursive为false时,仅仅遍历指定文件夹内符合模式的文件,当recursive为true时,会同时遍历指定文件夹的子文件夹
    //pattern要绝对路径 其它测试有问题
    string pattern ="/home/li/shijuejiance/sample/train/bad/*.bmp";
    //cout << pattern << endl;
    vector<Mat> images;
    // 必须cv的String
    vector<String> fn;
    glob(pattern, fn, false);
    int count = fn.size();
    cout << count << endl;
    for (int i = 0; i < count; i++)
    {
        images.push_back(imread(fn[i]));
        //Resize(i,images[i]);
        imageRotate(images[i],-30,1,i,1375,2125);
        //cout<<i<<endl;
        //Mat dstImage = addGaussianNoise(images[i],i);
        //imshow("添加高斯噪声后的图像", dstImage);
        cout<<i<<endl;
    }

}



/*
//裁剪和翻转
void Resize(int i,cv::Mat image1)
{
    i=i+40;
    //cv::Mat image2;
    //cv::resize(image1, image2, cv::Size(), 0.2, 0.2);
    //cv::imshow("原图",image2);
    //矩形提取
    cv::Rect rect(200,375,2125,1375);   //盖板
    //cv::Rect rect(260,375,2190,1375);   //学校
    cv::Mat image_cut = cv::Mat(image1, rect);      //从img中按照rect进行切割,此时修改image_cut时image中对应部分也会修改,因此需要copy
    cv::Mat image = image_cut.clone();   //clone函数创建新的图片
    //cv::imshow("裁剪好的图像",image);
     //cv::flip(image1,image1,-1);//>0: 沿y-轴翻转, 0: 沿x-轴翻转, <0: x、y轴同时翻转
     cv::imwrite("/home/li/shijuejiance/sample/train/bad/"+to_string(i)+".bmp",image1);
     imshow("images", image1);
}
*/



//旋转
void imageRotate(const cv::Mat &src,  double degree, const double scale,int i, float height, float width )
{
    i=i+76;
    cv::Mat image1;
    double angle = degree;
    int length = 0;//保证旋转后的图像足够大能存放结果(对角线长度)
    if (scale <= 1)
        length = sqrt(src.cols*src.cols + src.rows*src.rows);
    else
        length = sqrt(src.cols*src.cols + src.rows*src.rows) * scale;
    cv::Mat tmp_img = cv::Mat(length, length, src.type(), cv::Scalar(255, 255, 255));
    int ROI_X = length / 2 - src.cols / 2;
    int ROI_Y = length / 2 - src.rows / 2;
    cv::Rect ROI_SRC(ROI_X, ROI_Y, src.cols, src.rows);
    cv::Mat tmp_ROI(tmp_img, ROI_SRC);//取出临时图像tmp_img的中心的一块ROI_SEC存放src,也就是将src图像放到了临时图像tmp_img的中心
    src.copyTo(tmp_ROI);
    cv::Point2f rotate_center(length / 2, length / 2);//旋转中心
    cv::Mat affineMat = cv::getRotationMatrix2D(rotate_center, angle, scale);//仿射变换旋转矩阵
    cv::warpAffine(tmp_img, image1, affineMat, cv::Size(length, length), cv::INTER_CUBIC, 0, cv::Scalar(255, 255, 255));//仿射变换

    if(degree>=0)
        degree=degree;
    else
        degree=-degree;
    degree = degree*CV_PI / 180;
    float height1, width1;
    height1 = width*sin(degree) + height*cos(degree);
    width1 = width*cos(degree) + height*sin(degree);
    if (height1 > image1.rows)
            height1 = image1.rows;
    if (width1 > image1.cols)
            width1 = image1.cols;
    cv::Point2f point(image1.cols / 2 - width1 / 2, image1.rows / 2 - height1 / 2);
    cv::Rect2f rect(point, cv::Size2f(width1, height1));
    cv::Mat temp = image1(rect);
    cv::Mat dst;

    dst = temp;
    cv::imshow("images",dst);
    cv::imwrite("/home/li/shijuejiance/sample/test/"+to_string(i)+".bmp",dst);
}


/*
//生成高斯噪声
double generateGaussianNoise(double mu, double sigma)
{
    //定义小值
    const double epsilon = numeric_limits<double>::min();
    static double z0, z1;
    static bool flag = false;
    flag = !flag; //flag为假构造高斯随机变量X
    if (!flag)
       return z1 * sigma + mu;
    double u1, u2;
    //构造随机变量
    do
    {
        u1 = rand() * (1.0 / RAND_MAX);
        u2 = rand() * (1.0 / RAND_MAX);
    } while (u1 <= epsilon);
    //flag为真构造高斯随机变量
    z0 = sqrt(-2.0*log(u1))*cos(2 * CV_PI*u2);
    z1 = sqrt(-2.0*log(u1))*sin(2 * CV_PI*u2);
    return z0*sigma + mu;
}

//为图像添加高斯噪声
Mat addGaussianNoise(Mat &srcImag,int i)
{
        i=i+1;
        Mat dstImage = srcImag.clone();
        int channels = dstImage.channels();
        int rowsNumber = dstImage.rows;
        int colsNumber = dstImage.cols*channels;
        //判断图像的连续性
        if (dstImage.isContinuous())
        {
            colsNumber *= rowsNumber;
            rowsNumber = 1;
        }
        for (int k= 0; k < rowsNumber; k++)
        {
            for (int j = 0; j < colsNumber; j++)
            {
                //添加高斯噪声
                int val = dstImage.ptr<uchar>(k)[j] + generateGaussianNoise(2, 0.8) * 32;
                if (val < 0)
                    val = 0;
                if (val>255)
                    val = 255;
                dstImage.ptr<uchar>(k)[j] = (uchar)val;
            }
        }
        cv::imwrite("/home/li/shijuejiance/sample/test2/"+to_string(i)+".bmp",dstImage);
        return dstImage;
}

*/

版权声明:本文为weixin_41440103原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。