Search code examples
c#imageimage-processinggraphicsedge-detection

Sobel Edge Detection output for 16bit grayscale image


I've seen many Sobel Edge Detecting Operations in C++ and C#, but I'm having great difficulty converting the code to operate on a 16bit graphic. Most of the code I've seen is programmed to operate on R.G.B style bitmaps. The graphic I have is in a ushort[] array with intensity values in each row,col pixel.

The following is the code I've come out with: (The issue is, that its not quite working...) With a fudge factor in place, it is finding edges perhaps, but it is also finding a lot of noise.

However if I save the original file as a JPG, and run it into a another alternative Sobel-Edge-Detector C# code that accepts Bitmaps, it is a lot better... almost no noise! Shouldn't my 16bit Grayscale version be better?! But it must be my code is just not up to snuff. I'm not understanding the logic.

    public void sobel()
    {

        ushort[] pixels = new ushort[9];
        ushort[,] imageData = image_array[0].GetArray();
        ushort[,] imageOut = (ushort[,])imageData.Clone();
        uint xDim = (ushort)(imageData.GetLength(1) - imageData.GetLength(1) % regions);
        uint yDim = (ushort)(imageData.GetLength(0) - imageData.GetLength(0) % regions);

        double intensityX = 0.0;
        double intensityY = 0.0;
        double intensityTotal = 0.0;
        int limit = 1000000; //Just arbitrary junk number

        int filterOffset = 1;

        for (int offsetY = filterOffset; offsetY <
            yDim - (filterOffset+1); offsetY++)
        {

            for (int offsetX = filterOffset; offsetX <
                xDim - (filterOffset+1); offsetX++)
            {
                //intensityX = intensityY = 0;
                //intensityTotal = 0;

                pixels[0] = imageData[offsetY - 1, offsetX - 1];
                pixels[1] = imageData[offsetY - 1, offsetX];
                pixels[2] = imageData[offsetY - 1, offsetX + 1];
                pixels[3] = imageData[offsetY, offsetX - 1];
                pixels[4] = imageData[offsetY, offsetX];
                pixels[5] = imageData[offsetY, offsetX + 1];
                pixels[6] = imageData[offsetY + 1, offsetX - 1];
                pixels[7] = imageData[offsetY + 1, offsetX];
                pixels[8] = imageData[offsetY + 1, offsetX + 1];

                intensityX = pixels[8] + 2 * pixels[5] + pixels[2] - pixels[0] - 2 * pixels[3] - pixels[6];
                intensityY = pixels[8] + 2 * pixels[7] + pixels[6] - pixels[2] - 2 * pixels[1] - pixels[0];

                //intensityTotal = Math.Sqrt((intensityX * intensityX) + (intensityY * intensityY));
                //intensityTotal = Math.Abs(intensityX) + Math.Abs(intensityY);
                intensityTotal = intensityX * intensityX + intensityY * intensityY;
                //int sobel = (int)Math.Sqrt((xSobel * xSobel) + (ySobel * ySobel));

                //if (intensityTotal > MaximumValue)
                  //  intensityTotal = MaximumValue; //Presumably Black

                //if (intensityTotal < -1000) //1000 fudgefactor ...still not working correctly
                  //  intensityTotal = MinimumValue; //Presumably White
                //if (intensityTotal < (MinimumValue - 1000))
                  //  intensityTotal = MaximumValue;

                if (intensityTotal > limit)
                    imageOut[offsetY, offsetX] = MinimumValue;
                else
                    imageOut[offsetY, offsetX] = MaximumValue;

                //imageOut[offsetY, offsetX] = (ushort)intensityTotal;
            }

        }

        SetImageArrayItem(ImageDataIndex.RAWData, new DiskBackedArray(imageOut));

    }

Just assume 'image_array', xDim, yDim are givens. You'll notice some commented out other attempts.


Solution

  • Sobel (and other gradient-based filter) is suffered from noise. You can prefilter your picture with Gauss smoothing and compare results. Note that limit = 1000000 for squared difference corresponds to diff magnitudes about 1000 - this is rather small value for 16-bit (MAX=65535) picture.
    Saving in JPG makes a picture more blurred - sharp edges are smeared, high-frequency noise is lowered. So play a bit with mild smoothing and limit.