newtx/imgproc/algs/ImageProcess_Public.cpp

488 lines
13 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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>
#include <base/utils.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)
{
printf("loadLUT(%s) ...\n", file.c_str());
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)
{
if (!lutpath.empty() && (access(lutpath.c_str(), F_OK) == 0))
{
printf("\n-----init lutpath =%s------------\n",lutpath.c_str());
if(iscolor)
{
lutColorMat.release();
lutColorMat = loadLUT(lutpath); //彩色校正值
}
else
{
lutGrayMat.release();
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)));
}
}