twain3.0/huagao/ImageProcess/ImageApplyAutoCrop.cpp

380 lines
10 KiB
C++
Raw Normal View History

2021-09-03 06:12:28 +00:00
#include "ImageApplyAutoCrop.h"
#include "ImageProcess_Public.h"
CImageApplyAutoCrop::CImageApplyAutoCrop()
: m_isCrop(false)
, m_isDesaskew(false)
, m_isFillBlank(false)
, m_isConvexHull(true)
, m_isFillColor(false)
, m_threshold(40)
, m_noise(8)
, m_indent(5)
, m_normalCrop(false)
{
}
CImageApplyAutoCrop::CImageApplyAutoCrop(bool isCrop, bool isDesaskew, bool isFillBlank, const cv::Size& fixedSize, bool isConvex, bool isFillColor,
double threshold, int noise, int indent, bool normalCrop)
: m_isCrop(isCrop)
, m_isDesaskew(isDesaskew)
, m_isFillBlank(isFillBlank)
, m_isConvexHull(isConvex)
, m_isFillColor(isFillColor)
, m_threshold(threshold)
, m_noise(noise)
, m_indent(indent)
, m_fixedSize(fixedSize)
, m_normalCrop(normalCrop)
{
}
CImageApplyAutoCrop::~CImageApplyAutoCrop()
{
}
2021-09-03 06:12:28 +00:00
cv::Mat concatenateMatrix(const cv::Mat& first, const cv::Mat& second)
{
cv::Mat mul1 = cv::Mat::eye(3, 3, CV_64F);
cv::Mat mul2 = cv::Mat::eye(3, 3, CV_64F);
cv::Mat mul_r;
first.convertTo(mul_r, CV_64F);
mul_r.row(0).copyTo(mul1.row(0));
mul_r.row(1).copyTo(mul1.row(1));
second.convertTo(mul_r, CV_64F);
mul_r.row(0).copyTo(mul2.row(0));
mul_r.row(1).copyTo(mul2.row(1));
mul1 = mul2 * mul1;
mul_r = first.clone();
mul1.row(0).copyTo(mul_r.row(0));
mul1.row(1).copyTo(mul_r.row(1));
return mul_r;
}
std::vector<cv::Mat> comMat()
{
std::vector<cv::Mat> mats;
cv::Point2f srcTri[3];
srcTri[0] = cv::Point2f(1, 1);
srcTri[1] = cv::Point2f(1, 0);
srcTri[2] = cv::Point2f(0, 1);
2021-11-20 03:09:04 +00:00
const float fact = 0.33f;
float pos[] = { 0, 2 * fact, fact };
2021-09-03 06:12:28 +00:00
cv::Point2f dstTri[3];
for (int i = 0; i < 3; i++)
{
dstTri[0] = cv::Point2f(1, 1 + pos[i]);
dstTri[1] = cv::Point2f(1, pos[i]);
dstTri[2] = cv::Point2f(0, 1 + pos[i]);
mats.push_back(cv::getAffineTransform(srcTri, dstTri));
}
return mats;
}
void brightSharp(cv::Mat& src)
{
const float a = -0.49f;
const float b = 3.0f;
//float kernel_data[] = {
// a, 0, 0, 0, a,
// 0, 0, a, 0, 0,
// 0, a, b, a, 0,
// 0, 0, a, 0, 0,
// a, 0, 0, 0, a };
float kernel_data[] = {
0, a, 0,
a, b, a,
0, a, 0
};
cv::Mat kernel(3, 3, CV_32FC1, kernel_data);
cv::filter2D(src, src, src.depth(), kernel);
}
void CImageApplyAutoCrop::apply(cv::Mat& pDib, int side)
{
(void)side;
if (pDib.empty()) return;
2021-09-03 06:12:28 +00:00
if (m_normalCrop)
{
2021-09-03 06:12:28 +00:00
cv::Rect roi = cv::Rect((pDib.cols - m_fixedSize.width) / 2, side == 0 ? 75 : 145, m_fixedSize.width, m_fixedSize.height) & cv::Rect(0, 0, pDib.cols, pDib.rows);
pDib = pDib(roi).clone();
m_rect = cv::RotatedRect(cv::Point2f(roi.x + roi.width / 2, roi.y + roi.height / 2), cv::Size2f(roi.width, roi.height), 0.0f);
return;
}
2021-09-03 06:12:28 +00:00
if (!m_isCrop && !m_isDesaskew && !m_isFillBlank && m_fixedSize.empty()) return;
cv::Mat src = pDib;
cv::Mat thre;
cv::Mat dst;
hg::threshold_Mat(src, thre, m_threshold);
if (m_noise > 0)
{
cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(m_noise, 1));
2021-11-20 03:09:04 +00:00
cv::morphologyEx(thre, thre, cv::MORPH_OPEN, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT, cv::Scalar::all(0));
}
if (m_indent > 0)
{
cv::Mat element = getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(m_indent, m_indent));
cv::morphologyEx(thre, thre, cv::MORPH_ERODE, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT, cv::Scalar::all(0));
}
2021-11-20 03:09:04 +00:00
std::vector<cv::Vec4i> hierarchy;
std::vector<std::vector<cv::Point>> contours;
hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL);
m_maxContour = hg::getMaxContour(contours, hierarchy);
if (m_maxContour.size() == 0)
{
thre.release();
2021-11-20 03:09:04 +00:00
//
if (!m_isCrop)
pDib = pDib(cv::Rect((pDib.cols - m_fixedSize.width) / 2, (pDib.rows - m_fixedSize.height) / 2, m_fixedSize.width, m_fixedSize.height) & cv::Rect(0, 0, pDib.cols, pDib.rows)).clone();
#ifdef LOG
FileTools::write_log("imgprc.txt", "exit CImageApplyAutoCrop apply");
#endif // LOG
return;
}
2021-11-20 03:09:04 +00:00
thre.release();
dst.release();
cv::RotatedRect rect = hg::getBoundingRect(m_maxContour);
m_rect = rect;
cv::Rect boudingRect = cv::boundingRect(m_maxContour);
boudingRect.x -= 1;
boudingRect.y -= 1;
boudingRect.width += 2;
boudingRect.height += 2;
if (m_isDesaskew && rect.angle != 0)
{
2021-09-03 06:12:28 +00:00
cv::Point2f srcTri[4], srcTri_temp[3], dstTri[3];
rect.points(srcTri);
dstTri[0] = cv::Point2f(0, rect.size.height - 1);
dstTri[1] = cv::Point2f(0, 0);
dstTri[2] = cv::Point2f(rect.size.width - 1, 0);
2021-09-03 06:12:28 +00:00
srcTri_temp[0] = dstTri[0];
srcTri_temp[1] = dstTri[1];
srcTri_temp[2] = dstTri[2];
cv::Mat warp_mat;
warp_mat = cv::getAffineTransform(srcTri, dstTri);
2021-09-03 06:12:28 +00:00
if (src.channels() == 1)
{
cv::warpAffine(src, dst, warp_mat, rect.size, cv::INTER_LINEAR);
}
else
{
cv::Mat bgr[3];
cv::split(src, bgr);
auto mats = comMat();
warp_mat = cv::getAffineTransform(srcTri, dstTri);
warp_mat = concatenateMatrix(mats[0], warp_mat);
cv::warpAffine(bgr[0], bgr[0], warp_mat, rect.size, cv::INTER_LINEAR);
warp_mat = cv::getAffineTransform(srcTri, dstTri);
warp_mat = concatenateMatrix(mats[1], warp_mat);
cv::warpAffine(bgr[1], bgr[1], warp_mat, rect.size, cv::INTER_LINEAR);
warp_mat = cv::getAffineTransform(srcTri, dstTri);
warp_mat = concatenateMatrix(mats[2], warp_mat);
cv::warpAffine(bgr[2], bgr[2], warp_mat, rect.size, cv::INTER_LINEAR);
cv::merge(bgr, 3, dst);
}
double* ptr_m = reinterpret_cast<double*>(warp_mat.data);
double a = ptr_m[0];
double b = ptr_m[1];
double c = ptr_m[2];
double d = ptr_m[3];
double e = ptr_m[4];
double f = ptr_m[5];
for (cv::Point& p : m_maxContour)
{
p.x = static_cast<int>(a * p.x + b * p.y + c);
p.y = static_cast<int>(d * p.x + e * p.y + f);
}
2021-11-20 03:09:04 +00:00
for (std::vector<cv::Point>& sub : contours)
for (cv::Point& p : sub)
{
p.x = static_cast<int>(a * p.x + b * p.y + c);
p.y = static_cast<int>(d * p.x + e * p.y + f);
}
}
else
2021-09-03 06:12:28 +00:00
{
auto t_rect = boudingRect & cv::Rect(0, 0, src.cols, src.rows);
dst = src(t_rect);
if (dst.channels() == 3)
{
cv::Mat bgr[3];
cv::split(dst, bgr);
auto mats = comMat();
for (int i = 0; i < 3; i++)
cv::warpAffine(bgr[i], bgr[i], mats[i], t_rect.size(), cv::INTER_LINEAR);
cv::merge(bgr, 3, dst);
}
2021-11-20 03:09:04 +00:00
m_maxContour.clear();
m_maxContour.push_back(cv::Point(0, t_rect.height - 1));
m_maxContour.push_back(cv::Point(0, 0));
m_maxContour.push_back(cv::Point(t_rect.width - 1, 0));
m_maxContour.push_back(cv::Point(t_rect.width - 1, t_rect.height - 1));
contours.clear();
contours.push_back(m_maxContour);
}
cv::Scalar autoBGColor;
if (m_isFillBlank)
{
if (m_isConvexHull)
{
2021-09-03 06:12:28 +00:00
if (m_maxContour.size() == 0)
{
thre.release();
2021-11-20 03:09:04 +00:00
2021-09-03 06:12:28 +00:00
if (!m_isCrop)
pDib = pDib(cv::Rect((pDib.cols - m_fixedSize.width) / 2, (pDib.rows - m_fixedSize.height) / 2, m_fixedSize.width, m_fixedSize.height) & cv::Rect(0, 0, pDib.cols, pDib.rows)).clone();
return;
}
hg::convexHull(m_maxContour, m_maxContour);
contours.clear();
contours.push_back(m_maxContour);
}
contours.push_back(std::vector<cv::Point>());
contours[contours.size() - 1].push_back(cv::Point(-1, dst.rows - 1));
contours[contours.size() - 1].push_back(cv::Point(-1, -1));
contours[contours.size() - 1].push_back(cv::Point(dst.cols, -1));
contours[contours.size() - 1].push_back(cv::Point(dst.cols, dst.rows));
autoBGColor = m_isFillColor ? getBackGroudColor(pDib, rect.size.area()) : cv::Scalar(255, 255, 255);
hg::fillPolys(dst, contours, autoBGColor);
}
2021-09-03 06:12:28 +00:00
else
{
m_maxContour.clear();
m_maxContour.push_back(cv::Point(-1, dst.rows));
m_maxContour.push_back(cv::Point(-1, -1));
m_maxContour.push_back(cv::Point(dst.cols, -1));
m_maxContour.push_back(cv::Point(dst.cols, dst.rows));
}
pDib.release();
if (/*(m_isCrop && side == 0) || (side == 1 && m_fixedSize.width * m_fixedSize.height == 0)*/ m_isCrop)
pDib = dst.clone();
else
{
pDib = cv::Mat(m_fixedSize, dst.type(), m_isFillBlank ? autoBGColor : cv::Scalar(0, 0, 0));
cv::Rect roi;
roi.x = dst.cols > pDib.cols ? (dst.cols - pDib.cols) / 2 : 0;
roi.width = cv::min(pDib.cols, dst.cols);
roi.y = dst.rows > pDib.rows ? (dst.rows - pDib.rows) / 2 : 0;
roi.height = cv::min(pDib.rows, dst.rows);
cv::Rect rect((pDib.cols - roi.width) / 2, (pDib.rows - roi.height) / 2, roi.width, roi.height);
for (cv::Point& p : m_maxContour)
p += roi.tl();
dst(roi).copyTo(pDib(rect));
}
2021-09-03 06:12:28 +00:00
#ifdef LOG
FileTools::write_log("imgprc.txt", "exit CImageApplyAutoCrop apply8");
#endif // LOG
}
void CImageApplyAutoCrop::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
{
if (mats.empty()) return;
if (!mats[0].empty()) {
apply(mats[0], 0);
2021-08-24 10:17:32 +00:00
m_rects.push_back(m_rect);
2021-09-03 06:12:28 +00:00
brightSharp(mats[0]);
}
if (isTwoSide && mats.size() > 1)
{
cv::Size dSize = m_fixedSize;
if (!mats[0].empty())
m_fixedSize = mats[0].size();
if (!mats[1].empty()) {
apply(mats[1], 1);
2021-08-24 10:17:32 +00:00
m_rects.push_back(m_rect);
2021-09-03 06:12:28 +00:00
brightSharp(mats[1]);
}
if (!mats[0].empty())
m_fixedSize = dSize;
}
}
cv::Scalar CImageApplyAutoCrop::getBackGroudColor(const cv::Mat& image, int total)
{
if (image.channels() == 3)
{
cv::Mat image_bgr[3];
cv::split(image, image_bgr);
uchar bgr[3];
for (size_t i = 0; i < 3; i++)
bgr[i] = getBackGroudChannelMean(image_bgr[i], total);
return cv::Scalar(bgr[0], bgr[1], bgr[2]);
}
else
return cv::Scalar::all(getBackGroudChannelMean(image, total));
}
uchar CImageApplyAutoCrop::getBackGroudChannelMean(const cv::Mat& gray, int total)
{
cv::Mat image_clone;
cv::resize(gray, image_clone, cv::Size(), 0.25, 0.25);
int threnshold = total / 32;
int channels[] = { 0 };
int nHistSize[] = { 256 };
float range[] = { 0, 256 };
const float* fHistRanges[] = { range };
cv::Mat hist;
cv::calcHist(&image_clone, 1, channels, cv::Mat(), hist, 1, nHistSize, fHistRanges, true, false);
int hist_array[256];
for (int i = 0; i < 256; i++)
hist_array[i] = hist.at<float>(i, 0);
int length = 1;
const int length_max = 255 - m_threshold;
while (length < length_max)
{
for (size_t i = m_threshold + 1; i < 256 - length; i++)
{
int count = 0;
uint pixSum = 0;
for (size_t j = 0; j < length; j++)
{
count += hist_array[j + i];
pixSum += hist_array[j + i] * (i + j);
}
if (count >= threnshold)
return pixSum / count;
}
length++;
}
return 255;
}