在做深度学习相关的项目时,往往最麻烦的是样本的收集,或者只有很少的一些样本,训练根本达不到想要的效果,很多网络模型的配置文件里面都有样本增强的定义,是对样本做旋转,变换之类的操作,但没有给样本加一些背景来制造增强样本的数量。
1.我做一个发票检测位置到识别里面文字的项目,但我手里并没有多少张发票样本,在网上也很难找到能用的样本,我的应用场景是把发票放在桌面上拍照之后,检测识别。所以我先去网上下一些木纹桌面的样本,放在一个目录,完成之后从0开始命名如下:
2.我自己手中有发票样本也放在一个目录,也从0开始命名如下:
1.代码用到OpenCV的基本库,读写文件就随便写了个循环读写,最好是改成boost库来读写文件。
2.代码的思想,大概是要的发票样本按任意角度旋转,再与背景图像融合。
3.代码:
bool ROI_AddImage(Mat &cv_back, Mat &cv_front, Mat &cv_dst)
{
Mat cv_mask = cv_front.clone();
if (!cv_back.data)
{
std::cout << "读入图片失败" << std::endl;
return false;
}
if (!cv_front.data)
{
std::cout << "读入图片失败" << std::endl;
return false;
}
int w = (cv_back.cols - cv_front.cols) / 2;
int h = (cv_back.rows - cv_front.rows) / 2;
Mat imageROI = cv_back(Rect(w, h, cv_front.cols, cv_front.rows));
Mat mask;
cv::cvtColor(cv_mask, mask, COLOR_BGR2GRAY);
cv_front.copyTo(imageROI, mask);
cv_dst = cv_back.clone();
}
int main()
{
string back = "C:/Users/matt/Desktop/8/";
string front = "C:/Users/matt/Desktop/80/";
string save = "C:/Users/matt/Desktop/data/";
for (int i = 0; i < 20; i++)
{
string back_name = back + to_string(i) + ".jpg";
string front_name = front + to_string(i) + ".jpg";
Mat back = imread(back_name);
Mat cv_front = imread(front_name);
for (int j = 0; j < 5; j++)
{
Mat cv_back = back.clone();
Mat cv_rotata;
int a = rand() % 180;
rotateImage2(cv_front, cv_rotata, a, 0);
Mat cv_png;
toPng(cv_rotata, cv_png, 0);
if (cv_png.rows > cv_back.rows)
{
resize(cv_back, cv_back, cv_png.size(), 0.0, 0.0, INTER_NEAREST);
resize(cv_png, cv_png, Size(cv_png.cols / 1.2, cv_png.rows / 1.2));
}
if (cv_png.rows < cv_back.rows)
{
resize(cv_png, cv_png, cv_back.size(), 0.0, 0.0, INTER_NEAREST);
resize(cv_png, cv_png, Size(cv_png.cols / 1.2, cv_png.rows / 1.2));
}
Mat cv_dst;
ROI_AddImage(cv_back, cv_png, cv_dst);
string save_name = save + to_string(i) + to_string(j) + ".jpg";
imwrite(save_name, cv_dst);
}
}
waitKey(0);
return 0;
}
void toPng(cv::Mat &src, cv::Mat &dst, int mark)
{
cv::Mat cv_input = src.clone();
if (cv_input.channels() != 4)
{
cv::cvtColor(cv_input, dst, CV_BGR2BGRA);
}
else
{
return;
}
for (int y = 0; y < dst.rows; ++y)
{
for (int x = 0; x < dst.cols; ++x)
{
cv::Vec4b & pixel = dst.at<cv::Vec4b>(y, x);
if (pixel[0] == mark && pixel[1] == mark && pixel[2] == mark)
{
pixel[3] = 0;
}
}
}
}
int rotateImage(Mat &img, Mat & imgout, int degree, int border_value)
{
if (img.empty())
return 1;
degree = -degree;
double angle = degree * CV_PI / 180.; // 弧度
double a = sin(angle), b = cos(angle);
int width = img.cols;
int height = img.rows;
int width_rotate = int(width * fabs(b) + height * fabs(a));
int height_rotate = int(height * fabs(b) + width * fabs(a));
if (width_rotate <= 20 || height_rotate <= 20)
{
width_rotate = 20;
height_rotate = 20;
}
float map[6];
Mat map_matrix = Mat(2, 3, CV_32F, map);
// 旋转中心
CvPoint2D32f center = cvPoint2D32f(width / 2, height / 2);
CvMat map_matrix2 = map_matrix;
cv2DRotationMatrix(center, degree, 1.0, &map_matrix2);//计算二维旋转的仿射变换矩阵
map[2] += (width_rotate - width) / 2;
map[5] += (height_rotate - height) / 2;
int chnnel = img.channels();
if (chnnel == 3)
warpAffine(img, imgout, map_matrix, Size(width_rotate, height_rotate), 1, 0, Scalar(0, 0, 0));
else
warpAffine(img, imgout, map_matrix, Size(width_rotate, height_rotate), 1, 0, 255);
return 0;
}
4.可以自己设置融合多少次,运行之后的结果如下: