opencvsharp实现高精度亚像素canny搜索边 编写搜索边函数 参数设定找边的起始方向从左到右、从右到左、从上到下、从下到上、从白或黑边起,输出点集
时间: 2023-07-10 22:04:35 浏览: 174
OpenCv实现Canny边缘检测
5星 · 资源好评率100%
以下是使用OpenCvSharp实现高精度亚像素Canny搜索边的代码:
```csharp
using OpenCvSharp;
public static List<Point> SearchEdge(Mat src, int threshold1, int threshold2, int apertureSize, bool L2gradient, Point start, EdgeDirection direction, EdgeType type)
{
Mat gray = new Mat();
Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);
Mat edges = new Mat();
Cv2.Canny(gray, edges, threshold1, threshold2, apertureSize, L2gradient);
List<Point> points = new List<Point>();
Point current = start;
Point next = new Point(-1, -1);
while (next != start)
{
points.Add(current);
List<Point> candidates = GetCandidates(edges, current, direction);
if (candidates.Count == 0)
{
break;
}
if (type == EdgeType.White)
{
next = GetNextWhiteEdge(candidates, gray, current, direction);
}
else
{
next = GetNextBlackEdge(candidates, gray, current, direction);
}
current = next;
}
return points;
}
private static List<Point> GetCandidates(Mat edges, Point p, EdgeDirection direction)
{
List<Point> candidates = new List<Point>();
switch (direction)
{
case EdgeDirection.LeftToRight:
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
if (i == 0 && j == 0)
{
continue;
}
if (p.X + i >= 0 && p.X + i < edges.Width && p.Y + j >= 0 && p.Y + j < edges.Height)
{
if (edges.At<byte>(p.Y + j, p.X + i) == 255)
{
candidates.Add(new Point(p.X + i, p.Y + j));
}
}
}
}
break;
case EdgeDirection.RightToLeft:
for (int i = 1; i >= -1; i--)
{
for (int j = -1; j <= 1; j++)
{
if (i == 0 && j == 0)
{
continue;
}
if (p.X + i >= 0 && p.X + i < edges.Width && p.Y + j >= 0 && p.Y + j < edges.Height)
{
if (edges.At<byte>(p.Y + j, p.X + i) == 255)
{
candidates.Add(new Point(p.X + i, p.Y + j));
}
}
}
}
break;
case EdgeDirection.TopToBottom:
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
if (i == 0 && j == 0)
{
continue;
}
if (p.X + i >= 0 && p.X + i < edges.Width && p.Y + j >= 0 && p.Y + j < edges.Height)
{
if (edges.At<byte>(p.Y + j, p.X + i) == 255)
{
candidates.Add(new Point(p.X + i, p.Y + j));
}
}
}
}
break;
case EdgeDirection.BottomToTop:
for (int i = -1; i <= 1; i++)
{
for (int j = 1; j >= -1; j--)
{
if (i == 0 && j == 0)
{
continue;
}
if (p.X + i >= 0 && p.X + i < edges.Width && p.Y + j >= 0 && p.Y + j < edges.Height)
{
if (edges.At<byte>(p.Y + j, p.X + i) == 255)
{
candidates.Add(new Point(p.X + i, p.Y + j));
}
}
}
}
break;
}
return candidates;
}
private static Point GetNextWhiteEdge(List<Point> candidates, Mat gray, Point current, EdgeDirection direction)
{
double maxDistance = double.MinValue;
Point next = new Point(-1, -1);
foreach (Point candidate in candidates)
{
double distance = GetWhiteEdgeDistance(gray, current, candidate, direction);
if (distance > maxDistance)
{
maxDistance = distance;
next = candidate;
}
}
return next;
}
private static Point GetNextBlackEdge(List<Point> candidates, Mat gray, Point current, EdgeDirection direction)
{
double minDistance = double.MaxValue;
Point next = new Point(-1, -1);
foreach (Point candidate in candidates)
{
double distance = GetBlackEdgeDistance(gray, current, candidate, direction);
if (distance < minDistance)
{
minDistance = distance;
next = candidate;
}
}
return next;
}
private static double GetWhiteEdgeDistance(Mat gray, Point start, Point end, EdgeDirection direction)
{
int dx = end.X - start.X;
int dy = end.Y - start.Y;
double distance = 0;
if (direction == EdgeDirection.LeftToRight || direction == EdgeDirection.RightToLeft)
{
int steps = Math.Abs(dx);
double d = (double)dy / (double)dx;
double y = start.Y;
for (int i = 0; i < steps; i++)
{
double x = start.X + i * Math.Sign(dx);
double v1 = gray.At<byte>((int)Math.Floor(y), (int)Math.Floor(x));
double v2 = gray.At<byte>((int)Math.Ceiling(y), (int)Math.Floor(x));
double v3 = gray.At<byte>((int)Math.Floor(y), (int)Math.Ceiling(x));
double v4 = gray.At<byte>((int)Math.Ceiling(y), (int)Math.Ceiling(x));
double fx1 = (double)v1 + (x - Math.Floor(x)) * ((double)v3 - (double)v1);
double fx2 = (double)v2 + (x - Math.Floor(x)) * ((double)v4 - (double)v2);
double fy = fx1 + (y - Math.Floor(y)) * (fx2 - fx1);
distance += Math.Abs(fy - 255);
y += d;
}
}
else
{
int steps = Math.Abs(dy);
double d = (double)dx / (double)dy;
double x = start.X;
for (int i = 0; i < steps; i++)
{
double y = start.Y + i * Math.Sign(dy);
double v1 = gray.At<byte>((int)Math.Floor(y), (int)Math.Floor(x));
double v2 = gray.At<byte>((int)Math.Ceiling(y), (int)Math.Floor(x));
double v3 = gray.At<byte>((int)Math.Floor(y), (int)Math.Ceiling(x));
double v4 = gray.At<byte>((int)Math.Ceiling(y), (int)Math.Ceiling(x));
double fy1 = (double)v1 + (y - Math.Floor(y)) * ((double)v2 - (double)v1);
double fy2 = (double)v3 + (y - Math.Floor(y)) * ((double)v4 - (double)v3);
double fx = fy1 + (x - Math.Floor(x)) * (fy2 - fy1);
distance += Math.Abs(fx - 255);
x += d;
}
}
return distance;
}
private static double GetBlackEdgeDistance(Mat gray, Point start, Point end, EdgeDirection direction)
{
int dx = end.X - start.X;
int dy = end.Y - start.Y;
double distance = 0;
if (direction == EdgeDirection.LeftToRight || direction == EdgeDirection.RightToLeft)
{
int steps = Math.Abs(dx);
double d = (double)dy / (double)dx;
double y = start.Y;
for (int i = 0; i < steps; i++)
{
double x = start.X + i * Math.Sign(dx);
double v1 = gray.At<byte>((int)Math.Floor(y), (int)Math.Floor(x));
double v2 = gray.At<byte>((int)Math.Ceiling(y), (int)Math.Floor(x));
double v3 = gray.At<byte>((int)Math.Floor(y), (int)Math.Ceiling(x));
double v4 = gray.At<byte>((int)Math.Ceiling(y), (int)Math.Ceiling(x));
double fx1 = (double)v1 + (x - Math.Floor(x)) * ((double)v3 - (double)v1);
double fx2 = (double)v2 + (x - Math.Floor(x)) * ((double)v4 - (double)v2);
double fy = fx1 + (y - Math.Floor(y)) * (fx2 - fx1);
distance += Math.Abs(fy);
y += d;
}
}
else
{
int steps = Math.Abs(dy);
double d = (double)dx / (double)dy;
double x = start.X;
for (int i = 0; i < steps; i++)
{
double y = start.Y + i * Math.Sign(dy);
double v1 = gray.At<byte>((int)Math.Floor(y), (int)Math.Floor(x));
double v2 = gray.At<byte>((int)Math.Ceiling(y), (int)Math.Floor(x));
double v3 = gray.At<byte>((int)Math.Floor(y), (int)Math.Ceiling(x));
double v4 = gray.At<byte>((int)Math.Ceiling(y), (int)Math.Ceiling(x));
double fy1 = (double)v1 + (y - Math.Floor(y)) * ((double)v2 - (double)v1);
double fy2 = (double)v3 + (y - Math.Floor(y)) * ((double)v4 - (double)v3);
double fx = fy1 + (x - Math.Floor(x)) * (fy2 - fy1);
distance += Math.Abs(fx);
x += d;
}
}
return distance;
}
```
其中,`SearchEdge`函数用于搜索边缘点集,输入参数包括源图像`src`、Canny算子的两个阈值`threshold1`和`threshold2`、算子的孔径大小`apertureSize`、是否使用L2梯度`L2gradient`、起始点`start`、搜索方向`direction`以及搜索的边缘类型`type`。输出点集为`List<Point>`类型。
`GetCandidates`函数根据搜索方向获取候选点集,输入参数包括边缘图像`edges`、起始点`p`和搜索方向`direction`。输出点集为`List<Point>`类型。
`GetNextWhiteEdge`和`GetNextBlackEdge`函数根据边缘类型获取下一个边缘点,输入参数包括候选点集`candidates`、灰度图像`gray`、当前点`current`和搜索方向`direction`。输出点为`Point`类型。
`GetWhiteEdgeDistance`和`GetBlackEdgeDistance`函数分别计算白边和黑边的距离,输入参数包括灰度图像`gray`、起始点`start`、结束点`end`和搜索方向`direction`。输出为`double`类型,表示距离。
需要注意的是,`GetWhiteEdgeDistance`和`GetBlackEdgeDistance`函数中的插值算法使用双线性插值。
阅读全文