2017-11-03

#include <iostream>
#include <fstream>
#include <opencv2/opencv.hpp>
#include "Tools.h"
#include "ResourceManager.h"
#include "RobustMatcher.h"

using namespace cv;
using namespace std;

#define DEFAULT_IDCARD_WIDTH 655
#define DEFAULT_IDCARD_HEIGHT 413

#define FIX_IDCARD_SIZE Size(DEFAULT_IDCARD_WIDTH,DEFAULT_IDCARD_HEIGHT)

static Mat image_template_xingming;
static Mat image_template_haoma;
static Mat image_template_xingbie;
static Mat image_template_minzu;
static Mat image_template_chusheng;
static Mat image_template_zhuzhi;
static Mat image_template_gongmin;
static Mat image_template_shenfen;

//////////////////////////////////////////
static Mat image_template_guohui;
static Mat image_template_zhong;
static Mat image_template_guo;
static Mat image_template_ju;
static Mat image_template_zheng;
static Mat image_template_qianfa;
static Mat image_template_jiguan;
static Mat image_template_youxiao;
static Mat image_template_qixian;

Mat equalizeIntensityHist(const Mat &inputImage) {
if (inputImage.channels() >= 3) {
Mat ycrcb;
cvtColor(inputImage, ycrcb, COLOR_BGR2YCrCb);
vector<Mat> channels;
split(ycrcb, channels);
equalizeHist(channels[0], channels[0]);
Mat result;
merge(channels, ycrcb);
cvtColor(ycrcb, result, COLOR_YCrCb2BGR);
return result;
}
return Mat();
}

void LSDLines(cv::Mat &image, cv::Mat &gray, vector<vector<cv::Vec4i>> &lines) {
const double THETA = 40.0 / 180;
const int LINENUM = 8;
// lines[0] 上
// lines[1] 下
// lines[2] 左
// lines[3] 右
lines.clear();
//
// cv::imwrite("d:\\test1234.jpg", dilated_edges);
vector<cv::Vec4i> tmplines;
cv::Ptr<cv::LineSegmentDetector> detector = cv::createLineSegmentDetector(cv::LSD_REFINE_NONE, 0.8, 0.6, 1.5, 40);
//cv::Ptr<cv::LineSegmentDetector> detector = cv::createLineSegmentDetector(cv::LSD_REFINE_NONE, 0.8, 0.6, 1.5, 23.5);
detector->detect(gray, tmplines);

//根据直线位置分成四个区域的直线
vector<cv::Vec4i> ups;
vector<cv::Vec4i> downs;
vector<cv::Vec4i> lefts;
vector<cv::Vec4i> rights;
for (size_t i = 0; i < tmplines.size(); ++i) {
cv::Vec4i &line = tmplines[i];

// if (line[0] == 0 || line[1] == 0 || line[2] == 0 || line[3] == 0) {
// continue;
// }

//cv::line(gray, cv::Point(line[0], line[1]), cv::Point(line[2], line[3]), cv::Scalar(255 * (i <= 1), 0, 255 * (i>1)), 1, CV_AA);
int detaX = abs(line[0] - line[2]);
int detaY = abs(line[1] - line[3]);


if (detaX > detaY && atan(1.0 * detaY / detaX) < THETA)// "水平方向"
{
if (std::max(line[1], line[3]) < gray.rows / 3) {
ups.push_back(line);
continue;
}
if (std::max(line[1], line[3]) > gray.rows * 2 / 3) {
downs.push_back(line);
continue;
}
}
if (detaX < detaY && atan(1.0 * detaX / detaY) < THETA) {
if (std::max(line[0], line[2]) < gray.cols / 4) {
lefts.push_back(line);
continue;
}
if (std::max(line[0], line[2]) > gray.cols * 3 / 4) {
rights.push_back(line);
continue;
}
}
}
////过滤短直线
//if (tmplines.size() > LINENUM){
// sort(tmplines.begin(), tmplines.end(), [](cv::Vec4i&line1, cv::Vec4i& line2){ \
// return (pow(abs(line1[0] - line1[2]), 2) + pow(abs(line1[1] - line1[3]), 2)) > \
// (pow(abs(line2[0] - line2[2]), 2) + pow(abs(line2[1] - line2[3]), 2));});
// vector<cv::Vec4i> ttmplines;
// //ttmplines.swap(tmplines);
// int linenum = std::min(LINENUM, static_cast<int>(ttmplines.size() * 0.2));
// tmplines.clear();
// tmplines.insert(tmplines.begin(),ttmplines.begin(), ttmplines.begin() + linenum);
// //tmplines.insert(ttmplines.begin(), ttmplines.begin() + linenum);
//}
auto removeshortline = [&LINENUM](vector<cv::Vec4i> &lines) {
if (lines.size() < LINENUM) return;
vector<cv::Vec4i> tmplines;
tmplines.swap(lines);
sort(tmplines.begin(), tmplines.end(), [](cv::Vec4i &line1, cv::Vec4i &line2) {
\
return (pow(abs(line1[0] - line1[2]), 2) + pow(abs(line1[1] - line1[3]), 2)) > \
(pow(abs(line2[0] - line2[2]), 2) + pow(abs(line2[1] - line2[3]), 2));
});

lines.insert(lines.begin(), tmplines.begin(), tmplines.begin() + LINENUM);

};
removeshortline(ups);
lines.push_back(ups);
removeshortline(downs);
lines.push_back(downs);
removeshortline(lefts);
lines.push_back(lefts);
removeshortline(rights);
lines.push_back(rights);

// for (auto l:ups) {
// line(image, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255));
// }
// for (auto l:downs) {
// line(image, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255));
// }
// for (auto l:lefts) {
// line(image, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255));
// }
// for (auto l:rights) {
// line(image, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255));
// }
// cv::imwrite("d:\\test123.jpg", image);
}

void mergeLines(vector<vector<cv::Vec4i>> &lines, vector<cv::Vec4i> &edges) {
for (size_t i = 0; i < lines.size(); ++i) {
cv::Vec4i edge;
Tools::MergeLines(lines[i], edge, static_cast<int>(i >= 2));
edges.push_back(edge);
}
}

void detect(cv::Mat &image, vector<cv::Vec4i> &edges) {
edges.clear();
// edges[0] 上
// edges[1] 下
// edges[2] 左
// edges[3] 右
Mat gray;

GaussianBlur(image, image, cv::Size(3, 3), 0, 0);
//image = equalizeIntensityHist(image);

if (image.channels() != 1) {
cvtColor(image, gray, CV_BGR2GRAY);
} else {
gray = image.clone();
}

equalizeHist(gray, gray);

//边缘增强
// cv::Mat gray_x, gray_y;
// cv::Sobel(gray, gray_x, CV_16S, 1, 0, 3);
// gray_x = cv::abs(gray_x);
// gray_x.convertTo(gray_x, CV_8U);
// cv::Sobel(gray, gray_y, CV_16S, 0, 1, 3);
// gray_y = cv::abs(gray_y);
// gray_y.convertTo(gray_y, CV_8U);
// cv::add(gray, gray_x, gray);
// cv::add(gray, gray_y, gray);
// cv::Mat blurMat, blurMat16;
// cv::GaussianBlur(gray, blurMat, cv::Size(3, 3), 0, 0);
// cv::Laplacian(blurMat, blurMat16, CV_16S);
// blurMat16 = cv::abs(blurMat16);
// blurMat16.convertTo(blurMat, CV_8U);
// cv::add(gray, blurMat, gray);

vector<vector<cv::Vec4i>> lines;
LSDLines(image, gray, lines);
if (lines.size() != 4) return;
mergeLines(lines, edges);

gray.release();
}

Point2f computeIntersect(cv::Vec4i a,
cv::Vec4i b) {
int x1 = a[0], y1 = a[1], x2 = a[2], y2 = a[3], x3 = b[0], y3 = b[1], x4 = b[2], y4 = b[3];
float denom;

if (float d = ((float) (x1 - x2) * (y3 - y4)) - ((y1 - y2) * (x3 - x4))) {
cv::Point2f pt;
pt.x = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d;
pt.y = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d;
return pt;
} else
return cv::Point2f(-1, -1);
}

double angle(cv::Point pt1, cv::Point pt2, cv::Point pt0) {
double dx1 = pt1.x - pt0.x;
double dy1 = pt1.y - pt0.y;
double dx2 = pt2.x - pt0.x;
double dy2 = pt2.y - pt0.y;
return (dx1 * dx2 + dy1 * dy2) / sqrt((dx1 * dx1 + dy1 * dy1) * (dx2 * dx2 + dy2 * dy2) + 1e-10);
}

void find_squares(Mat &image, vector<vector<Point> > &squares) {
squares.clear();
Mat pyr, timg, gray0(image.size(), CV_8U), gray;
// karlphillip: dilate the image so this technique can detect the white square,
Mat blurred(image);
dilate(blurred, blurred, Mat(), Point(-1, -1), 3, 1, 1);
//
// //边缘增强
cv::Mat gray_x, gray_y;
cv::Sobel(blurred, gray_x, CV_16S, 1, 0, 3);
gray_x = cv::abs(gray_x);
gray_x.convertTo(gray_x, CV_8U);
cv::Sobel(blurred, gray_y, CV_16S, 0, 1, 3);
gray_y = cv::abs(gray_y);
gray_y.convertTo(gray_y, CV_8U);
cv::add(blurred, gray_x, blurred);
cv::add(blurred, gray_y, blurred);
cv::Mat blurMat, blurMat16;
cv::GaussianBlur(blurred, blurMat, cv::Size(3, 3), 0, 0);
cv::Laplacian(blurMat, blurMat16, CV_16S);
blurMat16 = cv::abs(blurMat16);
blurMat16.convertTo(blurMat, CV_8U);
cv::add(blurred, blurMat, blurred);
//

// // then blur it so that the ocean/sea become one big segment to avoid detecting them as 2 big squares.
// medianBlur(blurred, blurred, 3);
// // down-scale and upscale the image to filter out the noise
// pyrDown(blurred, pyr, Size(blurred.cols / 2, blurred.rows / 2));
// pyrUp(pyr, timg, blurred.size());

blurred = equalizeIntensityHist(blurred);

//imwrite("blurred.jpg", blurred);

vector<vector<Point> > contours;

// find squares in the first color plane.
for (int c = 0; c < 3; c++) {
int ch[] = {c, 0};
mixChannels(&blurred, 1, &gray0, 1, ch, 1);

// try several threshold levels
const int threshold_level = 60;
for (int l = 0; l < threshold_level; l++) {
// Use Canny instead of zero threshold level!
// Canny helps to catch squares with gradient shading
if (l == 0) {
Canny(gray0, gray, 0, 254, 3); //

// Dilate helps to remove potential holes between edge segments
dilate(gray, gray, Mat(), Point(-1, -1));
} else {
gray = gray0 >= (l + 1) * 255 / threshold_level;
}

// Find contours and store them in a list
findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);

// Test contours
vector<Point> approx;
for (size_t i = 0; i < contours.size(); i++) {
// approximate contour with accuracy proportional
// to the contour perimeter
approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true) * 0.08, true);
// Note: absolute value of an area is used because
// area may be positive or negative - in accordance with the
// contour orientation
//isContourConvex(Mat(approx)
//approx.size() == 4
//approx.size() >= 4 && approx.size() <=6
if (approx.size() == 4 && isContourConvex(Mat(approx)) &&
fabs(contourArea(Mat(approx))) > gray.rows * gray.cols * 0.1) {
double maxCosine = 0;

squares.push_back(approx);
// for (int j = 2; j < 5; j++) {
// double cosine = fabs(angle(approx[j % 4], approx[j - 2], approx[j - 1]));
// maxCosine = MAX(maxCosine, cosine);
// }
//
// if (maxCosine < 0.18) {
// squares.push_back(approx);
// }
}
}
}
}
}

void draw_squares(Mat &img, vector<vector<Point> > squares) {
for (int i = 0; i < squares.size(); i++) {
for (int j = 0; j < squares[i].size(); j++) {
cv::line(img, squares[i][j], squares[i][(j + 1) % 4], cv::Scalar(0, 0, 255), 1, CV_AA);
}
}
}

double angle(cv::Point pt0, cv::Point pt1) {
double dx1 = pt1.x - pt0.x;
double dy1 = pt1.y - pt0.y;
return abs(dy1 / dx1);
}

Mat whiteBalance(const Mat &source) {
Mat result;
vector<Mat> g_vChannels;
//分离通道
split(source, g_vChannels);
Mat imageBlueChannel = g_vChannels[0];
Mat imageGreenChannel = g_vChannels[1];
Mat imageRedChannel = g_vChannels[2];

double imageBlueChannelAvg = 0;
double imageGreenChannelAvg = 0;
double imageRedChannelAvg = 0;

//求各通道的平均值
imageBlueChannelAvg = mean(imageBlueChannel)[0];
imageGreenChannelAvg = mean(imageGreenChannel)[0];
imageRedChannelAvg = mean(imageRedChannel)[0];

//求出个通道所占增益
double K = (imageRedChannelAvg + imageGreenChannelAvg + imageRedChannelAvg) / 3;
double Kb = K / imageBlueChannelAvg;
double Kg = K / imageGreenChannelAvg;
double Kr = K / imageRedChannelAvg;

//更新白平衡后的各通道BGR值
addWeighted(imageBlueChannel, Kb, 0, 0, 0, imageBlueChannel);
addWeighted(imageGreenChannel, Kg, 0, 0, 0, imageGreenChannel);
addWeighted(imageRedChannel, Kr, 0, 0, 0, imageRedChannel);

merge(g_vChannels, result);//图像各通道合并
return result;
}

bool findIDCard(Mat &imageRoi) {
int foundCount1 = 0;
int foundCount2 = 0;
int foundCount3 = 0;
//int foundCount4 = 0;
int foundCount5 = 0;
Mat src = imageRoi.clone();
cvtColor(imageRoi, imageRoi, COLOR_BGR2GRAY);
cv::GaussianBlur(imageRoi, imageRoi, Size(3, 3), 0);

resize(imageRoi, imageRoi, FIX_IDCARD_SIZE);
resize(src, src, FIX_IDCARD_SIZE);
//resize(image_template_xingming, image_template_xingming, FIX_TEMPLATE_SIZE2);

image_template_xingming = ResourceManager::getInstance().image_template_xingming;
image_template_haoma = ResourceManager::getInstance().image_template_haoma;
image_template_xingbie = ResourceManager::getInstance().image_template_xingbie;
image_template_minzu = ResourceManager::getInstance().image_template_minzu;
image_template_chusheng = ResourceManager::getInstance().image_template_chusheng;
image_template_zhuzhi = ResourceManager::getInstance().image_template_zhuzhi;
image_template_gongmin = ResourceManager::getInstance().image_template_gongmin;
image_template_shenfen = ResourceManager::getInstance().image_template_shenfen;
// image_template_nian = ResourceManager::getInstance().image_template_nian;
// image_template_yue = ResourceManager::getInstance().image_template_yue;
// image_template_ri = ResourceManager::getInstance().image_template_ri;

int xOffsetMax = 60;
int yOffsetMax = 60;

////////////姓名/////////////
Mat image_matched;
matchTemplate(imageRoi, image_template_xingming, image_matched, TM_CCOEFF_NORMED);

static Point xingming_point = ResourceManager::getInstance().xingming_point;
double minVal, maxVal;
Point minPt, maxPt;
minMaxLoc(image_matched, &minVal, &maxVal, &minPt, &maxPt);
double minMatchQuality = 0.7;
if (maxVal > minMatchQuality && (abs(maxPt.x - xingming_point.x) < xOffsetMax) &&
(abs(maxPt.y - xingming_point.y) < yOffsetMax)) {
// rectangle(src,
// Rect(maxPt.x, maxPt.y, image_template_xingming.cols,
// image_template_xingming.rows),
// 255);

foundCount1++;
}

if (foundCount1 == 0) {
return false;
}

///////////////////性别/////////////////
static Point xingbie_point = ResourceManager::getInstance().xingbie_point;
matchTemplate(imageRoi, image_template_xingbie, image_matched, TM_CCOEFF_NORMED);
minMaxLoc(image_matched, &minVal, &maxVal, &minPt, &maxPt);
if (maxVal > minMatchQuality && (abs(maxPt.x - xingbie_point.x) < xOffsetMax) &&
(abs(maxPt.y - xingbie_point.y) < yOffsetMax)) {
// rectangle(src,
// Rect(maxPt.x, maxPt.y, image_template_xingbie.cols, image_template_xingbie.rows),
// 255);
foundCount2++;
}

if (foundCount2 == 0) {
///////////////////民族/////////////////
Point minzu_point = ResourceManager::getInstance().minzu_point;
matchTemplate(imageRoi, image_template_minzu, image_matched, TM_CCOEFF_NORMED);
minMaxLoc(image_matched, &minVal, &maxVal, &minPt, &maxPt);
if (maxVal > minMatchQuality && (abs(maxPt.x - minzu_point.x) < xOffsetMax) &&
(abs(maxPt.y - minzu_point.y) < yOffsetMax)) {
// rectangle(src,
// Rect(maxPt.x, maxPt.y, image_template_minzu.cols, image_template_minzu.rows),
// 255);
foundCount2++;
}
}

if (foundCount2 == 0) {
return false;
}

///////////////////出生/////////////////
Point chusheng_point = ResourceManager::getInstance().chusheng_point;
matchTemplate(imageRoi, image_template_chusheng, image_matched, TM_CCOEFF_NORMED);
minMaxLoc(image_matched, &minVal, &maxVal, &minPt, &maxPt);
if (maxVal > minMatchQuality && (abs(maxPt.x - chusheng_point.x) < xOffsetMax) &&
(abs(maxPt.y - chusheng_point.y) < yOffsetMax)) {
// rectangle(src,
// Rect(maxPt.x, maxPt.y, image_template_chusheng.cols,
// image_template_chusheng.rows),
// 255);
foundCount3++;
}

if (foundCount3 == 0) {
///////////////////住址/////////////////
Point zhuzhi_point = ResourceManager::getInstance().zhuzhi_point;
matchTemplate(imageRoi, image_template_zhuzhi, image_matched, TM_CCOEFF_NORMED);
minMaxLoc(image_matched, &minVal, &maxVal, &minPt, &maxPt);
if (maxVal > minMatchQuality && (abs(maxPt.x - zhuzhi_point.x) < xOffsetMax) &&
(abs(maxPt.y - zhuzhi_point.y) < yOffsetMax)) {
// rectangle(src,
// Rect(maxPt.x, maxPt.y, image_template_zhuzhi.cols,
// image_template_zhuzhi.rows),
// 255);
foundCount3++;
}

/* if (foundCount3 == 0) {
///////////////////年/////////////////
Point nian_point = ResourceManager::getInstance().nian_point;
matchTemplate(imageRoi, image_template_nian, image_matched, TM_CCOEFF_NORMED);
minMaxLoc(image_matched, &minVal, &maxVal, &minPt, &maxPt);
if (maxVal > minMatchQuality && (abs(maxPt.x - nian_point.x) < xOffsetMax) &&
(abs(maxPt.y - nian_point.y) < yOffsetMax)) {
// rectangle(src,
// Rect(maxPt.x, maxPt.y, image_template_nian.cols,
// image_template_nian.rows),
// 255);
foundCount3++;
}
if (foundCount3 == 0) {
///////////////////月/////////////////
Point yue_point = ResourceManager::getInstance().yue_point;
matchTemplate(imageRoi, image_template_yue, image_matched, TM_CCOEFF_NORMED);
minMaxLoc(image_matched, &minVal, &maxVal, &minPt, &maxPt);
if (maxVal > minMatchQuality && (abs(maxPt.x - yue_point.x) < xOffsetMax) &&
(abs(maxPt.y - yue_point.y) < yOffsetMax)) {
// rectangle(src,
// Rect(maxPt.x, maxPt.y, image_template_yue.cols,
// image_template_yue.rows),
// 255);
foundCount3++;
}

if (foundCount3 == 0) {
///////////////////日/////////////////
Point ri_point = ResourceManager::getInstance().ri_point;
matchTemplate(imageRoi, image_template_ri, image_matched, TM_CCOEFF_NORMED);
minMaxLoc(image_matched, &minVal, &maxVal, &minPt, &maxPt);
if (maxVal > minMatchQuality && (abs(maxPt.x - ri_point.x) < xOffsetMax) &&
(abs(maxPt.y - ri_point.y) < yOffsetMax)) {
// rectangle(src,
// Rect(maxPt.x, maxPt.y, image_template_ri.cols,
// image_template_ri.rows),
// 255);
foundCount3++;
}
}
}
}*/

}

if (foundCount3 == 0) {
return false;
}

///////////////////号码/////////////////
Point haoma_point = ResourceManager::getInstance().haoma_point;
matchTemplate(imageRoi, image_template_haoma, image_matched, TM_CCOEFF_NORMED);
minMaxLoc(image_matched, &minVal, &maxVal, &minPt, &maxPt);
if (maxVal > minMatchQuality && (abs(maxPt.x - haoma_point.x) < xOffsetMax) &&
(abs(maxPt.y - haoma_point.y) < yOffsetMax)) {
// rectangle(src,
// Rect(maxPt.x, maxPt.y, image_template_haoma.cols, image_template_haoma.rows),
// 255);
foundCount5++;
//切割号码
// Rect rect = Rect(maxPt.x + image_template_haoma.cols + 10, maxPt.y - 5,
// imageRoi.cols - (maxPt.x + image_template_haoma.cols) - 20,
// image_template_haoma.rows + 10);
// imwrite("/sdcard/id_num.jpg", src(rect));
}

if (foundCount5 == 0) {
///////////////////公民/////////////////
Point gongmin_point = ResourceManager::getInstance().gongmin_point;
matchTemplate(imageRoi, image_template_gongmin, image_matched, TM_CCOEFF_NORMED);
minMaxLoc(image_matched, &minVal, &maxVal, &minPt, &maxPt);
if (maxVal > minMatchQuality && (abs(maxPt.x - gongmin_point.x) < xOffsetMax) &&
(abs(maxPt.y - gongmin_point.y) < yOffsetMax)) {
// rectangle(src,
// Rect(maxPt.x, maxPt.y, image_template_gongmin.cols,
// image_template_gongmin.rows),
// 255);
foundCount5++;
}
if (foundCount5 == 0) {
///////////////////身份/////////////////
Point shenfen_point = ResourceManager::getInstance().shenfen_point;
matchTemplate(imageRoi, image_template_shenfen, image_matched, TM_CCOEFF_NORMED);
minMaxLoc(image_matched, &minVal, &maxVal, &minPt, &maxPt);
if (maxVal > minMatchQuality && (abs(maxPt.x - shenfen_point.x) < xOffsetMax) &&
(abs(maxPt.y - shenfen_point.y) < yOffsetMax)) {
// rectangle(src,
// Rect(maxPt.x, maxPt.y, image_template_shenfen.cols,
// image_template_shenfen.rows),
// 255);
foundCount5++;
}
}
}

if (foundCount5 == 0) {
return false;
}

//imwrite(ResourceManager::getInstance().ConfigDirPath + "output_front.jpg", src);
return true;
}

bool findIDCard_Back(Mat &imageRoi) {
int foundBottomCount1 = 0;
int foundBottomCount2 = 0;
int foundLeftCount = 0;
int foundRightCount = 0;
Mat src = imageRoi.clone();
cvtColor(imageRoi, imageRoi, COLOR_BGR2GRAY);
cv::GaussianBlur(imageRoi, imageRoi, Size(3, 3), 0);

// static Mat image_template_guohui = ResourceManager::getInstance().image_template_guohui;
// static Mat image_template_zhong = ResourceManager::getInstance().image_template_zhong;
// static Mat image_template_guo = ResourceManager::getInstance().image_template_guo;
// static Mat image_template_ju = ResourceManager::getInstance().image_template_ju;
// static Mat image_template_zheng = ResourceManager::getInstance().image_template_zheng;
// static Mat image_template_qianfa = ResourceManager::getInstance().image_template_qianfa;
// static Mat image_template_jiguan = ResourceManager::getInstance().image_template_jiguan;
// static Mat image_template_youxiao = ResourceManager::getInstance().image_template_youxiao;
// static Mat image_template_qixian = ResourceManager::getInstance().image_template_qixian;

image_template_guohui = ResourceManager::getInstance().image_template_guohui;
image_template_zhong = ResourceManager::getInstance().image_template_zhong;
image_template_guo = ResourceManager::getInstance().image_template_guo;
image_template_ju = ResourceManager::getInstance().image_template_ju;
image_template_zheng = ResourceManager::getInstance().image_template_zheng;
image_template_qianfa = ResourceManager::getInstance().image_template_qianfa;
image_template_jiguan = ResourceManager::getInstance().image_template_jiguan;
image_template_youxiao = ResourceManager::getInstance().image_template_youxiao;
image_template_qixian = ResourceManager::getInstance().image_template_qixian;

int xOffsetMax = 25;
int yOffsetMax = 20;

resize(imageRoi, imageRoi, FIX_IDCARD_SIZE);
resize(src, src, FIX_IDCARD_SIZE);

////////////国徽/////////////
Mat image_matched;
matchTemplate(imageRoi, image_template_guohui, image_matched, TM_CCOEFF_NORMED);

Point guohui_point = ResourceManager::getInstance().guohui_point;
double minVal, maxVal;
Point minPt, maxPt;
minMaxLoc(image_matched, &minVal, &maxVal, &minPt, &maxPt);
double minMatchQuality = 0.7;
if (maxVal > minMatchQuality && (abs(maxPt.x - guohui_point.x) < xOffsetMax) &&
(abs(maxPt.y - guohui_point.y) < yOffsetMax)) {
// rectangle(src,
// Rect(maxPt.x, maxPt.y, image_template_guohui.cols, image_template_guohui.rows),
// 255);

foundLeftCount++;
}

if (foundLeftCount == 0) {
///////////////////中/////////////////
Point zhong_point = ResourceManager::getInstance().zhong_point;
matchTemplate(imageRoi, image_template_zhong, image_matched, TM_CCOEFF_NORMED);
minMaxLoc(image_matched, &minVal, &maxVal, &minPt, &maxPt);
if (maxVal > minMatchQuality && (abs(maxPt.x - zhong_point.x) < xOffsetMax) &&
(abs(maxPt.y - zhong_point.y) < yOffsetMax)) {
// rectangle(src,
// Rect(maxPt.x, maxPt.y, image_template_zhong.cols, image_template_zhong.rows),
// 255);
foundLeftCount++;
}

if (foundLeftCount == 0) {
///////////////////居/////////////////
Point ju_point = ResourceManager::getInstance().ju_point;
matchTemplate(imageRoi, image_template_ju, image_matched, TM_CCOEFF_NORMED);
minMaxLoc(image_matched, &minVal, &maxVal, &minPt, &maxPt);
if (maxVal > minMatchQuality && (abs(maxPt.x - ju_point.x) < xOffsetMax) &&
(abs(maxPt.y - ju_point.y) < yOffsetMax)) {
// rectangle(src,
// Rect(maxPt.x, maxPt.y, image_template_ju.cols, image_template_ju.rows),
// 255);
foundLeftCount++;
}
}
}

if (foundLeftCount == 0) {
return false;
}
///////////////////国/////////////////
Point guo_point = ResourceManager::getInstance().guo_point;
matchTemplate(imageRoi, image_template_guo, image_matched, TM_CCOEFF_NORMED);
minMaxLoc(image_matched, &minVal, &maxVal, &minPt, &maxPt);
if (maxVal > minMatchQuality && (abs(maxPt.x - guo_point.x) < xOffsetMax) &&
(abs(maxPt.y - guo_point.y) < yOffsetMax)) {
// rectangle(src,
// Rect(maxPt.x, maxPt.y, image_template_guo.cols, image_template_guo.rows),
// 255);
foundRightCount++;
}

if (foundRightCount == 0) {
///////////////////证/////////////////
Point zheng_point = ResourceManager::getInstance().zheng_point;
matchTemplate(imageRoi, image_template_zheng, image_matched, TM_CCOEFF_NORMED);
minMaxLoc(image_matched, &minVal, &maxVal, &minPt, &maxPt);
if (maxVal > minMatchQuality && (abs(maxPt.x - zheng_point.x) < xOffsetMax) &&
(abs(maxPt.y - zheng_point.y) < yOffsetMax)) {
// rectangle(src,
// Rect(maxPt.x, maxPt.y, image_template_zheng.cols, image_template_zheng.rows),
// 255);
foundRightCount++;
}
}

if (foundRightCount == 0) {
return false;
}
///////////////////签发/////////////////
Point pointFound1;
Point qianfa_point = ResourceManager::getInstance().qianfa_point;
matchTemplate(imageRoi, image_template_qianfa, image_matched, TM_CCOEFF_NORMED);
minMaxLoc(image_matched, &minVal, &maxVal, &minPt, &maxPt);
if (maxVal > minMatchQuality && (abs(maxPt.x - qianfa_point.x) < xOffsetMax) &&
(abs(maxPt.y - qianfa_point.y) < yOffsetMax)) {
// rectangle(src,
// Rect(maxPt.x, maxPt.y, image_template_qianfa.cols, image_template_qianfa.rows),
// 255);
foundBottomCount1++;
pointFound1 = maxPt;
}

if (foundBottomCount1 == 0) {
///////////////////机关/////////////////
Point jiguan_point = ResourceManager::getInstance().jiguan_point;
matchTemplate(imageRoi, image_template_jiguan, image_matched, TM_CCOEFF_NORMED);
minMaxLoc(image_matched, &minVal, &maxVal, &minPt, &maxPt);
if (maxVal > minMatchQuality && (abs(maxPt.x - jiguan_point.x) < xOffsetMax) &&
(abs(maxPt.y - jiguan_point.y) < yOffsetMax)) {
// rectangle(src,
// Rect(maxPt.x, maxPt.y, image_template_jiguan.cols,
// image_template_jiguan.rows),
// 255);
foundBottomCount1++;
pointFound1 = maxPt;
}
}

if (foundBottomCount1 == 0) {
return false;
}

///////////////////期限/////////////////
Point qixian_point = ResourceManager::getInstance().qixian_point;
matchTemplate(imageRoi, image_template_qixian, image_matched, TM_CCOEFF_NORMED);
minMaxLoc(image_matched, &minVal, &maxVal, &minPt, &maxPt);
if (maxVal > minMatchQuality && (abs(maxPt.x - qixian_point.x) < xOffsetMax) &&
(abs(maxPt.y - qixian_point.y) < yOffsetMax)) {
// rectangle(src,
// Rect(maxPt.x, maxPt.y, image_template_qixian.cols,
// image_template_qixian.rows),
// 255);
foundBottomCount2++;
}

if (foundBottomCount2 == 0) {
///////////////////有效/////////////////
Point youxiao_point = ResourceManager::getInstance().youxiao_point;
matchTemplate(imageRoi, image_template_youxiao, image_matched, TM_CCOEFF_NORMED);
minMaxLoc(image_matched, &minVal, &maxVal, &minPt, &maxPt);
if (maxVal > minMatchQuality && (abs(maxPt.x - youxiao_point.x) < xOffsetMax) &&
(abs(maxPt.y - youxiao_point.y) < yOffsetMax)) {
// rectangle(src,
// Rect(maxPt.x, maxPt.y, image_template_youxiao.cols,
// image_template_youxiao.rows),
// 255);
foundBottomCount2++;
}
}

if (foundBottomCount2 == 0) {
return false;
} else {
if (abs(maxPt.y - pointFound1.y) < 10) {
return false;
}
}

//imwrite(ResourceManager::getInstance().ConfigDirPath + "output_back.jpg", src);
return true;

}

// Copy this file from opencv/data/haarscascades to target folder
//string face_cascade_name = "haarcascade_eye.xml";
//string face_cascade_name = "haarcascade_frontalface_alt2.xml";
//CascadeClassifier face_cascade;

Mat rotateMat(Mat mat, int angle) {
if (angle == 0) {
return mat;
}

Mat M = getRotationMatrix2D(Point2f(mat.cols / 2, mat.rows / 2), angle, 0.9);
Mat rot_mat;
warpAffine(mat, rot_mat, M, Size(mat.cols, mat.rows), INTER_LINEAR);
return rot_mat;
}

// Function detectAndDisplay
//void detectAndDisplay(Mat frame) {
// std::vector<Rect> faces;
// Mat frame_gray;
// Mat crop;
//
// cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
// equalizeHist(frame_gray, frame_gray);
//
// Mat rotatedMat;
//
// for (int angle = 0; angle < 180; angle += 30) {
// rotatedMat = rotateMat(frame_gray, angle);
//
// // Detect faces
// face_cascade.detectMultiScale(rotatedMat, faces, 1.1, 4,
// 0 |
// CV_HAAR_DO_ROUGH_SEARCH,
// Size(30, 30));
//
// if (faces.size() < 1) {
// continue;
// }
//
// // Set Region of Interest
// cv::Rect roi_b;
// cv::Rect roi_c;
//
// size_t ic = 0; // ic is index of current element
// int ac = 0; // ac is area of current element
//
// size_t ib = 0; // ib is index of biggest element
// int ab = 0; // ab is area of biggest element
//
// std::cout << "* " << faces.size() << " faces were found." << angle << std::endl;
//
// for (ic = 0; ic < faces.size(); ic++) // Iterate through all current elements (detected faces)
// {
// roi_c.x = faces[ic].x;
// roi_c.y = faces[ic].y;
// roi_c.width = (faces[ic].width);
// roi_c.height = (faces[ic].height);
//
// ac = roi_c.width * roi_c.height; // Get the area of current element (detected face)
//
// roi_b.x = faces[ib].x;
// roi_b.y = faces[ib].y;
// roi_b.width = (faces[ib].width);
// roi_b.height = (faces[ib].height);
//
// ab = roi_b.width *
// roi_b.height; // Get the area of biggest element, at beginning it is same as "current" element
//
// if (ac > ab) {
// ib = ic;
// roi_b.x = faces[ib].x;
// roi_b.y = faces[ib].y;
// roi_b.width = (faces[ib].width);
// roi_b.height = (faces[ib].height);
// }
//
//// Point pt1(faces[ic].x, faces[ic].y); // Display detected faces on main window - live stream from camera
//// Point pt2((faces[ic].x + faces[ic].height), (faces[ic].y + faces[ic].width));
//// rectangle(frame, pt1, pt2, Scalar(0, 255, 0), 2, 8, 0);
//// imwrite("frame.jpg", frame);
// }
//
// if (roi_b.area() > 0) {
// frame = rotateMat(frame, angle);
// crop = frame(roi_b);
// //resize(crop, res, Size(128, 128), 0, 0, INTER_LINEAR); // This will be needed later while saving images
// //cvtColor(crop, gray, CV_BGR2GRAY); // Convert cropped image to Grayscale
//
// imwrite("face.jpg", crop);
// imwrite("frame.jpg", frame);
// return;
// }
// }
//
// for (int angle = -30; angle > -180; angle -= 30) {
// rotatedMat = rotateMat(frame_gray, angle);
//
// // Detect faces
// face_cascade.detectMultiScale(rotatedMat, faces, 1.1, 4,
// 0 |
// CV_HAAR_DO_ROUGH_SEARCH,
// Size(30, 30));
//
// if (faces.size() < 1) {
// continue;
// }
//
// // Set Region of Interest
// cv::Rect roi_b;
// cv::Rect roi_c;
//
// size_t ic = 0; // ic is index of current element
// int ac = 0; // ac is area of current element
//
// size_t ib = 0; // ib is index of biggest element
// int ab = 0; // ab is area of biggest element
//
// std::cout << "* " << faces.size() << " faces were found." << angle << std::endl;
//
// for (ic = 0; ic < faces.size(); ic++) // Iterate through all current elements (detected faces)
// {
// roi_c.x = faces[ic].x;
// roi_c.y = faces[ic].y;
// roi_c.width = (faces[ic].width);
// roi_c.height = (faces[ic].height);
//
// ac = roi_c.width * roi_c.height; // Get the area of current element (detected face)
//
// roi_b.x = faces[ib].x;
// roi_b.y = faces[ib].y;
// roi_b.width = (faces[ib].width);
// roi_b.height = (faces[ib].height);
//
// ab = roi_b.width *
// roi_b.height; // Get the area of biggest element, at beginning it is same as "current" element
//
// if (ac > ab) {
// ib = ic;
// roi_b.x = faces[ib].x;
// roi_b.y = faces[ib].y;
// roi_b.width = (faces[ib].width);
// roi_b.height = (faces[ib].height);
// }
//
//// Point pt1(faces[ic].x, faces[ic].y); // Display detected faces on main window - live stream from camera
//// Point pt2((faces[ic].x + faces[ic].height), (faces[ic].y + faces[ic].width));
//// rectangle(frame, pt1, pt2, Scalar(0, 255, 0), 2, 8, 0);
//// imwrite("frame.jpg", frame);
// }
//
// if (roi_b.area() > 0) {
// frame = rotateMat(frame, angle);
// crop = frame(roi_b);
// //resize(crop, res, Size(128, 128), 0, 0, INTER_LINEAR); // This will be needed later while saving images
// //cvtColor(crop, gray, CV_BGR2GRAY); // Convert cropped image to Grayscale
//
// imwrite("face.jpg", crop);
// imwrite("frame.jpg", frame);
// return;
// }
// }
//
//}

//对轮廓按面积降序排列
bool biggerSort(vector<Point> v1, vector<Point> v2) {
return contourArea(v1) > contourArea(v2);
}

//对轮廓按面积升序排列
bool smallerSort(vector<Point> v1, vector<Point> v2) {
return contourArea(v1) < contourArea(v2);
}

void removeBigRect(vector<vector<Point>> &rects) {
vector<vector<Point>> tmpRects;
tmpRects.swap(rects);
sort(tmpRects.begin(), tmpRects.end(), smallerSort);
if(tmpRects.size() > 6) {
rects.insert(rects.begin(), tmpRects.begin(), tmpRects.begin() + 6);
}
else
{
rects.insert(rects.begin(), tmpRects.begin(), tmpRects.end());
}
}

int main(int argc, char *argv[]) {

if (argc < 2) {
return -1;
}

double t1 = (double) getTickCount();
remove((ResourceManager::getInstance().ConfigDirPath + "blurred.jpg").c_str());
remove((ResourceManager::getInstance().ConfigDirPath + "warpAffine.jpg").c_str());
remove((ResourceManager::getInstance().ConfigDirPath + "result.jpg").c_str());
remove((ResourceManager::getInstance().ConfigDirPath + "output_front.jpg").c_str());
remove((ResourceManager::getInstance().ConfigDirPath + "output_back.jpg").c_str());

fstream _file;
_file.open(argv[1], ios::in);
if(!_file)
{
//文件不存在
std::cout << "File '" << argv[1] << "' does not exist!" << std::endl;
return -1;
}
Mat inputSrc = imread(argv[1]);

int isBackSide = 0;
if (argc > 2) {
isBackSide = atoi(argv[2]);
}

double fScale = 1.0;
if (inputSrc.rows > inputSrc.cols) {
//竖拍
if (inputSrc.cols > 720) {
fScale = 720L / (double) inputSrc.cols; //缩放倍数
}
} else {
//横拍
if (inputSrc.cols > 960) {
fScale = 960L / (double) inputSrc.cols;
}
}

//Mat src;
resize(inputSrc, inputSrc, Size(inputSrc.cols * fScale, inputSrc.rows * fScale));
//inputSrc = whiteBalance(src);
//inputSrc = src;
Mat inputSrc2 = inputSrc.clone();

///////////////////
// Mat blurEdges;
// cv::Canny(inputSrc, blurEdges, 225, 175);
//
// double countBlurEdges = cv::countNonZero(blurEdges);
// double blurValue = countBlurEdges * 1000 / (blurEdges.cols * blurEdges.rows);
// std::cout << "blurValue: " << blurValue << std::endl;
// blurEdges.release();
////////////////////////////////

if (isBackSide) {
RobustMatcher rmatcher;
Mat img1;
vector<cv::KeyPoint> img1_keypoints;
Mat img1_descriptors;
Mat img2;
vector<cv::KeyPoint> img2_keypoints;
Mat img2_descriptors;

std::vector<cv::DMatch> matches;
img1 = imread("d:\\shenfenzheng_back.jpg");
GaussianBlur(img1, img1, Size(5, 5), 0);
//img2 = cv::imread("d:\\IMG_20171031_090651.jpg");
img2 = inputSrc2;
Mat result;
rmatcher.match(img1, img2, matches, img1_keypoints, img2_keypoints, result);

Mat dstForBack = result.clone();
bool success = false;
if (findIDCard_Back(dstForBack)) {
imwrite(ResourceManager::getInstance().ConfigDirPath + "output_back.jpg", result);
success = true;
}

img1.release();
img1_descriptors.release();
img2.release();
img2_descriptors.release();
dstForBack.release();
result.release();

if (success) {
double t2 = (double) getTickCount();
double time = (t2 - t1) / getTickFrequency();
std::cout << "time: " << time << std::endl;
return 0;
}
}

Mat res; //分割后图像
int spatialRad = 10; //空间窗口大小
int colorRad = 10; //色彩窗口大小
int maxPyrLevel = 2; //金字塔层数
pyrMeanShiftFiltering(inputSrc, res, spatialRad, colorRad, maxPyrLevel); //色彩聚类平滑滤波

//GaussianBlur(res, res, Size(9, 9), 0);
Mat closerect = getStructuringElement(MORPH_RECT, Size(11, 11)); //进行结构算子生成
morphologyEx(res, res, MORPH_DILATE, closerect);//进行形态学开运算
morphologyEx(res, res, MORPH_OPEN, closerect);
closerect.release();
//imwrite("res1.jpg", res);
RNG rng = theRNG();
Mat mask(res.rows + 2, res.cols + 2, CV_8UC1, Scalar::all(0)); //掩模
for (int y = 0; y < res.rows; y++) {
for (int x = 0; x < res.cols; x++) {
if (mask.at<uchar>(y + 1, x + 1) == 0) //非0处即为1,表示已经经过填充,不再处理
{
Scalar newVal(rng(256), rng(256), rng(256));
floodFill(res, mask, Point(x, y), newVal, 0, Scalar::all(1), Scalar::all(1)); //执行漫水填充
}
}
}
//GaussianBlur(res, res, Size(9, 9), 0);

//inputSrc = res;
//res.release();
mask.release();
//imwrite("res.jpg", res);

vector<vector<Point> > squares;
Mat forSmAT = inputSrc.clone();
//Mat contour = inputSrc2.clone();
Mat contour2 = inputSrc2.clone();
find_squares(forSmAT, squares);
forSmAT.release();

std::cout << "* " << squares.size() << " squares were found." << std::endl;

// draw_squares(contour, squares);
// imwrite("contour.jpg", contour);

vector<Point> minAreaPoints;
int minArea = inputSrc.cols * inputSrc.rows;
Rect minRect;

vector<vector<Point> > squares2;

for (auto points: squares) {
Rect test = minAreaRect(points).boundingRect();
bool valid = true;
if (test.x < 0) {
test.x = 0;
valid = false;
}
if (test.y < 0) {
test.y = 0;
valid = false;
}
if (test.x + test.width > inputSrc.cols) {
test.width = inputSrc.cols - test.x;
}
if (test.y + test.height > inputSrc.rows) {
test.height = inputSrc.rows - test.y;
}

//过滤比例不合理的
if (test.width < test.height) {
if (test.height > test.width * 1.9) {
continue;
}
} else {
if (test.width > test.height * 1.9) {
continue;
}
}

if (test.area() <= minArea) {
minArea = test.area();
minAreaPoints = points;
minRect = test;
}

if (valid) {
squares2.push_back(points);
}
}

if (squares2.size() == 0 && minAreaPoints.size() > 0) {
squares2.push_back(minAreaPoints);
}

std::cout << "* " << squares2.size() << " squares2 were found." << std::endl;


draw_squares(contour2, squares2);
imwrite("contour2.jpg", contour2);
contour2.release();

if (squares2.size() > 1) {
removeBigRect(squares2);
}

//if (minRect.area() > 0) {
for (auto p : squares2) {
RotatedRect rr = minAreaRect(p);
//cout << rr.angle << endl;

// rect is the RotatedRect
// matrices we'll use
Mat M, rotatedImage;
// get angle and size from the bounding box
float angle = rr.angle;
Size2f rect_size = rr.size;
// thanks to http://felix.abecassis.me/2011/10/opencv-rotation-deskewing/
if (rr.angle < -45.) {
angle += 90.0;
swap(rect_size.width, rect_size.height);
}

if (rect_size.width > rect_size.height) {
rect_size.width += rect_size.width * 0.2;
rect_size.height += rect_size.height * 0.2;
} else {
rect_size.width += rect_size.width * 0.2;
rect_size.height += rect_size.height * 0.2;
}
// get the rotation matrix
M = getRotationMatrix2D(rr.center, angle, 1.0);
// perform the affine transformation
//warpAffine(inputSrc, rotated, M, inputSrc.size(), INTER_CUBIC);
warpAffine(inputSrc2, rotatedImage, M, inputSrc2.size(), INTER_CUBIC);
M.release();
// crop the resulting image
//getRectSubPix(rotated, rect_size, rr.center, roiMat);
getRectSubPix(rotatedImage, rect_size, rr.center, rotatedImage);
imwrite("warpAffine.jpg", rotatedImage);


if (rotatedImage.cols < rotatedImage.rows) {
//rotate(roiMat, roiMat, ROTATE_90_COUNTERCLOCKWISE);
rotate(rotatedImage, rotatedImage, ROTATE_90_COUNTERCLOCKWISE);
}

Mat roiMat2 = rotatedImage.clone();
vector<cv::Vec4i> edges;
detect(roiMat2, edges);
roiMat2.release();

if (edges.size() != 4) {
return 0;
}

vector<cv::Point2f> PTransfrom(4);
vector<cv::Point2f> PTransto(4);
PTransfrom[0] = Tools::CrossPoint(edges[0], edges[2]); //upleft
PTransfrom[1] = Tools::CrossPoint(edges[0], edges[3]); //upright
PTransfrom[2] = Tools::CrossPoint(edges[1], edges[2]); //downleft
PTransfrom[3] = Tools::CrossPoint(edges[1], edges[3]); //downright
PTransto[0].x = 0;
PTransto[0].y = 0;
PTransto[1].x = 640;
PTransto[1].y = 0;
PTransto[2].x = 0;
PTransto[2].y = 404;
PTransto[3].x = 640;
PTransto[3].y = 404;
Mat tf = cv::getPerspectiveTransform(PTransfrom, PTransto);
Mat dst = cv::Mat::zeros(cv::Size(640, 404), rotatedImage.type());
warpPerspective(rotatedImage, dst, tf, dst.size(), cv::INTER_CUBIC);
rotatedImage.release();
tf.release();

dst.convertTo(dst, CV_8UC3);

imwrite(ResourceManager::getInstance().ConfigDirPath + "result.jpg", dst);

//////////////////////////////////////////////////////////////////////////////
// Mat brightnessMat = dst.clone();
// brightnessMat = equalizeIntensityHist(brightnessMat);
// Mat hsv;
// cvtColor(brightnessMat, hsv, CV_BGR2HSV );//颜色转换
// vector<Mat> mv;
// split(hsv,mv);//分为3个通道
// //equalizeHist(mv[2], brightnessMat);
// //cv::cvtColor(brightnessMat, brightnessMat, COLOR_BGR2GRAY);
// double thresh = 254;
// cv::threshold(mv[2], brightnessMat, thresh, 255, THRESH_BINARY);
//
// double count = cv::countNonZero(brightnessMat);
//
// if(count > 3)
// {
// std::cout << "有光斑: " << count << std::endl;
// return 1;
// }
//////////////////////////////////////////////////////////////////////////////

Mat dstForBack = dst.clone();
Mat dstForFront = dst.clone();
if (!isBackSide) {
if (findIDCard(dstForFront)) {
imwrite(ResourceManager::getInstance().ConfigDirPath + "output_front.jpg", dst);
break;
} else {
Mat dstForFrontRotated = dst.clone();
rotate(dstForFrontRotated, dstForFrontRotated, ROTATE_180);
Mat dstForFrontRotated2 = dstForFrontRotated.clone();
if (findIDCard(dstForFrontRotated2)) {
imwrite(ResourceManager::getInstance().ConfigDirPath + "output_front.jpg", dstForFrontRotated);
break;
}
dstForFrontRotated2.release();
dstForFrontRotated.release();
}
} else {
if (findIDCard_Back(dstForBack)) {
imwrite(ResourceManager::getInstance().ConfigDirPath + "output_back.jpg", dst);
break;
} else {
Mat dstForBackRotated = dst.clone();
rotate(dstForBackRotated, dstForBackRotated, ROTATE_180);
Mat dstForBackRotated2 = dstForBackRotated.clone();
if (findIDCard_Back(dstForBackRotated2)) {
imwrite(ResourceManager::getInstance().ConfigDirPath + "output_back.jpg", dstForBackRotated);
break;
}
dstForBackRotated.release();
dstForBackRotated2.release();
}
}

dst.release();
dstForBack.release();
dstForFront.release();
}

double t2 = (double) getTickCount();
double time = (t2 - t1) / getTickFrequency();
std::cout << "time: " << time << std::endl;
return 0;
}
posted @ 2017-11-03 09:42  飞晨信息  阅读(127)  评论(0)    收藏  举报