285 lines
8.6 KiB
C++
285 lines
8.6 KiB
C++
#include "CSizedetect.h"
|
|
#include <opencv2/opencv.hpp>
|
|
#include "ImageProcess_Public.h"
|
|
#include "commondef.h"
|
|
|
|
void threshold_Mat(const cv::Mat& src, cv::Mat& dst, double thre)
|
|
{
|
|
if (src.channels() == 3)
|
|
{
|
|
#ifdef USE_ONENCL
|
|
if (cl_res.context)
|
|
transforColor_threshold_opencl(src, dst, static_cast<uchar>(thre));
|
|
else
|
|
#endif
|
|
{
|
|
cv::Mat gray = hg::transforColor(src);
|
|
cv::threshold(gray, dst, thre, 255, cv::THRESH_BINARY);
|
|
gray.release();
|
|
}
|
|
}
|
|
else
|
|
cv::threshold(src, dst, thre, 255, cv::THRESH_BINARY);
|
|
}
|
|
|
|
void findContours(const cv::Mat& src, std::vector<std::vector<cv::Point>>& contours, std::vector<cv::Vec4i>& hierarchy, int retr, int method, cv::Point offset)
|
|
{
|
|
#if CV_VERSION_REVISION == 6
|
|
CvMat c_image = src;
|
|
#else
|
|
CvMat c_image;
|
|
c_image = cvMat(src.rows, src.cols, src.type(), src.data);
|
|
c_image.step = src.step[0];
|
|
c_image.type = (c_image.type & ~cv::Mat::CONTINUOUS_FLAG) | (src.flags & cv::Mat::CONTINUOUS_FLAG);
|
|
#endif
|
|
cv::MemStorage storage(cvCreateMemStorage());
|
|
CvSeq* _ccontours = nullptr;
|
|
|
|
#if CV_VERSION_REVISION == 6
|
|
cvFindContours(&c_image, storage, &_ccontours, sizeof(CvContour), retr, method, CvPoint(offset));
|
|
#else
|
|
cvFindContours(&c_image, storage, &_ccontours, sizeof(CvContour), retr, method, CvPoint{ offset.x, offset.y });
|
|
#endif
|
|
if (!_ccontours)
|
|
{
|
|
contours.clear();
|
|
return;
|
|
}
|
|
cv::Seq<CvSeq*> all_contours(cvTreeToNodeSeq(_ccontours, sizeof(CvSeq), storage));
|
|
size_t total = all_contours.size();
|
|
contours.resize(total);
|
|
|
|
cv::SeqIterator<CvSeq*> it = all_contours.begin();
|
|
for (size_t i = 0; i < total; i++, ++it)
|
|
{
|
|
CvSeq* c = *it;
|
|
reinterpret_cast<CvContour*>(c)->color = static_cast<int>(i);
|
|
int count = c->total;
|
|
int* data = new int[static_cast<size_t>(count * 2)];
|
|
cvCvtSeqToArray(c, data);
|
|
for (int j = 0; j < count; j++)
|
|
{
|
|
contours[i].push_back(cv::Point(data[j * 2], data[j * 2 + 1]));
|
|
}
|
|
delete[] data;
|
|
}
|
|
|
|
hierarchy.resize(total);
|
|
it = all_contours.begin();
|
|
for (size_t i = 0; i < total; i++, ++it)
|
|
{
|
|
CvSeq* c = *it;
|
|
int h_next = c->h_next ? reinterpret_cast<CvContour*>(c->h_next)->color : -1;
|
|
int h_prev = c->h_prev ? reinterpret_cast<CvContour*>(c->h_prev)->color : -1;
|
|
int v_next = c->v_next ? reinterpret_cast<CvContour*>(c->v_next)->color : -1;
|
|
int v_prev = c->v_prev ? reinterpret_cast<CvContour*>(c->v_prev)->color : -1;
|
|
hierarchy[i] = cv::Vec4i(h_next, h_prev, v_next, v_prev);
|
|
}
|
|
|
|
storage.release();
|
|
}
|
|
|
|
std::vector<cv::Point> getMaxContour(const std::vector<std::vector<cv::Point>>& contours, const std::vector<cv::Vec4i>& hierarchy)
|
|
{
|
|
std::vector<cv::Point> maxContour;
|
|
if (contours.size() < 1) return {};
|
|
|
|
for (size_t i = 0, length = hierarchy.size(); i < length; i++)
|
|
if (hierarchy[i][3] == -1)
|
|
for (const auto& item : contours[i])
|
|
maxContour.push_back(item);
|
|
|
|
return maxContour;
|
|
}
|
|
|
|
cv::RotatedRect getBoundingRect(const std::vector<cv::Point>& contour)
|
|
{
|
|
if (contour.empty()) return {};
|
|
|
|
cv::RotatedRect rect = minAreaRect(contour);
|
|
if (rect.angle < -45)
|
|
{
|
|
rect.angle += 90;
|
|
float temp = rect.size.width;
|
|
rect.size.width = rect.size.height;
|
|
rect.size.height = temp;
|
|
}
|
|
if (rect.angle > 45)
|
|
{
|
|
rect.angle -= 90;
|
|
float temp = rect.size.width;
|
|
rect.size.width = rect.size.height;
|
|
rect.size.height = temp;
|
|
}
|
|
|
|
return rect;
|
|
}
|
|
|
|
CSizedetect::CSizedetect(int papaertype) : m_papertype(papaertype),
|
|
m_horThre(70),
|
|
m_verThre(100)
|
|
{
|
|
|
|
}
|
|
|
|
CSizedetect::~CSizedetect(void) {}
|
|
|
|
void CSizedetect::SetPapertype(int papertype) {
|
|
m_papertype=papertype;
|
|
}
|
|
static int x=0;
|
|
int CSizedetect::preprocess(cv::Mat &mat, void *unused)
|
|
{
|
|
if(!mat.empty())
|
|
{
|
|
float width, height;
|
|
cv::Mat thre;
|
|
hg::threshold_Mat(mat, thre, 40);
|
|
cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(8, 1));
|
|
cv::morphologyEx(thre, thre, cv::MORPH_OPEN, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT, cv::Scalar::all(0));
|
|
std::vector<std::vector<cv::Point>> contours;
|
|
std::vector<cv::Vec4i> hierarchy;
|
|
hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL);
|
|
std::vector<cv::Point> maxContour = hg::getMaxContour(contours, hierarchy);
|
|
cv::RotatedRect rect = hg::getBoundingRect(maxContour);
|
|
width = rect.size.width;
|
|
height = rect.size.height;
|
|
printf("\n width =%f ,height = %f ",width,height);
|
|
//fastMeasureSize(mat.data,mat.cols,mat.rows,mat.channels(),width,height,40,20,5);
|
|
HGSize dstSize;
|
|
if(m_supportPaper.count((PaperSize)m_papertype)>0)//包含设置的幅面
|
|
{
|
|
dstSize=m_supportPaper[(PaperSize)m_papertype];
|
|
if((width>(dstSize.width+m_horThre))||(width<(dstSize.width-m_horThre))||(height > (dstSize.height+m_verThre))||(height < (dstSize.height-m_verThre)))
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void CSizedetect::rotate(float &x, float &y, float angle)
|
|
{
|
|
float a = x * cos(angle) - y * sin(angle);
|
|
float b = x * sin(angle) + y * cos(angle);
|
|
x = a;
|
|
y = b;
|
|
}
|
|
|
|
void CSizedetect::minAeaRect(const float *x, const float *y, int size, float &width, float &height)
|
|
{
|
|
float area = width * height;
|
|
// rotate 0~90 degree
|
|
for (int i = 0; i < 91; ++i)
|
|
{
|
|
float tmpx = x[0], tmpy = y[0];
|
|
rotate(tmpx, tmpy, i);
|
|
float xl = tmpx, xr = tmpx, yt = tmpy, yb = tmpy;
|
|
// traverse all points
|
|
for (int j = 1; j < size; ++j)
|
|
{
|
|
tmpx = x[j];
|
|
tmpy = y[j];
|
|
rotate(tmpx, tmpy, i);
|
|
if (tmpx < xl)
|
|
xl = tmpx;
|
|
if (tmpx > xr)
|
|
xr = tmpx;
|
|
if (tmpy < yb)
|
|
yb = tmpy;
|
|
if (tmpy > yt)
|
|
yt = tmpy;
|
|
}
|
|
float xx = xr - xl, yy = yt - yb;
|
|
if (area > xx * yy)
|
|
{
|
|
area = xx * yy;
|
|
height = xx;
|
|
width = yy;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (height < width)
|
|
{
|
|
float tmp = height;
|
|
height = width;
|
|
width = tmp;
|
|
}
|
|
}
|
|
|
|
void CSizedetect::fastMeasureSize(const unsigned char *data, int src_width, int src_height, int channels, float &dst_width, float &dst_height, int threshold, int indent, int step)
|
|
{
|
|
int bytesPerLine = src_width * channels;
|
|
int indent_x = indent * channels;
|
|
int indent_y = indent;
|
|
int step_x = step * channels;
|
|
int step_y = step;
|
|
|
|
int total_count = (bytesPerLine + src_height) * 2 / indent;
|
|
if (total_count < 1)
|
|
return;
|
|
|
|
float *points_x = new float[total_count];
|
|
float *points_y = new float[total_count];
|
|
|
|
int points_count = 0;
|
|
//top
|
|
int rows = src_height / 2;
|
|
for (int x = 0; x < bytesPerLine; x += indent_x)
|
|
for (int y = 0; y < rows; y += step_y)
|
|
if (data[y * bytesPerLine + x] > threshold)
|
|
{
|
|
points_x[points_count] = x / channels;
|
|
points_y[points_count] = y;
|
|
points_count++;
|
|
break;
|
|
}
|
|
|
|
//bottom
|
|
for (int x = 0; x < bytesPerLine; x += indent_x)
|
|
for (int y = src_height - 1; y >= rows; y -= step_y)
|
|
if (data[y * bytesPerLine + x] > threshold)
|
|
{
|
|
points_x[points_count] = x / channels;
|
|
points_y[points_count] = y;
|
|
points_count++;
|
|
break;
|
|
}
|
|
|
|
//left
|
|
int cols = bytesPerLine / 2;
|
|
for (int y = 0; y < src_height; y += indent)
|
|
for (int x = 0; x < cols; x += step_x)
|
|
if (data[y * bytesPerLine + x] > threshold)
|
|
{
|
|
points_x[points_count] = x / channels;
|
|
points_y[points_count] = y;
|
|
points_count++;
|
|
break;
|
|
}
|
|
|
|
//right
|
|
for (int y = 0; y < src_height; y += indent)
|
|
for (int x = bytesPerLine - 1; x >= cols; x -= step_x)
|
|
if (data[y * bytesPerLine + x] > threshold)
|
|
{
|
|
points_x[points_count] = x / channels;
|
|
points_y[points_count] = y;
|
|
points_count++;
|
|
break;
|
|
}
|
|
|
|
if (points_count > 3)
|
|
{
|
|
dst_width = src_width;
|
|
dst_height = src_height;
|
|
minAeaRect(points_x, points_y, points_count, dst_width, dst_height);
|
|
}
|
|
|
|
delete[] points_x;
|
|
delete[] points_y;
|
|
}
|
|
|