#include "CSizedetect.h" #include #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(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> &contours, std::vector &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 all_contours(cvTreeToNodeSeq(_ccontours, sizeof(CvSeq), storage)); size_t total = all_contours.size(); contours.resize(total); cv::SeqIterator it = all_contours.begin(); for (size_t i = 0; i < total; i++, ++it) { CvSeq *c = *it; reinterpret_cast(c)->color = static_cast(i); int count = c->total; int *data = new int[static_cast(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(c->h_next)->color : -1; int h_prev = c->h_prev ? reinterpret_cast(c->h_prev)->color : -1; int v_next = c->v_next ? reinterpret_cast(c->v_next)->color : -1; int v_prev = c->v_prev ? reinterpret_cast(c->v_prev)->color : -1; hierarchy[i] = cv::Vec4i(h_next, h_prev, v_next, v_prev); } storage.release(); } std::vector getMaxContour(const std::vector> &contours, const std::vector &hierarchy) { std::vector 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 &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> contours; std::vector hierarchy; hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL); std::vector 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; }