287 lines
7.4 KiB
C++
287 lines
7.4 KiB
C++
#include "CISTestImageProcess.h"
|
|
|
|
int CISTestImageProcess::test(const cv::Mat& image, CISTestResult& result)
|
|
{
|
|
|
|
#if 0
|
|
//std::vector<cv::RotatedRect> marks;
|
|
//int res = findMarks(image, marks);
|
|
//return res;
|
|
result.scaleXY1 = -1;
|
|
result.scaleXY2 = -1;
|
|
result.scaleXY3 = -1;
|
|
|
|
if (image.channels() != 3)
|
|
return -1; //图片不是彩色图
|
|
|
|
int res = 0;
|
|
|
|
cv::Mat hsv;
|
|
cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV_FULL);
|
|
std::vector<cv::Mat> hsv_channels;
|
|
cv::split(hsv, hsv_channels);
|
|
|
|
cv::Mat mask_s, range_h, range_temp;
|
|
cv::inRange(hsv_channels[1], 110, 255, mask_s); //饱和度在[50, 220]的像素
|
|
|
|
//cv::imwrite("range1.jpg", mask_s);
|
|
cv::inRange(hsv_channels[0], 0, 84, range_h); //饱和度在[220, 255]的像素
|
|
cv::inRange(hsv_channels[0], 213, 255, range_temp); //饱和度在[220, 255]的像素
|
|
range_h &= mask_s;
|
|
range_h |= range_temp & mask_s;
|
|
//cv::imwrite("range3.jpg", range_h);
|
|
res = findEllipse(range_h, result.scaleXY1);
|
|
if (res != 0)
|
|
return -2;
|
|
|
|
cv::inRange(hsv_channels[0], 30, 140, range_h); //饱和度在[220, 255]的像素
|
|
range_h &= mask_s;
|
|
//cv::imwrite("range4.jpg", range_h);
|
|
res = findEllipse(range_h, result.scaleXY2);
|
|
if (res != 0)
|
|
return -2;
|
|
|
|
cv::inRange(hsv_channels[0], 128, 213, range_h); //饱和度在[220, 255]的像素
|
|
range_h &= mask_s;
|
|
//cv::imwrite("range5.jpg", range_h);
|
|
res = findEllipse(range_h, result.scaleXY3);
|
|
if (res != 0)
|
|
return -2;
|
|
#else
|
|
cv::Mat thre;
|
|
if (image.channels() == 3)
|
|
cv::cvtColor(image, thre, cv::COLOR_BGR2GRAY);
|
|
else
|
|
thre = image.clone();
|
|
|
|
cv::threshold(thre, thre, 127, 255, cv::THRESH_BINARY);
|
|
|
|
std::vector<std::vector<cv::Point>> contours;
|
|
std::vector<cv::Vec4i> hierarchy;
|
|
|
|
findContours(thre, contours, hierarchy, cv::RETR_CCOMP, cv::CHAIN_APPROX_SIMPLE);
|
|
|
|
std::vector<cv::Point> contour;
|
|
for (size_t i = 0; i < contours.size(); i++)
|
|
{
|
|
if (hierarchy[i][3] == -1)
|
|
continue;
|
|
|
|
cv::Rect rect = cv::boundingRect(contours[i]);
|
|
if (rect.width < 100)
|
|
continue;
|
|
else
|
|
{
|
|
contour = contours[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (contour.size() < 3)
|
|
return -2;
|
|
|
|
cv::RotatedRect box = cv::fitEllipse(contour);
|
|
|
|
if (box.angle < -45)
|
|
{
|
|
box.angle += 90;
|
|
float temp = box.size.width;
|
|
box.size.width = box.size.height;
|
|
box.size.height = temp;
|
|
}
|
|
if (box.angle > 45)
|
|
{
|
|
box.angle -= 90;
|
|
float temp = box.size.width;
|
|
box.size.width = box.size.height;
|
|
box.size.height = temp;
|
|
}
|
|
|
|
result.w = box.size.width;
|
|
result.h = box.size.height;
|
|
result.scaleXY = box.size.width / box.size.height;
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
CISTestImageProcess::CISTestImageProcess()
|
|
{
|
|
}
|
|
|
|
void CISTestImageProcess::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();
|
|
}
|
|
|
|
void CISTestImageProcess::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
|
|
|
|
//将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);
|
|
}
|
|
|
|
int CISTestImageProcess::findPaperContour(const std::vector<std::vector<cv::Point>>& contours, const std::vector<cv::Vec4i>& hierarchy, cv::RotatedRect& paperRect)
|
|
{
|
|
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);
|
|
|
|
if (maxContour.size() == 0)
|
|
return -1;
|
|
|
|
paperRect = cv::minAreaRect(maxContour);
|
|
if (paperRect.angle < -45)
|
|
{
|
|
paperRect.angle += 90;
|
|
float temp = paperRect.size.width;
|
|
paperRect.size.width = paperRect.size.height;
|
|
paperRect.size.height = temp;
|
|
}
|
|
if (paperRect.angle > 45)
|
|
{
|
|
paperRect.angle -= 90;
|
|
float temp = paperRect.size.width;
|
|
paperRect.size.width = paperRect.size.height;
|
|
paperRect.size.height = temp;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int CISTestImageProcess::classfiyContours(const std::vector<std::vector<cv::Point>>& contours, std::vector<std::vector<cv::Point>>& marks,
|
|
std::vector<std::vector<cv::Point>>& colorBlocks,
|
|
std::vector<std::vector<cv::Point>>& grayBlocks)
|
|
{
|
|
marks.clear();
|
|
colorBlocks.clear();
|
|
grayBlocks.clear();
|
|
for (size_t i = 0; i < contours.size(); i++)
|
|
{
|
|
double area = cv::contourArea(contours[i]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int CISTestImageProcess::findEllipse(const cv::Mat& image, double& scale_xy, double areaThre)
|
|
{
|
|
//cv::imwrite("range2.jpg", image);
|
|
std::vector<std::vector<cv::Point>> contours;
|
|
std::vector<cv::Vec4i> hierarchy;
|
|
|
|
findContours(image, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
|
|
|
|
std::vector<cv::Point> maxContour;
|
|
for (std::vector<std::vector<cv::Point>>::iterator iter = contours.begin(); iter != contours.end(); iter++)
|
|
if (cv::contourArea(*iter) > areaThre)
|
|
for (const auto& item : *iter)
|
|
maxContour.push_back(item);
|
|
|
|
convexHull(maxContour, maxContour);
|
|
|
|
if (maxContour.size() < 3)
|
|
return -1;
|
|
|
|
cv::RotatedRect box = cv::fitEllipse(maxContour);
|
|
|
|
if (box.angle < -45)
|
|
{
|
|
box.angle += 90;
|
|
float temp = box.size.width;
|
|
box.size.width = box.size.height;
|
|
box.size.height = temp;
|
|
}
|
|
if (box.angle > 45)
|
|
{
|
|
box.angle -= 90;
|
|
float temp = box.size.width;
|
|
box.size.width = box.size.height;
|
|
box.size.height = temp;
|
|
}
|
|
scale_xy = box.size.width / box.size.height;
|
|
return 0;
|
|
}
|