opencvsharp实现高精度亚像素canny搜索边 编写搜索边函数 参数设定找边的起始方向从左到右、从右到左、从上到下、从下到上、从白或黑边起第一条边
时间: 2023-07-10 12:04:36 浏览: 76
首先,需要了解一下Canny算法的基本原理。Canny算法主要分为以下几步:
1. 高斯滤波,降低噪声干扰。
2. 计算梯度和方向,找到边缘的方向。
3. 非极大值抑制,保留边缘上的最大值点。
4. 双阈值处理,将边缘分成强边缘和弱边缘。
5. 边缘连接,将弱边缘连接到强边缘上。
在实现高精度亚像素Canny搜索边的过程中,我们需要对第三步和第五步进行改进,以实现更精确的边缘搜索。具体实现如下:
1. 对于第三步,我们可以使用双线性插值来找到边缘上的亚像素点。具体来说,我们可以在梯度方向上找到相邻的两个像素点,然后根据梯度值的比例来计算插值点的位置,从而找到亚像素点。
2. 对于第五步,我们可以使用跟踪算法来将弱边缘连接到强边缘上。具体来说,我们可以从强边缘上的一个点开始,沿着梯度方向前进,直到找到一个弱边缘上的点。然后,我们可以继续沿着弱边缘前进,直到找到另一个强边缘上的点。这样,我们就可以将两个强边缘连接起来了。
下面是一个示例代码,用于实现高精度亚像素Canny搜索边的函数:
```csharp
public static Mat SearchEdge(Mat src, double threshold1, double threshold2, EdgeDirection direction, EdgeType type)
{
Mat gray = new Mat();
Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);
Mat blurred = new Mat();
Cv2.GaussianBlur(gray, blurred, new Size(3, 3), 0);
Mat edges = new Mat();
Cv2.Canny(blurred, edges, threshold1, threshold2);
Mat result = new Mat(src.Rows, src.Cols, MatType.CV_8UC1, new Scalar(0));
int startX, startY, endX, endY, stepX, stepY;
switch (direction)
{
case EdgeDirection.LeftToRight:
startX = 0;
startY = 0;
endX = src.Cols - 1;
endY = src.Rows - 1;
stepX = 1;
stepY = 1;
break;
case EdgeDirection.RightToLeft:
startX = src.Cols - 1;
startY = 0;
endX = 0;
endY = src.Rows - 1;
stepX = -1;
stepY = 1;
break;
case EdgeDirection.TopToBottom:
startX = 0;
startY = 0;
endX = src.Cols - 1;
endY = src.Rows - 1;
stepX = 1;
stepY = 1;
break;
case EdgeDirection.BottomToTop:
startX = 0;
startY = src.Rows - 1;
endX = src.Cols - 1;
endY = 0;
stepX = 1;
stepY = -1;
break;
}
for (int y = startY; y != endY; y += stepY)
{
for (int x = startX; x != endX; x += stepX)
{
if (edges.At<byte>(y, x) == 255)
{
Point pt = new Point(x, y);
Point pt2 = SearchSubPixelPoint(gray, pt, type);
Cv2.Circle(result, pt2, 2, new Scalar(255), -1);
}
}
}
return result;
}
public static Point SearchSubPixelPoint(Mat src, Point pt, EdgeType type)
{
int dx = 0, dy = 0;
switch (type)
{
case EdgeType.White:
dx = 1;
dy = -1;
break;
case EdgeType.Black:
dx = -1;
dy = 1;
break;
}
double[] grad = new double[2];
grad[0] = src.At<byte>(pt.Y, pt.X + dx) - src.At<byte>(pt.Y, pt.X - dx);
grad[1] = src.At<byte>(pt.Y + dy, pt.X) - src.At<byte>(pt.Y - dy, pt.X);
double norm = Math.Sqrt(grad[0] * grad[0] + grad[1] * grad[1]);
double theta = Math.Atan2(grad[1], grad[0]);
double x = pt.X;
double y = pt.Y;
double step = 0.1;
while (true)
{
double x1 = x + step * Math.Cos(theta);
double y1 = y + step * Math.Sin(theta);
double x2 = x - step * Math.Cos(theta);
double y2 = y - step * Math.Sin(theta);
if (type == EdgeType.White)
{
if (src.At<byte>((int)y1, (int)x1) > src.At<byte>((int)y2, (int)x2))
{
x = x1;
y = y1;
}
else
{
x = x2;
y = y2;
}
}
else
{
if (src.At<byte>((int)y1, (int)x1) < src.At<byte>((int)y2, (int)x2))
{
x = x1;
y = y1;
}
else
{
x = x2;
y = y2;
}
}
if (step < 0.01 || x < 0 || x >= src.Cols || y < 0 || y >= src.Rows)
{
break;
}
grad[0] = src.At<byte>((int)y, (int)x + dx) - src.At<byte>((int)y, (int)x - dx);
grad[1] = src.At<byte>((int)y + dy, (int)x) - src.At<byte>((int)y - dy, (int)x);
double norm1 = Math.Sqrt(grad[0] * grad[0] + grad[1] * grad[1]);
if (norm1 < norm * 0.1)
{
break;
}
norm = norm1;
theta = Math.Atan2(grad[1], grad[0]);
}
return new Point((int)Math.Round(x), (int)Math.Round(y));
}
public enum EdgeDirection
{
LeftToRight,
RightToLeft,
TopToBottom,
BottomToTop
}
public enum EdgeType
{
White,
Black
}
```
这个函数可以接受一个输入图像,以及Canny算法的两个阈值,搜索边缘的方向和类型作为参数。函数的返回值是一个二值化图像,其中白色像素表示找到的边缘点。
阅读全文