C#: Sobel gradient magnitude on a diagonal edge
Combine horizontal and vertical Sobel responses into one edge-strength value.
On this page
C# two-dimensional arrays and Math.Sqrt.
- Combine horizontal and vertical Sobel responses into one edge-strength value.
- Predict the sample output and explain the state changes.
- Complete the practice task and check the boundary cases.
The concept
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.
Code example
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
Follow the code
Open the walkthrough to inspect the example one step at a time.
Show guided walkthrough
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 |
Behind the scenes
How C# processes this code
C# compiles to code for the .NET runtime, which invokes the program entry point.
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.