#include <time.h> #include<iostream> #include <sstream> #include <string> #include <vector> #include <algorithm>
#ifdef linux #include <unistd.h> #include <dirent.h> #endif #ifdef _WIN32 #include <direct.h> #include <Windows.h> #include <io.h> #endif
#include <facesdk.h> #include <opencv2/opencv.hpp> using namespace std;
#define OUTPUTMAXSIZE 384
float face_quality(const Image& image, const Face& face);
int GetFilesInDirectory(std::vector<string> &out, const string &directory) { if ((&directory) == nullptr || directory.length() == 0)return -1; HANDLE dir; WIN32_FIND_DATA file_data;
if ((dir = FindFirstFile((directory + "/*").c_str(), &file_data)) == INVALID_HANDLE_VALUE) return -1;
do { const string file_name = file_data.cFileName; const bool is_directory = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
if (file_name[0] == '.') continue; if (file_name.length() < 5) continue;
string file_ext = &file_data.cFileName[file_name.length() - 3]; if (file_ext[0] >= 'A' && file_ext[0] <= 'Z') file_ext[0] += 'a' - 'A'; if (file_ext[1] >= 'A' && file_ext[1] <= 'Z') file_ext[1] += 'a' - 'A'; if (file_ext[2] >= 'A' && file_ext[2] <= 'Z') file_ext[2] += 'a' - 'A';
if (0 == strcmp(&file_ext[0], "jpg") || 0 == strcmp(&file_ext[0], "png") || 0 == strcmp(&file_ext[0], "bmp") ) { } else { continue; }
if (is_directory) continue;
out.push_back(file_name); } while (FindNextFile(dir, &file_data));
FindClose(dir); return out.size(); }
Rect ext_face_(int img_h, int img_w, Rect& f) { int min_len = std::min(img_h, img_w); int fw = f.width; int fh = f.height; int ext_dist = 2 / 5.0 * fw - (fw > 16 ? 4 : 0); int ext_len = std::min(fw + 2 * ext_dist, min_len);
Rect ret = { 0 };
ret.x = std::max(0, f.x - ext_dist); ret.y = std::max(0, f.y - ext_dist); ret.width = (std::min(img_w - ret.x, ext_len))&~3; ret.height = (std::min(img_h - ret.y, ext_len))&~3; cout << "没下巴裁剪后左上顶点" << ret.x << " " << ret.y << "没下巴裁剪后右上顶点" << ret.x + ret.width << " " << ret.y << endl; cout << "没下巴裁剪后左下顶点" << ret.x << " " << ret.y + ret.height << "没下巴裁剪后右下顶点" << ret.x + ret.width << " " << ret.y + ret.height << endl; if ((ret.y + fh/ 2+ext_dist)>(ret.height-fh/2-ext_dist))
{ ret.x = std::max(0, f.x - ext_dist); ret.y = std::max(0, f.y - ext_dist); ret.width = (std::min(img_w - ret.x, fw + 2 * ext_dist))&~3; ret.height = (std::min(img_h - ret.y, fw + 2 * ext_dist))&~3;
cout << "裁剪前人脸左上" << f.x << " " << f.y << "裁剪前人脸右上" << f.x + fw << " " << f.y << endl; cout << "裁剪前左下" << f.x << " " << f.y + fh << "裁剪前右下" << f.x + fw << " " << f.y + fh << endl; cout << "裁剪后左上顶点" << ret.x << " " << ret.y << "裁剪后右上顶点" << ret.x + ret.width << " " << ret.y << endl; cout << "裁剪后左下顶点" << ret.x << " " << ret.y + ret.height << "裁剪后右下顶点" << ret.x + ret.width << " " << ret.y + ret.height << endl; }
return ret;
} void cut_one_image(IFaceDetector* detector, IFaceMatcher* matcher, const char* src_path, const char* dst_path, const char* failed_path = nullptr) { cv::Mat img = cv::imread(src_path); struct Image m_img; m_img.data = (char *)img.data; m_img.height = img.rows; m_img.width = img.cols; m_img.format = IMAGE_FORMAT_BGR; Face face; int ret = detector->DoDetect(m_img, NULL, face); if (ret != 1) { printf("[E] Cannot detect face! file: %s\n", src_path); if (failed_path != nullptr)cv::imwrite(failed_path, img); return; } float feature[2048]; bool r = matcher->ExtractFeature(m_img, face, (char*)feature, 2048); ErrorCode err = matcher->LastError(); float nm = feature[256]; printf("feature norm:%f\t", nm); float score = face_quality(m_img, face);
if (nm < 12) { score = 15 + nm * 0.01; }
if (score < 70) { if (score < 12) { printf("[E!!!] Face Quality is too low! score:%f[eyes distance must big than 55]\t file:%s\t", score, src_path); } else if (score < 15) { printf("[E!!!] Face Quality is too low! score:%f[blur value must big than 30]\t file:%s\t", score, src_path); } else if (score < 17) { printf("[E!!!] Face Quality is too low! score:%f[face feature norm must big than 12]\t file:%s\t", score, src_path); } else { printf("[E!!!] Face Quality is too low! score:%f[pose score must big than 70]\t file:%s\t", score, src_path); } if (failed_path != nullptr) { printf("move to %s\n", failed_path); cv::imwrite(failed_path, img); } else { printf("\n"); } return; } Rect f = ext_face_(img.rows, img.cols, face.region); cv::Mat dst = img(cv::Rect(f.x, f.y, f.width, f.height)); if (f.width < OUTPUTMAXSIZE) { cv::imwrite(dst_path, dst); } else { cv::Mat dst2; cv::resize(dst, dst2, cv::Size(OUTPUTMAXSIZE, OUTPUTMAXSIZE)); cv::imwrite(dst_path, dst2); } } int main(int argc, char** argv) { const char* inp_dir = nullptr; const char* out_dir = nullptr; const char* err_dir = nullptr; printf("Version:1.0\nBuilt Date:%s\n", __DATE__); printf("Support:jpg,bmp,png\n"); printf("Usage: %s[input_dir][output_dir][failed_dir]\n", argv[0]); printf("=========================================================\n"); #if 1 if (argc > 1)inp_dir = argv[1]; else inp_dir = "Input"; if (argc > 2)out_dir = argv[2]; else out_dir = "Output"; if (argc > 3)err_dir = argv[3]; else err_dir = "Error"; IFaceDetector* detector = Create(IFaceDetector::DETECTOR_MODE_NORMAL); IFaceMatcher* matcher = Create(IFaceMatcher::TVT_MATCHER_MODE_19V101_NORMAL); detector->Init(NULL, NULL); matcher->Init(NULL, NULL); vector<string> files; int fcnt = GetFilesInDirectory(files, inp_dir); if (fcnt < 0) { return 0; } CreateDirectory(out_dir, NULL); CreateDirectory(err_dir, NULL); int i = 0; for (auto file_name : files) { i++; printf("\n=========Processing %d%% [%d of %d]:%s==========\n", i * 100 / fcnt, i, fcnt, file_name.c_str()); string src = inp_dir; src += "/" + file_name; string dst = out_dir; dst += "/" + file_name; if (err_dir != nullptr) { string failed = err_dir; failed += "/" + file_name; cut_one_image(detector, matcher, src.c_str(), dst.c_str(), failed.c_str()); } else { cut_one_image(detector, matcher, src.c_str(), dst.c_str()); } } Destroy(detector); Destroy(matcher); #endif system("pause"); return 0; }
|