|
|
|
|
|
#include "ImageProcess.h"
|
|
|
|
|
|
#include "qstring.h"
|
|
|
|
|
|
#include "CVUtils.h"
|
|
|
|
|
|
#include "ED.h"
|
|
|
|
|
|
#include "EDLines.h"
|
|
|
|
|
|
#include "EDCircles.h"
|
|
|
|
|
|
#include "CircleDetector.h"
|
|
|
|
|
|
|
|
|
|
|
|
//摩轮宏定义 表示该算法用于摩轮型号识别检测
|
|
|
|
|
|
#define MOTO_DETECT
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
{
|
|
|
|
|
|
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;
|
|
|
|
|
|
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 (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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (nIndex != -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
int startX = EDCircle[nIndex].center.x * REAIZE - EDCircle[nIndex].r * REAIZE;
|
|
|
|
|
|
int startY = EDCircle[nIndex].center.y * REAIZE - EDCircle[nIndex].r* REAIZE;
|
|
|
|
|
|
radius = EDCircle[nIndex].r;
|
|
|
|
|
|
int hight = 2 * radius * REAIZE;
|
|
|
|
|
|
|
|
|
|
|
|
center.x = (EDCircle[nIndex].center.x * REAIZE);
|
|
|
|
|
|
center.y = (EDCircle[nIndex].center.y * REAIZE);
|
|
|
|
|
|
radius = radius * REAIZE;
|
|
|
|
|
|
return DetectCircle(srcImg, center, radius, bEqual);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {//EDCirle 没找到圆 直径调用精细找圆算法
|
|
|
|
|
|
center.x = srcImg.cols / 2;
|
|
|
|
|
|
center.y = srcImg.rows / 2;
|
|
|
|
|
|
radius = 0;
|
|
|
|
|
|
return DetectCircle(srcImg, center, radius, bEqual);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Mat ImageProcess::DetectCircle(Mat img, Point2f& center, double& radius, bool bEqual)
|
|
|
|
|
|
{
|
|
|
|
|
|
Mat detectImg;
|
|
|
|
|
|
if (bEqual == true)
|
|
|
|
|
|
{
|
|
|
|
|
|
equalizeHist(img, detectImg);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
detectImg = img;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CircleDetector cd;
|
|
|
|
|
|
cd.setAlgoType(CircleDetector::PeakCircle);
|
|
|
|
|
|
cd.setEdgeWidth(3);
|
|
|
|
|
|
cd.setPolarity(Polarity::White2Black);
|
|
|
|
|
|
cd.setFindBy(FindBy::Best);
|
|
|
|
|
|
double difRadiusMin = radius - 100;
|
|
|
|
|
|
double difRadiusMax = radius + 150;
|
|
|
|
|
|
if (difRadiusMin < 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
difRadiusMin = 0;
|
|
|
|
|
|
if(radius>0)
|
|
|
|
|
|
difRadiusMax = abs(center.y - (img.cols / 2)) - 50;
|
|
|
|
|
|
else {
|
|
|
|
|
|
int minV = (img.rows / 2) > (img.cols / 2) ? (img.cols / 2) : (img.rows / 2);
|
|
|
|
|
|
difRadiusMax = minV - 50;
|
|
|
|
|
|
center.x = img.cols / 2;
|
|
|
|
|
|
center.y = img.rows / 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
cd.setRadii(difRadiusMin, difRadiusMax);
|
|
|
|
|
|
cd.setACThres(3);
|
|
|
|
|
|
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 = img(rect);
|
|
|
|
|
|
center = cen;
|
|
|
|
|
|
radius = r;
|
|
|
|
|
|
return s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//使用背景图做减法扣圆
|
|
|
|
|
|
cv::Mat ImageProcess::findCircleByBackground(const Mat &src, const Mat& backgroundImg, luffy_base::luffyCircle *pCircle /*= NULL*/)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (src.empty() || backgroundImg.empty() || src.rows < 500) {
|
|
|
|
|
|
return Mat();
|
|
|
|
|
|
}
|
|
|
|
|
|
assert(backgroundImg.type() == CV_8UC1);
|
|
|
|
|
|
Mat imgTmp = src;
|
|
|
|
|
|
Mat foregroundImg = getForeImage(imgTmp, backgroundImg);
|
|
|
|
|
|
|
|
|
|
|
|
CircleDetector cd;
|
|
|
|
|
|
cd.setAlgoType(CircleDetector::PeakCircle);
|
|
|
|
|
|
cd.setEdgeWidth(6);
|
|
|
|
|
|
cd.setPolarity(Polarity::White2Black);
|
|
|
|
|
|
cd.setFindBy(FindBy::Best);
|
|
|
|
|
|
double difRadiusMin = 0;
|
|
|
|
|
|
double difRadiusMax = (foregroundImg.cols > foregroundImg.rows ? foregroundImg.rows / 2 : foregroundImg.cols / 2) - 50;
|
|
|
|
|
|
cd.setRadii(difRadiusMin, difRadiusMax);
|
|
|
|
|
|
cd.setACThres(3);
|
|
|
|
|
|
vector<float> allScores;
|
|
|
|
|
|
Vec3f bestCircle;
|
|
|
|
|
|
float bestScore = cd.detectBest(foregroundImg, Point2f(imgTmp.cols / 2, imgTmp.rows / 2), bestCircle, &allScores);
|
|
|
|
|
|
if (abs(bestScore) <= FLT_EPSILON || bestCircle == Vec3f::zeros()) {
|
|
|
|
|
|
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 rltMat = src(rect);
|
|
|
|
|
|
if (pCircle)
|
|
|
|
|
|
{
|
|
|
|
|
|
pCircle->fRadius = r;
|
|
|
|
|
|
pCircle->ptCenter = cen;
|
|
|
|
|
|
}
|
|
|
|
|
|
return rltMat;
|
|
|
|
|
|
}
|