mirror of http://192.168.1.51:8099/lmh188/twain3
315 lines
9.7 KiB
C++
315 lines
9.7 KiB
C++
|
#include "ImageApplyMarkCrop.h"
|
|||
|
#include "ImageProcess_Public.h"
|
|||
|
|
|||
|
#define RE 2
|
|||
|
//#define DRAW
|
|||
|
|
|||
|
#ifdef NOT_USE
|
|||
|
|
|||
|
|
|||
|
|
|||
|
CImageApplyMarkCrop::CImageApplyMarkCrop(CImageApplyMarkCrop::DeviceModel device, bool isCropped, double threshold, int noise, CImageApplyMarkCrop::DPI dpi, DirectionMethod direction)
|
|||
|
: m_device(device)
|
|||
|
, m_b_isCropped(isCropped)
|
|||
|
, m_threshold(120)
|
|||
|
, m_noise(noise)
|
|||
|
, m_dpi(dpi)
|
|||
|
, m_range(30, 55)
|
|||
|
, m_direction(direction)
|
|||
|
{
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
int CImageApplyMarkCrop::apply(const cv::Mat& src, cv::Mat& dst, Orientation markOri, bool barCode, int& angle)
|
|||
|
{
|
|||
|
if (src.empty()) return -1;
|
|||
|
|
|||
|
cv::Mat src_resize;
|
|||
|
if (m_device == DeviceModel::G400)
|
|||
|
cv::resize(src, src_resize, cv::Size(src.cols / RE, src.rows / RE));
|
|||
|
else
|
|||
|
cv::resize(src, src_resize, cv::Size(src.cols / 3, src.rows / RE));
|
|||
|
cv::Mat scale_mat;
|
|||
|
cv::Mat thre(src_resize.size(), CV_8UC1);
|
|||
|
hg::threshold_Mat(src_resize, thre, m_threshold);
|
|||
|
|
|||
|
#ifdef DRAW
|
|||
|
cv::imwrite("thre.bmp", thre);
|
|||
|
#endif
|
|||
|
std::vector<cv::Vec4i> hierarchy;
|
|||
|
std::vector<std::vector<cv::Point>> contours;
|
|||
|
|
|||
|
hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL);
|
|||
|
std::vector<cv::Point> maxContour = hg::getMaxContour(contours, hierarchy);
|
|||
|
|
|||
|
float scale = m_device == DeviceModel::G300 ? 3 : RE;
|
|||
|
|
|||
|
if (maxContour.size() == 0)
|
|||
|
{
|
|||
|
thre.release();
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
//thre.release();
|
|||
|
//dst.release();
|
|||
|
|
|||
|
cv::RotatedRect rect = hg::getBoundingRect(maxContour);
|
|||
|
|
|||
|
cv::Point2f vertex[4];
|
|||
|
rect.points(vertex);
|
|||
|
|
|||
|
std::vector<std::vector<cv::Point>> marks;
|
|||
|
std::vector<cv::RotatedRect> rrects;
|
|||
|
|
|||
|
hg::threshold_Mat(src_resize, thre, m_threshold);
|
|||
|
cv::bitwise_not(thre, thre);
|
|||
|
contours.clear();
|
|||
|
hierarchy.clear();
|
|||
|
hg::findContours(thre, contours, hierarchy, cv::RETR_LIST);
|
|||
|
findMarks(contours, rect, cv::Range(m_range.start / RE, m_range.end / RE), marks, rrects);
|
|||
|
|
|||
|
if (marks.size() < 3) return -2;
|
|||
|
|
|||
|
#ifdef DRAW
|
|||
|
for (int i = 0; i < marks.size(); i++)
|
|||
|
cv::circle(thre, marks[i][0], 30, cv::Scalar(255));
|
|||
|
cv::imwrite("contour.bmp", thre);
|
|||
|
#endif
|
|||
|
|
|||
|
maxContour.clear();
|
|||
|
for (const std::vector<cv::Point>& mark : marks)
|
|||
|
for (const cv::Point& p : mark)
|
|||
|
maxContour.push_back(p);
|
|||
|
|
|||
|
if (rrects.size() == 3)
|
|||
|
{
|
|||
|
double distance1 = hg::distanceP2P(rrects[0].center, rrects[1].center);
|
|||
|
double distance2 = hg::distanceP2P(rrects[1].center, rrects[2].center);
|
|||
|
double distance3 = hg::distanceP2P(rrects[2].center, rrects[0].center);
|
|||
|
|
|||
|
if (distance1 > distance2 && distance1 > distance3)
|
|||
|
maxContour.push_back(((rrects[0].center + rrects[1].center) / 2 * 3 - rrects[2].center) / 2);
|
|||
|
else if (distance2 > distance1 && distance2 > distance3)
|
|||
|
maxContour.push_back(((rrects[1].center + rrects[2].center) / 2 * 3 - rrects[0].center) / 2);
|
|||
|
else
|
|||
|
maxContour.push_back(((rrects[2].center + rrects[0].center) / 2 * 3 - rrects[1].center) / 2);
|
|||
|
}
|
|||
|
|
|||
|
for (cv::Point& item : maxContour)
|
|||
|
item *= scale;
|
|||
|
|
|||
|
rect = hg::getBoundingRect(maxContour);
|
|||
|
rect.points(vertex);
|
|||
|
|
|||
|
cv::Point2f focus;
|
|||
|
Orientation ori;
|
|||
|
|
|||
|
for (size_t i = 0; i < rrects.size(); i++)
|
|||
|
for (size_t j = i + 1; j < rrects.size(); j++)
|
|||
|
if (rrects[i].size.area() < rrects[j].size.area())
|
|||
|
{
|
|||
|
cv::RotatedRect rect_remp = rrects[j];
|
|||
|
rrects[j] = rrects[i];
|
|||
|
rrects[i] = rect_remp;
|
|||
|
}
|
|||
|
|
|||
|
for (cv::RotatedRect& item : rrects)
|
|||
|
item.center *= scale;
|
|||
|
|
|||
|
if (m_direction == DirectionMethod::Multilateral)
|
|||
|
{
|
|||
|
if (rrects.size() < 4) return -3;
|
|||
|
|
|||
|
for (int i = 0; i < 5; i++)
|
|||
|
focus += rrects[i].center;
|
|||
|
focus /= 5;
|
|||
|
|
|||
|
float dis_top = hg::distanceP2L(focus, vertex[1], vertex[2]);
|
|||
|
float dis_bottom = hg::distanceP2L(focus, vertex[0], vertex[3]);
|
|||
|
float dis_left = hg::distanceP2L(focus, vertex[0], vertex[1]);
|
|||
|
float dis_right = hg::distanceP2L(focus, vertex[2], vertex[3]);
|
|||
|
|
|||
|
float dis_min = cv::min(dis_top, cv::min(dis_bottom, cv::min(dis_left, dis_right)));
|
|||
|
if (dis_top == dis_min)
|
|||
|
ori = Top_RB;
|
|||
|
else if (dis_bottom == dis_min)
|
|||
|
ori = Bottom_LT;
|
|||
|
else if (dis_left == dis_min)
|
|||
|
ori = Left_RT;
|
|||
|
else
|
|||
|
ori = Right_LB;
|
|||
|
}
|
|||
|
else if (m_direction == DirectionMethod::Trilateral_7Net)
|
|||
|
{
|
|||
|
for (int i = 0; i < 3; i++)
|
|||
|
focus += rrects[i].center;
|
|||
|
focus /= 3;
|
|||
|
|
|||
|
float dis_top = hg::distanceP2L(focus, vertex[1], vertex[2]);
|
|||
|
float dis_bottom = hg::distanceP2L(focus, vertex[0], vertex[3]);
|
|||
|
float dis_left = hg::distanceP2L(focus, vertex[0], vertex[1]);
|
|||
|
float dis_right = hg::distanceP2L(focus, vertex[2], vertex[3]);
|
|||
|
|
|||
|
float dis_min_lr = cv::min(dis_left, dis_right);
|
|||
|
float dis_min_tb = cv::min(dis_top, dis_bottom);
|
|||
|
if (dis_min_lr == dis_right && dis_min_tb == dis_bottom)
|
|||
|
ori = Bottom_LT;
|
|||
|
else if (dis_min_lr == dis_left && dis_min_tb == dis_top)
|
|||
|
ori = Top_RB;
|
|||
|
else if (dis_min_lr == dis_right && dis_min_tb == dis_top)
|
|||
|
ori = Right_LB;
|
|||
|
else
|
|||
|
ori = Left_RT;
|
|||
|
}
|
|||
|
|
|||
|
cv::Point2f srcTri[4];
|
|||
|
cv::Point2f dstTri[3];
|
|||
|
rect.points(srcTri);
|
|||
|
|
|||
|
if (m_device == DeviceModel::G300)
|
|||
|
for (cv::Point2f& p : srcTri)
|
|||
|
p.y = p.y * RE / m_device;
|
|||
|
|
|||
|
cv::Size temp_size;
|
|||
|
float width = rect.size.width;
|
|||
|
float height = hg::distanceP2P(srcTri[0], srcTri[1]);
|
|||
|
if (markOri == Default || markOri == ori)
|
|||
|
{
|
|||
|
dstTri[0] = cv::Point2f(0, height - 1);
|
|||
|
dstTri[1] = cv::Point2f(0, 0);
|
|||
|
dstTri[2] = cv::Point2f(width - 1, 0);
|
|||
|
temp_size.width = width;
|
|||
|
temp_size.height = height;
|
|||
|
angle = 0;
|
|||
|
}
|
|||
|
else if (markOri - ori == -3 || markOri - ori == 1)
|
|||
|
{
|
|||
|
dstTri[0] = cv::Point2f(0, 0);
|
|||
|
dstTri[1] = cv::Point2f(height - 1, 0);
|
|||
|
dstTri[2] = cv::Point2f(height - 1, width - 1);
|
|||
|
temp_size.width = height;
|
|||
|
temp_size.height = width;
|
|||
|
angle = -90;
|
|||
|
}
|
|||
|
else if (markOri - ori == -2 || markOri - ori == 2)
|
|||
|
{
|
|||
|
dstTri[0] = cv::Point2f(width - 1, 0);
|
|||
|
dstTri[1] = cv::Point2f(width - 1, height - 1);
|
|||
|
dstTri[2] = cv::Point2f(0, height - 1);
|
|||
|
temp_size.width = width;
|
|||
|
temp_size.height = height;
|
|||
|
angle = 180;
|
|||
|
}
|
|||
|
else if (markOri - ori == -1 || markOri - ori == 3)
|
|||
|
{
|
|||
|
dstTri[0] = cv::Point2f(height - 1, width - 1);
|
|||
|
dstTri[1] = cv::Point2f(0, width - 1);
|
|||
|
dstTri[2] = cv::Point2f(0, 0);
|
|||
|
temp_size.width = height;
|
|||
|
temp_size.height = width;
|
|||
|
angle = 90;
|
|||
|
}
|
|||
|
|
|||
|
if (m_b_isCropped)
|
|||
|
{
|
|||
|
cv::Mat warp_mat;
|
|||
|
warp_mat = cv::getAffineTransform(srcTri, dstTri);
|
|||
|
cv::warpAffine(src, dst, warp_mat, temp_size);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (angle == 0)
|
|||
|
dst = src.clone();
|
|||
|
else if (angle == 90)
|
|||
|
{
|
|||
|
cv::transpose(src, dst);
|
|||
|
cv::flip(dst, dst, 0);
|
|||
|
}
|
|||
|
else if (angle == -90)
|
|||
|
{
|
|||
|
cv::transpose(src, dst);
|
|||
|
cv::flip(dst, dst, 1);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
cv::flip(src, dst, 0);
|
|||
|
cv::flip(dst, dst, 1);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD>ж<EFBFBD><D0B6><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
if (barCode)
|
|||
|
{
|
|||
|
//cv::imwrite("dst.bmp", dst);
|
|||
|
if (dst.cols < 600 || dst.rows < 400)
|
|||
|
return -4;
|
|||
|
if (!isContainBarCode(dst(cv::Rect(0, 0, 600, 400))))
|
|||
|
return -5;
|
|||
|
}
|
|||
|
|
|||
|
return 0;
|
|||
|
|
|||
|
#ifdef DRAW
|
|||
|
cv::imwrite("dst.bmp", dst);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
void CImageApplyMarkCrop::findMarks(const std::vector<std::vector<cv::Point>>& contours, const cv::RotatedRect& region,
|
|||
|
const cv::Range& range, std::vector<std::vector<cv::Point>>& marks, std::vector<cv::RotatedRect>& rrect)
|
|||
|
{
|
|||
|
cv::RotatedRect region_outside = region;
|
|||
|
cv::RotatedRect region_inside = region;
|
|||
|
region_inside.size = cv::Size2f(region.size.width * 0.9, region.size.height * 0.9);
|
|||
|
|
|||
|
cv::Point2f outside[4], inside[4];
|
|||
|
region_outside.points(outside);
|
|||
|
region_inside.points(inside);
|
|||
|
|
|||
|
std::vector<cv::Point> v_outside, v_inside;
|
|||
|
for (size_t i = 0; i < 4; i++)
|
|||
|
{
|
|||
|
v_outside.push_back(cv::Point(outside[i].x, outside[i].y));
|
|||
|
v_inside.push_back(cv::Point(inside[i].x, inside[i].y));
|
|||
|
}
|
|||
|
for (size_t i = 0, length = contours.size(); i < length; i++)
|
|||
|
{
|
|||
|
std::vector<cv::Point> contour = contours[i];
|
|||
|
cv::RotatedRect rect = cv::minAreaRect(contour);
|
|||
|
double area = cv::contourArea(contour);
|
|||
|
|
|||
|
if (rect.size.width < range.start || rect.size.height < range.start || rect.size.width > range.end || rect.size.height > range.end)
|
|||
|
continue;
|
|||
|
if (rect.size.width * rect.size.height < 40 / RE)
|
|||
|
continue;
|
|||
|
|
|||
|
if (cv::pointPolygonTest(v_outside, rect.center, true) > 0 && cv::pointPolygonTest(v_inside, rect.center, true) < 0)
|
|||
|
{
|
|||
|
marks.push_back(contour);
|
|||
|
rrect.push_back(rect);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
bool CImageApplyMarkCrop::isContainBarCode(const cv::Mat& image)
|
|||
|
{
|
|||
|
cv::Mat thre;
|
|||
|
hg::threshold_Mat(image, thre, 127);
|
|||
|
cv::bitwise_not(thre, thre);
|
|||
|
|
|||
|
cv::Mat element = cv::getStructuringElement(cv::MorphShapes::MORPH_RECT, cv::Size(20, 1));
|
|||
|
cv::morphologyEx(thre, thre, cv::MorphTypes::MORPH_DILATE, element);
|
|||
|
//cv::imwrite("barCode.bmp", thre);
|
|||
|
|
|||
|
std::vector<cv::Vec4i> hierarchy;
|
|||
|
std::vector<std::vector<cv::Point>> contours;
|
|||
|
hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL);
|
|||
|
|
|||
|
for (size_t i = 0; i < contours.size(); i++)
|
|||
|
{
|
|||
|
cv::Rect rect = cv::boundingRect(contours[i]);
|
|||
|
if (rect.width > 250 && rect.height > 50)
|
|||
|
return true;
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
#endif //
|