C#: Sobel gradient magnitude on a diagonal edge
Combine horizontal and vertical Sobel responses into one edge-strength value.
using System;
class Program {
static void Main() {
int[,] image = new int[5, 5];
for (int r = 0; r < 5; r++) {
for (int c = 0; c < 5; c++) {
image[r, c] = c >= r ? 100 : 0;
}
}
int[,] kx = { { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 } };
int[,] ky = { { -1, -2, -1 }, { 0, 0, 0 }, { 1, 2, 1 } };
for (int r = 1; r < 4; r++) {
string row = "";
for (int c = 1; c < 4; c++) {
int gx = 0, gy = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
int pixel = image[r - 1 + i, c - 1 + j];
gx += pixel * kx[i, j];
gy += pixel * ky[i, j];
}
}
row += ((int)Math.Round(Math.Sqrt(gx * gx + gy * gy))).ToString().PadLeft(5);
}
Console.WriteLine(row);
}
}
}424 141 0 424 424 141 141 424 424
Explanation
The Sobel operator uses two 3×3 kernels, one for the horizontal gradient Gx and one for the vertical gradient Gy. The strength of an edge at a pixel is the gradient magnitude √(Gx² + Gy²), and the angle of the edge normal is atan2(Gy, Gx).
The test image is dark below a diagonal line and bright above and on it. A horizontal or vertical edge gives a response in one kernel only. A diagonal edge produces a response in both, and the magnitude combines them. Flat areas, away from the edge, give zero.
Explore the dry run
using System; class Program { static void Main() { int[,] image = new int[5, 5]; for (int r = 0; r < 5; r++) { for (int c = 0; c < 5; c++) { image[r, c] = c >= r ? 100 : 0; } } int[,] kx = { { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 } }; int[,] ky = { { -1, -2, -1 }, { 0, 0, 0 }, { 1, 2, 1 } }; for (int r = 1; r < 4; r++) { string row = ""; for (int c = 1; c < 4; c++) { int gx = 0, gy = 0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { int pixel = image[r - 1 + i, c - 1 + j]; gx += pixel * kx[i, j]; gy += pixel * ky[i, j]; } } row += ((int)Math.Round(Math.Sqrt(gx * gx + gy * gy))).ToString().PadLeft(5); } Console.WriteLine(row); } }}Follow the example
Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.
View the complete dry-run table
| Step / line | What happens | State after step | Output so far |
|---|---|---|---|
| Pixels on or above the main diagonal are bright; those below are dark. | a diagonal step edge | — | |
| The vertical kernel is the horizontal kernel rotated: it subtracts the row above from the row below. | a diagonal step edge | — | |
| Both responses are accumulated for the same window. | gx and gy for this window | — | |
| Combine them into one magnitude per pixel. | magnitude = √(gx² + gy²) | — | |
| The value 424 (about 300·√2) appears on and next to the diagonal, while the window far above it is flat, so it gives 0. | magnitude = √(gx² + gy²) | 424 141 0 424 424 141 141 424 424 |
Cost and common mistakes
O(R·C) for a fixed 3×3 kernel.
- Adding |gx| + |gy| is a cheaper approximation of the magnitude that is often good enough.
- Sobel responds to noise as well as edges, so smooth the image first and then choose a threshold.
- The border pixels are skipped here because the kernel would extend outside the image.
Try it yourself
What is the magnitude where the window contains only bright pixels?
Reveal answer and reasoning
Zero. Gx and Gy both cancel when all nine pixels have the same value.