484 lines
13 KiB
C++
484 lines
13 KiB
C++
#include "ImageProcess_Public.h"
|
||
|
||
#include <unistd.h>
|
||
#include <opencv2/core/core_c.h>
|
||
#include <opencv2/core/types_c.h>
|
||
#include <opencv2/imgproc/imgproc_c.h>
|
||
|
||
static cv::Mat lutGrayMat; //灰色校正值
|
||
static cv::Mat lutColorMat; //彩色校正值
|
||
static int offsetStep[12];
|
||
static int expStep[2][3];
|
||
|
||
namespace hg
|
||
{
|
||
void convexHull(const std::vector<cv::Point>& src, std::vector<cv::Point>& dst, bool clockwise)
|
||
{
|
||
CvMemStorage* storage = cvCreateMemStorage(); //
|
||
CvSeq* ptseq = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, sizeof(CvContour), sizeof(CvPoint), storage); //ptseqstorage
|
||
|
||
//<2F><>src<72>ĵ㼯<C4B5><E3BCAF><EFBFBD><EFBFBD><EFBFBD>ptseq
|
||
for (const cv::Point& item : src)
|
||
{
|
||
CvPoint p;
|
||
p.x = item.x;
|
||
p.y = item.y;
|
||
cvSeqPush(ptseq, &p);
|
||
}
|
||
|
||
//<2F><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
CvSeq* hull = cvConvexHull2(ptseq, nullptr, clockwise ? CV_CLOCKWISE : CV_COUNTER_CLOCKWISE, 0);
|
||
|
||
if (hull == nullptr)
|
||
{
|
||
//<2F>ͷ<EFBFBD>storage
|
||
cvReleaseMemStorage(&storage);
|
||
return;
|
||
}
|
||
|
||
//<2F><><EFBFBD>dst
|
||
dst.clear();
|
||
for (int i = 0, hullCount = hull->total; i < hullCount; i++)
|
||
dst.push_back(**CV_GET_SEQ_ELEM(CvPoint*, hull, i));
|
||
|
||
//<2F>ͷ<EFBFBD>storage
|
||
cvReleaseMemStorage(&storage);
|
||
}
|
||
|
||
#define R_COLOR 255
|
||
void fillConvexHull(cv::Mat& image, const std::vector<cv::Point>& 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<cv::Point> 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<cv::Point> 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<int> left_edge_x;
|
||
std::vector<int> 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<uint>(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<size_t>((pix + 1) * image.channels()));
|
||
}
|
||
|
||
std::vector<int> right_edge_x;
|
||
std::vector<int> 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<uint>(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<size_t>(pix * image.channels()));
|
||
}
|
||
|
||
if (edge_left[0].y > 0)
|
||
memset(image.data, R_COLOR, static_cast<size_t>(edge_left[0].y) * step);
|
||
|
||
if (edge_left.back().y < image.rows - 1)
|
||
memset(image.data + static_cast<size_t>(edge_left.back().y) * step, R_COLOR,
|
||
static_cast<size_t>(image.rows - edge_left.back().y) * step);
|
||
}
|
||
|
||
void fillPolys(cv::Mat& image, const std::vector<std::vector<cv::Point>>& 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<const cv::Point**>(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<std::vector<cv::Point>>& contours, std::vector<cv::Vec4i>& 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<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();
|
||
}
|
||
|
||
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<float>(j) > max_value)
|
||
{
|
||
index_max = j;
|
||
max_value = hist[i].at<float>(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<float>(j) > max_value)
|
||
{
|
||
index_max = j;
|
||
max_value = hist.at<float>(j);
|
||
}
|
||
bgc = cv::Scalar::all(index_max);
|
||
}
|
||
|
||
return bgc;
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
std::vector<cv::Point> getVertices(const cv::RotatedRect& rect)
|
||
{
|
||
cv::Point2f box[4];
|
||
rect.points(box);
|
||
std::vector<cv::Point> points;
|
||
for (int i = 0; i < 4; i++)
|
||
points.push_back(cv::Point(box[i]));
|
||
|
||
return points;
|
||
}
|
||
|
||
void polyIndent(std::vector<cv::Point>& 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<float>(vec.x * vec.x / length)) * indent;
|
||
float y = cv::sqrt(static_cast<float>(vec.y * vec.y / length)) * indent;
|
||
|
||
if (vec.x < 0) x *= -1.0f;
|
||
if (vec.y < 0) y *= -1.0f;
|
||
|
||
item.x -= static_cast<int>(x);
|
||
item.y -= static_cast<int>(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<cv::Mat> 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<uchar>(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<int> unusual_cols;
|
||
std::vector<uchar> unusual_gray;
|
||
|
||
uchar* firstLine = temp.ptr<uchar>(0);
|
||
uchar* lastLine = temp.ptr<uchar>(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<double>(p.x), static_cast<double>(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<double*>(dst.data);
|
||
return cv::Point(static_cast<int>(ptr[0]), static_cast<int>(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)
|
||
{
|
||
//<2F><>ֱ<EFBFBD>߷<EFBFBD><DFB7><EFBFBD>
|
||
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;
|
||
//<2F><><EFBFBD><EFBFBD>㵽ֱ<E3B5BD>߾<EFBFBD><DFBE>빫ʽ
|
||
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)));
|
||
}
|
||
|
||
} |