// Canny detects and returns edges from the given image. // Each dst pixel is given one of three values: // 0xff: an edge // 0x80: possibly an edge // 0x00: not an edge func Canny(dst *image.Gray, src image.Image) error { if dst == nil { return errors.New("edge: dst is nil") } if src == nil { return errors.New("edge: src is nil") } b := src.Bounds() srcGray, ok := src.(*image.Gray) if !ok { srcGray = image.NewGray(b) draw.Draw(srcGray, b, src, b.Min, draw.Src) } if err := graphics.Blur(srcGray, srcGray, nil); err != nil { return err } mag, dir := image.NewGray(b), image.NewGray(b) if err := Sobel(mag, dir, srcGray); err != nil { return err } // Non-maximum supression. for y := b.Min.Y; y < b.Max.Y; y++ { for x := b.Min.X; x < b.Max.X; x++ { d := dir.Pix[(y-b.Min.Y)*dir.Stride+(x-b.Min.X)*1] var m0, m1 uint8 switch d { case 0: // west and east m0 = atOrZero(mag, x-1, y) m1 = atOrZero(mag, x+1, y) case 45: // north-east and south-west m0 = atOrZero(mag, x+1, y-1) m1 = atOrZero(mag, x-1, y+1) case 90: // north and south m0 = atOrZero(mag, x, y-1) m1 = atOrZero(mag, x, y+1) case 135: // north-west and south-east m0 = atOrZero(mag, x-1, y-1) m1 = atOrZero(mag, x+1, y+1) default: return fmt.Errorf("edge: bad direction (%d, %d): %d", x, y, d) } m := mag.Pix[(y-b.Min.Y)*mag.Stride+(x-b.Min.X)*1] if m > m0 && m > m1 { m = 0xff } else if m > m0 || m > m1 { m = 0x80 } else { m = 0x00 } dst.Pix[(y-b.Min.Y)*dst.Stride+(x-b.Min.X)*1] = m } } return nil }
// DifferenceOfGaussians produces the difference of Gaussians sd0 and sd1. func DifferenceOfGaussians(dst *image.Gray, src image.Image, sd0, sd1 float64) { b := src.Bounds() srcg := image.NewGray(b) m0 := image.NewGray(b) m1 := image.NewGray(b) draw.Draw(srcg, b, src, b.Min, draw.Src) graphics.Blur(m0, srcg, &graphics.BlurOptions{StdDev: sd0}) graphics.Blur(m1, srcg, &graphics.BlurOptions{StdDev: sd1}) for y := b.Min.Y; y < b.Max.Y; y++ { for x := b.Min.X; x < b.Max.X; x++ { off := (y-m0.Rect.Min.Y)*m0.Stride + (x - m0.Rect.Min.X) c := m0.Pix[off] - m1.Pix[off] if c < 0 { c = -c } doff := (y-dst.Rect.Min.Y)*dst.Stride + (x - dst.Rect.Min.X) dst.Pix[doff] = c } } }