目的:公司在申请项目填写计划书时,需要提交所有参与人员的电子签名,项目参与人员将电子签名提交上来(在白纸上写上名字并拍照发送过来),我这里需将发送过来的图片背景变为纯白(为了美观),由于人员众多,普通的PS速度太慢,故编写下述代码,该代码可对某个文件夹下的所有图片,进行背景处理,大大加快了工作效率
代码:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace std;
using namespace cv;
//读取指定目录下的图片
void getAllFiles(string path, vector<string> &files, string fileType)
{
long hFile = 0;
struct _finddata_t fileInfo;
string p;
if ((hFile = _findfirst(p.assign(path).append("\\*" + fileType).c_str(), &fileInfo)) != -1) {
do {
files.push_back(p.assign(path).append("\\").append(fileInfo.name));
} while (_findnext(hFile, &fileInfo) == 0);
}
}
int otsu(IplImage *image)
{
assert(NULL != image);
int width = image->width;
int height = image->height;
int x = 0, y = 0;
int pixelCount[256];
float pixelPro[256];
int i, j, pixelSum = width * height, threshold = 0;
uchar* data = (uchar*)image->imageData;
//初始化
for (i = 0; i < 256; i++)
{
pixelCount[i] = 0;
pixelPro[i] = 0;
}
//统计灰度级中每个像素在整幅图像中的个数
for (i = y; i < height; i++)
{
for (j = x; j <width; j++)
{
pixelCount[data[i * image->widthStep + j]]++;
}
}
//计算每个像素在整幅图像中的比例
for (i = 0; i < 256; i++)
{
pixelPro[i] = (float)(pixelCount[i]) / (float)(pixelSum);
}
//经典ostu算法,得到前景和背景的分割
//遍历灰度级[0,255],计算出方差最大的灰度值,为最佳阈值
float w0, w1, u0tmp, u1tmp, u0, u1, u, deltaTmp, deltaMax = 0;
for (i = 0; i < 256; i++)
{
w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = deltaTmp = 0;
for (j = 0; j < 256; j++)
{
if (j <= i) //背景部分
{
//以i为阈值分类,第一类总的概率
w0 += pixelPro[j];
u0tmp += j * pixelPro[j];
}
else //前景部分
{
//以i为阈值分类,第二类总的概率
w1 += pixelPro[j];
u1tmp += j * pixelPro[j];
}
}
u0 = u0tmp / w0; //第一类的平均灰度
u1 = u1tmp / w1; //第二类的平均灰度
u = u0tmp + u1tmp; //整幅图像的平均灰度
//计算类间方差
deltaTmp = w0 * (u0 - u)*(u0 - u) + w1 * (u1 - u)*(u1 - u);
//找出最大类间方差以及对应的阈值
if (deltaTmp > deltaMax)
{
deltaMax = deltaTmp;
threshold = i;
}
}
//返回最佳阈值;
return threshold;
}
int num = 0; // 图片编号
//对读取的图片尽心处理
void linshiImg(string path)
{
num++;
Mat img = imread(path, 0);
Mat thresImg;
IplImage img2 = img;
int threshold2 = otsu(&img2);
// 若处理效果不理想,可直接将 threshold2 改为固定值,如:120、150等进行测试;
threshold(img, thresImg,threshold2, 255, CV_THRESH_BINARY);
String path2 = "D:\\11_" + to_string(num) + ".png"; //设置存储图片的地址及名称
imwrite(path2, thresImg);
}
int main()
{
vector<string> temp;
// 指定读取的目录及图片类型
getAllFiles("D:\\img3", temp, ".jpg");
//视频切割
clock_t start, finish;
start = clock();
for (int i = 0; i < temp.size(); i++)
{
// cout << temp[i] << endl;
linshiImg(temp[i]);
}
}