我解决了设计基于@Abhishek 思想的函数的问题。
这是伪代码及其 C++ 实现。
checkCircleSectors(imagePoints, circle, circleExpansionFactor, theta, acceptThreshold)
Divide the circle in n sectors, using angle theta (so n = 2*PI /theta)
(Optional) Slightly expand or reduce the radius of the circle by circleExpansionFactor, if needed.
for each point "curPoint" within the image (imagePoints){
if the distance between curPoint and center.circle is lesser/equal to circle.radius{
let "curAngle" be the angle between circle.center and curPoint, calculated using curPoint as origin.
let "curSector" be the sector of circle which contains curAngle
upgrade the ranking of curSector by one.
}
}
if there are more than acceptThreshold sectors whose rank is zero
the circle is not acceptable
else
the circle is acceptable
注意事项:
我发现稍微扩大圆的半径非常有用(我使用 1.25 的扩大系数),因为有时(特别是在手写圆的情况下)检测可能不准确。 p>
这是我对该概念的 C++ 实现:
boolean ImgCheck::checkCircleSectors(vector<Point> tgtPoints, Point tgtCenter, int tgtRadius, float tgtRadiusExp, int tgtStep, int tgtThreshold){
vector<int> circleData( 360 / tgtStep, 0);
int detectionReliability = 0;
tgtRadius = tgtRadius * tgtRadiusExp;
/* Analyze the sectors. */
for(size_t i=0; i<tgtPoints.size(); i++){
Point curCartesianPoint = getCartesianCoordinates(tgtCenter, tgtPoints[i]);
float angleRad = arctangent2(curCartesianPoint);
int angleDeg = angleRad * (180/M_PI);
if(distance(tgtPoints[i],tgtCenter) <= tgtRadius){
circleData.at(angleDeg / tgtStep) += 1;
}
}
/* Count the postive-ranked sectors. */
for(size_t i = 0; i< circleData.size(); i++){
if(circleData[i] > 0)
detectionReliability += 100.0/(360/tgtStep);
}
if(detectionReliability >= tgtThreshold)
return true;
}
return false;
}
注意事项:
我对最后三个参数的偏好如下:
- tgtRadiusExp = 1.25(半径扩大四分之一长度)
- tgtStep = 5(theta = 5 度 -> 圆分为 72 个扇区)
- tgtTreshold = 75(至少需要 75 个非零扇区才能通过测试)
getCartesianCoordinates 函数(以下源代码)将 OpenCV 坐标转换为笛卡尔坐标。它需要两个参数:
- Point tgtOrigin 是该点的 openCV 坐标,必须是
用作原点。
- 点 tgtPoint 是另一个点的 openCV 坐标。
函数返回tgtPoint的坐标,以tgtOrigin为原点进行转换。
Point getCartesianCoordinates(Point tgtOrigin, Point tgtPoint){
Point resPoint = tgtPoint - tgtOrigin;
return Point(resPoint.x, -resPoint.y);
}