求算法高手帮解决一个问题
如图,我的代码功能就是把图中的白色球用矩形框出来,想优化下算法。
下面贴找白色球部分的代码。
public static bool init(Bitmap bmp)
{
try
{
lightPoints = new Rectangle[POINTNUM];
int DIA = 20; //光斑最小直径
int[,] Centers = new int[POINTNUM, 3]; //圆心二维数组【横坐标,纵坐标,半径】
int Gate = 100; //亮度临界点
int Count = 0; //圆心计数器
int xPoint = 0; //圆顶点横坐标
int yPoint = 0; //圆顶点纵坐标
int radius = 0; //圆半径
int ox = 0; //圆心横坐标
int oy = 0; //圆心纵坐标
int yTraversal = 0; //纵向遍历标记0
bool touchCircle = false; //没有接触到圆
bool topPoint = false; //未找到顶点
bool firstPoint = false; //未找到横向首点
//下面的循环找顶点
for (yTraversal = 10; yTraversal < bmp.Height - 10; yTraversal = yTraversal + 10) //之所以要留出10像素的框是因为边界颜色是淡灰色的,容易被误认为是圆内
{
for (int xTra = 10; xTra < bmp.Width - 10; xTra = xTra + 10) //先横向扫描,+10为了提高效率
{
if (Count < POINTNUM)
{
if (inFoundCircle(Centers, xTra, yTraversal, Count)) //如果这个点在已经发现的圆内了,那就没必要判断了,我们要找的是圆的定点
{
continue;
}
else
{
if (getPixelByGray(bmp, xTra, yTraversal) > Gate && !firstPoint) //圆内了,且是首次进圆
{
xTra = xTra - 11; //使横坐标倒退1
touchCircle = true;
}
else if (getPixelByGray(bmp, xTra, yTraversal) < Gate && touchCircle && !firstPoint) //刚到圆外,且未找到首点,横坐标+1即可确定首点横坐标
{
xPoint = xTra; //理论上圆的顶点是个点,但是图片中圆的顶部可能是条线,我们算它的中点作为顶点,所以要记收尾坐标
xTra = xTra - 9;
firstPoint = true;
}
else if (getPixelByGray(bmp, xTra, yTraversal) > Gate && touchCircle && firstPoint) //又到圆内了,且是首点
{
xTra = xTra - 9;
}
else if (getPixelByGray(bmp, xTra, yTraversal) < Gate && touchCircle && firstPoint) //刚出圆,且是尾点
{
xPoint = (xPoint + xTra - 1) / 2; //顶点横坐标
yPoint = yTraversal; //顶点纵坐标
topPoint = true;
firstPoint = false;
touchCircle = false;
}
} //end else
//找到顶点了,开始找直径
if (topPoint)
{
for (int iTra = yTraversal; iTra > 10; iTra--)
{
if (getPixelByGray(bmp, xPoint, iTra) < Gate) //出圆了!
{
yTraversal = iTra + 1;
break;
}
}
for (int iTra = yTraversal; iTra < bmp.Height - 10; iTra++) //后纵向扫描
{
if (getPixelByGray(bmp, xPoint, iTra) < Gate && iTra -DIA > yTraversal) //出圆了!
{
radius = (iTra - yTraversal - 1) / 2; //半径
ox = xPoint; //圆心横坐标
oy = (iTra + yTraversal - 1) / 2; //圆心纵坐标
Centers[Count,0] = ox; //保存圆心的横坐标
Centers[Count,1] = oy; //保存圆心的纵坐标
Centers[Count,2] = radius; //保存圆的半径
//记录矩形
lightPoints[Count].X = ox - radius; //矩形左上角横坐标
lightPoints[Count].Y = oy - radius; //矩形左上角纵坐标
lightPoints[Count].Width = 2 * radius; //矩形宽
lightPoints[Count].Height = 2 * radius; //矩形长
topPoint = false;
Count++;
break;
}
}
}
} //end if
else break;
}
}
return true;
} //end try
catch (System.Exception ex)
{
MessageBox.Show(ex.ToString() + "IIPOINT");
return false;
}
}
//判断图片上一点是否在光斑内
public static bool inFoundCircle(int[,] centers, int x, int y, int num)
{
for (int iTra = 0; iTra < num; iTra++)
{
if (((x - centers[iTra, 0]) * (x - centers[iTra, 0]) + (y - centers[iTra, 1]) * (y - centers[iTra, 1])) <= (centers[iTra, 2] + 20) * (centers[iTra, 2] + 20))
//为了效率,避免了除法和开方,原公式为计算点到圆心距离与半径大小,这个经过了变形
//原式:[(x-ox)^2+(y-oy)^2]<=r^2把圆扩大了一圈(r=r+10)
{
return true;
}
}
return false;
}
//计算图片上一点的灰度值
public static int getPixelByGray(Bitmap bmp, int x, int y)
{
Color color = bmp.GetPixel(x, y);
return color.R + color.G + color.B;//算平均值获得灰度,为了效率不除3了,反正只判断大小
}
算法 性能优化
[解决办法]
楼主这个算法叫什么,有相关理论链接吗?发一个,有空研究下,比较有趣
[解决办法]
直接用OpenCV好了,代码少,效率高。
http://wenku.baidu.com/view/96e75a41a8956bec0975e327
[解决办法]
http://www.aiseminar.cn/bbs/forum.php?mod=viewthread&tid=617
http://www.cnblogs.com/tornadomeet/archive/2012/12/11/2813534.html
http://blog.csdn.net/byxdaz/article/details/5807639