func maskFor(in image.Image) image.Image { b := in.Bounds() // thumb size, corresponds to first convert command thumbWidth := int(b.Dx() / 5) thumbHeight := int(b.Dy() / 5) thumb := image.NewRGBA(image.Rect(0, 0, thumbWidth, thumbHeight)) final := image.NewRGBA(image.Rect(0, 0, b.Dx(), b.Dy())) // fill black (xc:black) // draw white rectangle (1,1 : thumbWidth-1,thumbHeight-1) for y := 0; y < thumbHeight; y++ { for x := 0; x < thumbWidth; x++ { if (y > 0 && y < thumbHeight-1) && (x > 0 && x < thumbWidth-1) { thumb.Set(x, y, color.White) } else { thumb.Set(x, y, color.Black) } } } // apply Gaussian blur with radius=7, sigma=15 graphics.Blur(thumb, thumb, &graphics.BlurOptions{2, 7}) // now resize to original image size resized := resize.Resize(uint(b.Dx()), uint(b.Dy()), thumb, resize.Bilinear) // with gaussian blur radius=0, sigma=5 graphics.Blur(final, resized, &graphics.BlurOptions{5, 0}) return final }
// 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 } } }