speedcontroller/imageprocess/ImageApplyMarkCrop.cpp

340 lines
11 KiB
C++
Raw Permalink Blame History

#include "ImageApplyMarkCrop.h"
#include "ImageProcess_Public.h"
#define RE 2
//#define DRAW
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);
cv::Point p_temp;
if (distance1 > distance2 && distance1 > distance3)
{
p_temp = rrects[0].center + rrects[1].center;
p_temp.x = p_temp.x / 2 * 3 - rrects[2].center.x;
p_temp.x = p_temp.x / 2;
p_temp.y = p_temp.y / 2 * 3 - rrects[2].center.y;
p_temp.y = p_temp.y / 2;
//maxContour.push_back(((rrects[0].center + rrects[1].center) / 2.0f * 3.0f - rrects[2].center) / 2.0f);
}
else if (distance2 > distance1 && distance2 > distance3)
{
p_temp = rrects[1].center + rrects[2].center;
p_temp.x = p_temp.x / 2 * 3 - rrects[0].center.x;
p_temp.x = p_temp.x / 2;
p_temp.y = p_temp.y / 2 * 3 - rrects[0].center.y;
p_temp.y = p_temp.y / 2;
//maxContour.push_back(((rrects[1].center + rrects[2].center) / 2.0f * 3.0f - rrects[0].center) / 2.0f);
}
else
{
p_temp = rrects[0].center + rrects[2].center;
p_temp.x = p_temp.x / 2 * 3 - rrects[1].center.x;
p_temp.x = p_temp.x / 2;
p_temp.y = p_temp.y / 2 * 3 - rrects[1].center.y;
p_temp.y = p_temp.y / 2;
//maxContour.push_back(((rrects[2].center + rrects[0].center) / 2.0f * 3.0f - rrects[1].center) / 2.0f);
}
maxContour.push_back(p_temp);
}
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;
focus.x /= 5;
focus.y /= 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.x /= 3;
focus.y /= 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::MORPH_RECT, cv::Size(20, 1));
cv::morphologyEx(thre, thre, cv::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;
}