|
|
|
|
|
#include "ImageProcess.h"
|
|
|
|
|
|
#include "qstring.h"
|
|
|
|
|
|
#include "CVUtils.h"
|
|
|
|
|
|
#include "ED.h"
|
|
|
|
|
|
#include "EDLines.h"
|
|
|
|
|
|
#include "EDCircles.h"
|
|
|
|
|
|
#include "CircleDetector.h"
|
|
|
|
|
|
|
|
|
|
|
|
//摩轮宏定义 表示该算法用于摩轮型号识别检测
|
|
|
|
|
|
ImageProcess::ImageProcess()
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
ImageProcess::~ImageProcess()
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
Mat _EnhanImg_sharpen(const Mat &img) {
|
|
|
|
|
|
int mGainValue = 3;
|
|
|
|
|
|
float amount = mGainValue * 0.5f;
|
|
|
|
|
|
Mat blurred;
|
|
|
|
|
|
|
|
|
|
|
|
int mSmoothValue = 3;
|
|
|
|
|
|
GaussianBlur(img, blurred, Size(), mSmoothValue);
|
|
|
|
|
|
Mat lowContrastMask = abs(img - blurred) < 5;
|
|
|
|
|
|
Mat orResult = img * (1 + amount) + blurred * (-amount);
|
|
|
|
|
|
img.copyTo(orResult, lowContrastMask);
|
|
|
|
|
|
Mat openMat = orResult.clone();
|
|
|
|
|
|
return openMat;
|
|
|
|
|
|
}
|
|
|
|
|
|
Mat findEdge2(const Mat &Src)
|
|
|
|
|
|
{
|
|
|
|
|
|
Mat ret = Src.clone();
|
|
|
|
|
|
Mat kernel = (Mat_<float>(5, 5) <<
|
|
|
|
|
|
-1, -1, -1, -1, -1,
|
|
|
|
|
|
-1, -1, -1, -1, -1,
|
|
|
|
|
|
-1, -1, 24, -1, -1,
|
|
|
|
|
|
-1, -1, -1, -1, -1,
|
|
|
|
|
|
-1, -1, -1, -1, -1);
|
|
|
|
|
|
filter2D(Src, ret, CV_8UC1, kernel);
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
#define REAIZE 2
|
|
|
|
|
|
|
|
|
|
|
|
cv::Mat ImageProcess::getForeImage(const Mat & src, const Mat &backgroundImg)
|
|
|
|
|
|
{
|
|
|
|
|
|
Mat resizedBackgroundImg = backgroundImg;
|
|
|
|
|
|
if (backgroundImg.size() != src.size()) {
|
|
|
|
|
|
resize(backgroundImg, resizedBackgroundImg, src.size());
|
|
|
|
|
|
}
|
|
|
|
|
|
return (src - resizedBackgroundImg);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//输入一张灰度图,输出抠出的圆小图和半径,圆心坐标
|
|
|
|
|
|
cv::Mat ImageProcess::findCircle(const Mat &srcImg, Point2f& center, double &radius, bool bEqual, int filterSize, const CircleParam& cParam)
|
|
|
|
|
|
{
|
|
|
|
|
|
Mat detectImg;
|
|
|
|
|
|
Mat src = srcImg;
|
|
|
|
|
|
|
|
|
|
|
|
cv::resize(src, detectImg, cv::Size(src.cols / REAIZE, src.rows / REAIZE));
|
|
|
|
|
|
int bBaseX = detectImg.cols;
|
|
|
|
|
|
int bBaseY = detectImg.rows;
|
|
|
|
|
|
if (bEqual == true)
|
|
|
|
|
|
equalizeHist(detectImg, detectImg);
|
|
|
|
|
|
detectImg = _EnhanImg_sharpen(detectImg);
|
|
|
|
|
|
|
|
|
|
|
|
EDCircles edcircles(detectImg);
|
|
|
|
|
|
vector<mCircle> EDCircle = edcircles.getCircles();
|
|
|
|
|
|
double maxR = 0;
|
|
|
|
|
|
int nIndex = -1;
|
|
|
|
|
|
float centerX = 0;
|
|
|
|
|
|
float centerY = 0;
|
|
|
|
|
|
double tmpmaxR = 0;
|
|
|
|
|
|
for (int i = 0; i < EDCircle.size(); i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
int startX = EDCircle[i].center.x - EDCircle[i].r;
|
|
|
|
|
|
int startY = EDCircle[i].center.y - EDCircle[i].r;
|
|
|
|
|
|
if (EDCircle[i].r > tmpmaxR)
|
|
|
|
|
|
{
|
|
|
|
|
|
centerX = EDCircle[i].center.x * REAIZE;
|
|
|
|
|
|
centerY = EDCircle[i].center.y * REAIZE;
|
|
|
|
|
|
tmpmaxR = EDCircle[i].r;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (startX < 0 || startY < 0)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
if (EDCircle[i].center.x + EDCircle[i].r > bBaseX || EDCircle[i].center.y + EDCircle[i].r > bBaseY)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
if ((EDCircle[i].r * REAIZE) < filterSize)//过滤半径小于指定宽度的圆
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
if (EDCircle[i].r > maxR)
|
|
|
|
|
|
{
|
|
|
|
|
|
maxR = EDCircle[i].r;
|
|
|
|
|
|
nIndex = i;
|
|
|
|
|
|
centerX = EDCircle[i].center.x * REAIZE;
|
|
|
|
|
|
centerY = EDCircle[i].center.y * REAIZE;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (nIndex != -1)//找到合适的圆 只需要圆心
|
|
|
|
|
|
{
|
|
|
|
|
|
radius = EDCircle[nIndex].r * REAIZE;
|
|
|
|
|
|
center.x = (EDCircle[nIndex].center.x * REAIZE);
|
|
|
|
|
|
center.y = (EDCircle[nIndex].center.y * REAIZE);
|
|
|
|
|
|
return DetectCircle(srcImg, Mat(), center, radius, bEqual, cParam);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
center.x = centerX;
|
|
|
|
|
|
center.y = centerY;
|
|
|
|
|
|
radius = 0;
|
|
|
|
|
|
return DetectCircle(srcImg, Mat(), center, radius, bEqual, cParam);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Mat ImageProcess::DetectCircle(Mat srcImg, Mat background, Point2f& center, double& radius, bool bEqual, const CircleParam& cParam)
|
|
|
|
|
|
{
|
|
|
|
|
|
Mat img;
|
|
|
|
|
|
if (!background.empty()) {
|
|
|
|
|
|
img = getForeImage(srcImg, background);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
img = srcImg;
|
|
|
|
|
|
}
|
|
|
|
|
|
Mat detectImg;
|
|
|
|
|
|
if (bEqual == true) {
|
|
|
|
|
|
equalizeHist(img, detectImg);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
detectImg = img;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CircleDetector cd;
|
|
|
|
|
|
cd.setAlgoType(CircleDetector::PeakCircle);
|
|
|
|
|
|
cd.setEdgeWidth(cParam.CircleEdgeWidth);
|
|
|
|
|
|
if (cParam.CirclePolarity == 0)
|
|
|
|
|
|
cd.setPolarity(Polarity::Black2White);
|
|
|
|
|
|
else
|
|
|
|
|
|
cd.setPolarity(Polarity::White2Black);
|
|
|
|
|
|
|
|
|
|
|
|
cd.setFindBy(FindBy::Best);
|
|
|
|
|
|
if (center.x == 0 || center.y == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
center.x = img.cols / 2;
|
|
|
|
|
|
center.y = img.rows / 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
int rY = img.rows - center.y;
|
|
|
|
|
|
int rX = img.cols - center.x;
|
|
|
|
|
|
int min_dify = center.y > rY ? rY : center.y;
|
|
|
|
|
|
int min_difx = center.x > rX ? rX : center.x;
|
|
|
|
|
|
int maxRadius = abs(abs(min_difx > min_dify ? min_dify : min_difx) - 50);
|
|
|
|
|
|
double difRadiusMin = radius - 150;
|
|
|
|
|
|
double difRadiusMax = radius + 250;
|
|
|
|
|
|
if (difRadiusMin <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
difRadiusMin = cParam.filterSize;
|
|
|
|
|
|
difRadiusMax = maxRadius;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//控制范围,不让检测越界
|
|
|
|
|
|
//if (difRadiusMin < cParam.filterSize)
|
|
|
|
|
|
difRadiusMin = cParam.filterSize;
|
|
|
|
|
|
//if (difRadiusMax > maxRadius)
|
|
|
|
|
|
difRadiusMax = maxRadius;
|
|
|
|
|
|
if (difRadiusMin > difRadiusMax)
|
|
|
|
|
|
difRadiusMin = 0;
|
|
|
|
|
|
|
|
|
|
|
|
cd.setRadii(difRadiusMin, difRadiusMax);
|
|
|
|
|
|
cd.setACThres(cParam.CircleACThres);
|
|
|
|
|
|
vector<float> allScores;
|
|
|
|
|
|
Vec3f bestCircle;
|
|
|
|
|
|
float bestScore = cd.detectBest(detectImg, Point2f(center.x, center.y), bestCircle, &allScores);
|
|
|
|
|
|
if (abs(bestScore) <= FLT_EPSILON || bestCircle == Vec3f::zeros()) {
|
|
|
|
|
|
center.x = 0;
|
|
|
|
|
|
center.y = 0;
|
|
|
|
|
|
radius = 0;
|
|
|
|
|
|
return Mat();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Point2f cen(bestCircle[0], bestCircle[1]);
|
|
|
|
|
|
double r = bestCircle[2];
|
|
|
|
|
|
Rect rect;
|
|
|
|
|
|
rect.x = cen.x - r;
|
|
|
|
|
|
rect.y = cen.y - r;
|
|
|
|
|
|
if (rect.x < 0)
|
|
|
|
|
|
rect.x = 0;
|
|
|
|
|
|
if (rect.y < 0)
|
|
|
|
|
|
rect.y = 0;
|
|
|
|
|
|
rect.width = 2 * r;
|
|
|
|
|
|
rect.height = 2 * r;
|
|
|
|
|
|
Mat s = srcImg(rect);
|
|
|
|
|
|
center = cen;
|
|
|
|
|
|
radius = r;
|
|
|
|
|
|
return s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//使用背景图做减法扣圆
|
|
|
|
|
|
cv::Mat ImageProcess::findCircleByBackground(const Mat &srcImg, const Mat& backgroundImg, Point2f& center, double &radius, bool bEqual, int filterSize, const CircleParam& cParam)
|
|
|
|
|
|
{
|
|
|
|
|
|
Mat detectImg;
|
|
|
|
|
|
Mat src = srcImg;
|
|
|
|
|
|
|
|
|
|
|
|
cv::resize(src, detectImg, cv::Size(src.cols / REAIZE, src.rows / REAIZE));
|
|
|
|
|
|
int bBaseX = detectImg.cols;
|
|
|
|
|
|
int bBaseY = detectImg.rows;
|
|
|
|
|
|
if (bEqual == true)
|
|
|
|
|
|
equalizeHist(detectImg, detectImg);
|
|
|
|
|
|
detectImg = _EnhanImg_sharpen(detectImg);
|
|
|
|
|
|
|
|
|
|
|
|
EDCircles edcircles(detectImg);
|
|
|
|
|
|
vector<mCircle> EDCircle = edcircles.getCircles();
|
|
|
|
|
|
double maxR = 0;
|
|
|
|
|
|
int nIndex = -1;
|
|
|
|
|
|
float centerX = 0;
|
|
|
|
|
|
float centerY = 0;
|
|
|
|
|
|
double tmpmaxR = 0;
|
|
|
|
|
|
for (int i = 0; i < EDCircle.size(); i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
int startX = EDCircle[i].center.x - EDCircle[i].r;
|
|
|
|
|
|
int startY = EDCircle[i].center.y - EDCircle[i].r;
|
|
|
|
|
|
if (EDCircle[i].r > tmpmaxR)
|
|
|
|
|
|
{
|
|
|
|
|
|
centerX = EDCircle[i].center.x * REAIZE;
|
|
|
|
|
|
centerY = EDCircle[i].center.y * REAIZE;
|
|
|
|
|
|
tmpmaxR = EDCircle[i].r;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (startX < 0 || startY < 0)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
if (EDCircle[i].center.x + EDCircle[i].r > bBaseX || EDCircle[i].center.y + EDCircle[i].r > bBaseY)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
if ((EDCircle[i].r * REAIZE) < filterSize)//过滤半径小于指定宽度的圆
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
if (EDCircle[i].r > maxR)
|
|
|
|
|
|
{
|
|
|
|
|
|
maxR = EDCircle[i].r;
|
|
|
|
|
|
nIndex = i;
|
|
|
|
|
|
centerX = EDCircle[i].center.x * REAIZE;
|
|
|
|
|
|
centerY = EDCircle[i].center.y * REAIZE;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (nIndex != -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
center.x = (EDCircle[nIndex].center.x * REAIZE);
|
|
|
|
|
|
center.y = (EDCircle[nIndex].center.y * REAIZE);
|
|
|
|
|
|
return DetectCircle(srcImg, backgroundImg, center, radius, bEqual, cParam);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
center.x = centerX;
|
|
|
|
|
|
center.y = centerY;
|
|
|
|
|
|
radius = 0;
|
|
|
|
|
|
return DetectCircle(srcImg, backgroundImg, center, radius, bEqual, cParam);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|