#include "ImageProcess_Public.h" #include #include #include #include static cv::Mat lutGrayMat; //灰色校正值 static cv::Mat lutColorMat; //彩色校正值 static int offsetStep[12]; static int expStep[2][3]; namespace hg { void convexHull(const std::vector& src, std::vector& dst, bool clockwise) { CvMemStorage* storage = cvCreateMemStorage(); // CvSeq* ptseq = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, sizeof(CvContour), sizeof(CvPoint), storage); //ptseqstorage //��src�ĵ㼯�����ptseq for (const cv::Point& item : src) { CvPoint p; p.x = item.x; p.y = item.y; cvSeqPush(ptseq, &p); } //��ȡ������ CvSeq* hull = cvConvexHull2(ptseq, nullptr, clockwise ? CV_CLOCKWISE : CV_COUNTER_CLOCKWISE, 0); if (hull == nullptr) { //�ͷ�storage cvReleaseMemStorage(&storage); return; } //���dst dst.clear(); for (int i = 0, hullCount = hull->total; i < hullCount; i++) dst.push_back(**CV_GET_SEQ_ELEM(CvPoint*, hull, i)); //�ͷ�storage cvReleaseMemStorage(&storage); } #define R_COLOR 255 void fillConvexHull(cv::Mat& image, const std::vector& points) { uint index_top = 0; uint index_bottom = 0; for (size_t i = 0, length = points.size(); i < length; i++) { if (points[i].y < points[index_top].y) index_top = i; if (points[i].y > points[index_bottom].y) index_bottom = i; } std::vector edge_left; uint temp = index_top; while (temp != index_bottom) { edge_left.push_back(points[temp]); temp = (temp + points.size() - 1) % points.size(); } edge_left.push_back(points[index_bottom]); std::vector edge_right; temp = index_top; while (temp != index_bottom) { edge_right.push_back(points[temp]); temp = (temp + points.size() + 1) % points.size(); } edge_right.push_back(points[index_bottom]); std::vector left_edge_x; std::vector left_edge_y; for (size_t i = 0, length = edge_left.size() - 1; i < length; i++) { int y_top = edge_left[i].y; int x_top = edge_left[i].x; int y_bottom = edge_left[i + 1].y; int x_bottom = edge_left[i + 1].x; for (int y = y_top; y < y_bottom; y++) if (y >= 0 && y_top != y_bottom && y < image.rows) { left_edge_x.push_back(((x_bottom - x_top) * y + x_top * y_bottom - x_bottom * y_top) / (y_bottom - y_top)); left_edge_y.push_back(y); } } size_t step = image.step; unsigned char* ptr; ptr = image.data + static_cast(left_edge_y[0]) * step; for (size_t i = 0, length = left_edge_x.size(); i < length; i++) { int pix = left_edge_x[i]; if (pix < image.cols - 1 && pix > 0) memset(ptr + i * step, R_COLOR, static_cast((pix + 1) * image.channels())); } std::vector right_edge_x; std::vector right_edge_y; for (size_t i = 0, length = edge_right.size() - 1; i < length; i++) { int y_top = edge_right[i].y; int x_top = edge_right[i].x; int y_bottom = edge_right[i + 1].y; int x_bottom = edge_right[i + 1].x; for (int y = y_top; y < y_bottom; y++) if (y_top != y_bottom && y < image.rows && y >= 0) { right_edge_x.push_back(((x_bottom - x_top) * y + x_top * y_bottom - x_bottom * y_top) / (y_bottom - y_top)); right_edge_y.push_back(y); } } ptr = image.data + static_cast(right_edge_y[0]) * step; for (size_t i = 0, length = right_edge_x.size(); i < length; i++) { int pix = right_edge_x[i]; if (pix < image.cols - 1 && pix > 0) memset(ptr + i * step + pix * image.channels(), R_COLOR, step - static_cast(pix * image.channels())); } if (edge_left[0].y > 0) memset(image.data, R_COLOR, static_cast(edge_left[0].y) * step); if (edge_left.back().y < image.rows - 1) memset(image.data + static_cast(edge_left.back().y) * step, R_COLOR, static_cast(image.rows - edge_left.back().y) * step); } void fillPolys(cv::Mat& image, const std::vector>& contours, const cv::Scalar& color) { if (contours.empty()) return; size_t count = contours.size(); cv::Point** pointss = new cv::Point*[count]; int* npts = new int[count]; for (size_t i = 0; i < count; i++) { size_t length = contours[i].size(); npts[i] = length; pointss[i] = new cv::Point[length]; for (size_t j = 0; j < length; j++) pointss[i][j] = contours[i][j]; } cv::fillPoly(image, const_cast(pointss), npts, count, color); for (size_t i = 0; i < count; i++) delete[] pointss[i]; delete[] pointss; delete[] npts; } void findContours(const cv::Mat& src, std::vector>& contours, std::vector& hierarchy, int retr, int method, cv::Point offset) { 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); 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(); } cv::Scalar getBackGroundColor(const cv::Mat& image, const cv::Mat& mask, int threshold) { float range[] = { 0, 256 }; const float* ranges = { range }; int histSize = 256; cv::Scalar bgc; if (image.channels() == 3) { cv::Mat mv[3]; cv::split(image, mv); cv::Mat hist[3]; for (int i = 0; i < 3; i++) { cv::calcHist(&mv[i], 1, 0, mask, hist[i], 1, &histSize, &ranges); int index_max = 0; int max_value = 0; for (size_t j = threshold; j < 256; j++) if (hist[i].at(j) > max_value) { index_max = j; max_value = hist[i].at(j); } bgc[i] = index_max; } } else { cv::Mat hist; cv::calcHist(&image, 1, 0, mask, hist, 1, &histSize, &ranges); int index_max = 0; int max_value = 0; for (size_t j = threshold; j < 256; j++) if (hist.at(j) > max_value) { index_max = j; max_value = hist.at(j); } bgc = cv::Scalar::all(index_max); } return bgc; } 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; } 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; } std::vector getVertices(const cv::RotatedRect& rect) { cv::Point2f box[4]; rect.points(box); std::vector points; for (int i = 0; i < 4; i++) points.push_back(cv::Point(box[i])); return points; } void polyIndent(std::vector& points, const cv::Point& center, int indent) { static cv::Point zero(0, 0); for (cv::Point& item : points) { #if 0 cv::Point vec = item - center; if (vec != zero) { int length = vec.x * vec.x + vec.y * vec.y; float x = cv::sqrt(static_cast(vec.x * vec.x / length)) * indent; float y = cv::sqrt(static_cast(vec.y * vec.y / length)) * indent; if (vec.x < 0) x *= -1.0f; if (vec.y < 0) y *= -1.0f; item.x -= static_cast(x); item.y -= static_cast(y); } #else if (item.x > center.x) item.x -= indent; else item.x += indent; if (item.y > center.y) item.y -= indent; else item.y += indent; #endif } } cv::Mat transforColor(const cv::Mat& src) { if (src.channels() == 1) return src.clone(); std::vector channels(3); cv::split(src, channels); cv::Mat temp, dst; bitwise_or(channels[0], channels[1], temp); bitwise_or(channels[2], temp, dst); temp.release(); for (cv::Mat& index : channels) index.release(); return dst; } #define DEFAULT_THRESHOLD 30 #define THRESHOLD_OFFSET 10 void threshold_Mat(const cv::Mat& src, cv::Mat& dst, double thre) { cv::Mat temp; if (src.channels() == 3) { #ifdef USE_ONENCL if (cl_res.context) transforColor_threshold_opencl(src, dst, static_cast(thre)); else #endif { //temp = transforColor(src); cv::cvtColor(src, temp, cv::COLOR_BGR2GRAY); } } else temp = src; if (thre > 0) cv::threshold(temp, dst, thre, 255, cv::THRESH_BINARY); else { std::vector unusual_cols; std::vector unusual_gray; uchar* firstLine = temp.ptr(0); uchar* lastLine = temp.ptr(temp.rows - 1); uchar temp_gray; for (size_t i = 0, length = temp.step; i < length; i++) { temp_gray = cv::min(firstLine[i], lastLine[i]); if (temp_gray > DEFAULT_THRESHOLD) { unusual_cols.push_back(i); unusual_gray.push_back(temp_gray); } } cv::threshold(temp, dst, DEFAULT_THRESHOLD + THRESHOLD_OFFSET, 255, cv::THRESH_BINARY); for (size_t i = 0; i < unusual_cols.size(); i++) dst(cv::Rect(unusual_cols[i], 0, 1, temp.rows)) = 0; } } cv::Point warpPoint(const cv::Point& p, const cv::Mat& warp_mat) { double src_data[3] = { static_cast(p.x), static_cast(p.y), 1 }; cv::Mat src(3, 1, warp_mat.type(), src_data); //warp_mat.type() == CV_64FC1 cv::Mat dst = warp_mat * src; double* ptr = reinterpret_cast(dst.data); return cv::Point(static_cast(ptr[0]), static_cast(ptr[1])); } int distanceP2P(const cv::Point& p1, const cv::Point& p2) { return cv::sqrt(cv::pow(p1.x - p2.x, 2) + cv::pow(p1.y - p2.y, 2)); } float distanceP2L(const cv::Point& p, const cv::Point& l1, const cv::Point& l2) { //��ֱ�߷��� int A = 0, B = 0, C = 0; A = l1.y - l2.y; B = l2.x - l1.x; C = l1.x * l2.y - l1.y * l2.x; //����㵽ֱ�߾��빫ʽ return ((float)abs(A * p.x + B * p.y + C)) / ((float)sqrtf(A * A + B * B)); } cv::Mat loadLUT(const std::string& file) { cv::Mat dataFile = cv::imread(file, cv::IMREAD_ANYCOLOR); long total = dataFile.total(); int step = total / 256; int channel = 408; // 1; // #ifndef USE_NEWFLAT // if (step == 4896 || step == 7344 ) // channel = 408; // else if (step == 14688 ||step== 22032 || step == 44064) // channel = 432; //486 // #else // channel = 408; // #endif cv::Mat lut(step / channel, 256, CV_8UC(channel)); memcpy(lut.data, dataFile.data, total); return lut; } void initLut(const std::string lutpath,bool iscolor) { lutColorMat.release(); lutGrayMat.release(); if (!lutpath.empty() && (access(lutpath.c_str(), F_OK) == 0)) { printf("\n-----init lutpath =%s------------\n",lutpath.c_str()); if(iscolor) lutColorMat = loadLUT(lutpath); //彩色校正值 else lutGrayMat = loadLUT(lutpath); //灰色校正值 } } void correctColor(cv::Mat& src, int dpi, int mode,bool isText) { cv::Mat lutMat(src.type() == CV_8UC3 ? lutColorMat : lutGrayMat); if (lutMat.empty()) { return; } cv::Mat image_temp(src.rows, src.cols * src.channels() / lutMat.channels(), CV_8UC(lutMat.channels()), src.data); for (size_t i = 0; i < image_temp.cols; i++) cv::LUT(image_temp(cv::Rect(i, 0, 1, image_temp.rows)), lutMat(cv::Rect(0, i, 256, 1)), image_temp(cv::Rect(i, 0, 1, image_temp.rows))); } }