func drawsq(b *draw.Image, p image.Point, ptx int) { var r image.Rectangle r.Min = p r.Max.X = r.Min.X + pcsz r.Max.Y = r.Min.Y + pcsz b.Draw(r, display.Black, nil, image.ZP) b.Draw(r.Inset(1), tx[ptx], nil, image.ZP) }
func drawsq(b draw.Image, p image.Point, ptx int) { var r image.Rectangle r.Min = p r.Max.X = r.Min.X + pcsz r.Max.Y = r.Min.Y + pcsz draw.Draw(b, r, image.Black, image.ZP) draw.Draw(b, r.Inset(1), txpix[ptx], image.ZP) }
func FeatSize(pix image.Point, conf Config) image.Point { // Leave a one-pixel border to compute derivatives. inside := image.Rectangle{image.ZP, pix}.Inset(1) // Leave a half-cell border. half := conf.CellSize / 2 valid := inside.Inset(half) // Number of whole cells inside valid region. cells := valid.Size().Div(conf.CellSize) if cells.X <= 0 || cells.Y <= 0 { return image.ZP } // Remove one cell on all sides for output. out := cells.Sub(image.Pt(2, 2)) return out }
func drawRectangle(img draw.Image, rectangle *image.Rectangle) { diff := rectangle.Inset(-5) red := &image.Uniform{color.RGBA{255, 0, 0, 255}} minX := diff.Min.X maxX := diff.Max.X minY := diff.Min.Y maxY := diff.Max.Y topLine := image.Rect(minX-lineWidth, minY, maxX+lineWidth, minY-lineWidth) bottomLine := image.Rect(minX-lineWidth, maxY, maxX+lineWidth, maxY+lineWidth) leftLine := image.Rect(minX-lineWidth, minY-lineWidth, minX, maxY+lineWidth) rightLine := image.Rect(maxX, minY-lineWidth, maxX+lineWidth, maxY+lineWidth) draw.Draw(img, topLine, red, image.ZP, draw.Src) draw.Draw(img, bottomLine, red, image.ZP, draw.Src) draw.Draw(img, leftLine, red, image.ZP, draw.Src) draw.Draw(img, rightLine, red, image.ZP, draw.Src) }
func setpiece(p *Piece) { bb.Draw(bb.R, display.White, nil, image.ZP) bbmask.Draw(bb.R, display.Transparent, nil, image.ZP) br = image.Rect(0, 0, 0, 0) br2 = br piece = p if p == nil { return } var op image.Point var r image.Rectangle r.Min = bb.R.Min for i, pt := range p.d { r.Min.X += pt.X * pcsz r.Min.Y += pt.Y * pcsz r.Max.X = r.Min.X + pcsz r.Max.Y = r.Min.Y + pcsz if i == 0 { bb.Draw(r, display.Black, nil, image.ZP) bb.Draw(r.Inset(1), tx[piece.tx], nil, image.ZP) bbmask.Draw(r, display.Opaque, nil, image.ZP) op = r.Min } else { bb.Draw(r, bb, nil, op) bbmask.Draw(r, bbmask, nil, op) } if br.Max.X < r.Max.X { br.Max.X = r.Max.X } if br.Max.Y < r.Max.Y { br.Max.Y = r.Max.Y } } br.Max = br.Max.Sub(bb.R.Min) delta := image.Pt(0, DY) br2.Max = br.Max.Add(delta) r = br.Add(bb2.R.Min) r2 := br2.Add(bb2.R.Min) bb2.Draw(r2, display.White, nil, image.ZP) bb2.Draw(r.Add(delta), bb, nil, bb.R.Min) bb2mask.Draw(r2, display.Transparent, nil, image.ZP) bb2mask.Draw(r, display.Opaque, bbmask, bb.R.Min) bb2mask.Draw(r.Add(delta), display.Opaque, bbmask, bb.R.Min) }
func setpiece(p *Piece) { draw.Draw(bb, bbr, image.White, image.ZP) draw.Draw(bbmask, bbr, image.Transparent, image.ZP) br = image.Rect(0, 0, 0, 0) br2 = br piece = p if p == nil { return } var op image.Point var r image.Rectangle r.Min = bbr.Min for i, pt := range p.d { r.Min.X += pt.X * pcsz r.Min.Y += pt.Y * pcsz r.Max.X = r.Min.X + pcsz r.Max.Y = r.Min.Y + pcsz if i == 0 { draw.Draw(bb, r, image.Black, image.ZP) draw.Draw(bb, r.Inset(1), txpix[piece.tx], image.ZP) draw.Draw(bbmask, r, image.Opaque, image.ZP) op = r.Min } else { draw.Draw(bb, r, bb, op) draw.Draw(bbmask, r, bbmask, op) } if br.Max.X < r.Max.X { br.Max.X = r.Max.X } if br.Max.Y < r.Max.Y { br.Max.Y = r.Max.Y } } br.Max = br.Max.Sub(bbr.Min) delta := image.Pt(0, DY) br2.Max = br.Max.Add(delta) r = br.Add(bb2r.Min) r2 := br2.Add(bb2r.Min) draw.Draw(bb2, r2, image.White, image.ZP) draw.Draw(bb2, r.Add(delta), bb, bbr.Min) draw.Draw(bb2mask, r2, image.Transparent, image.ZP) draw.DrawMask(bb2mask, r, image.Opaque, bbr.Min, bbmask, image.ZP, draw.Over) draw.DrawMask(bb2mask, r.Add(delta), image.Opaque, bbr.Min, bbmask, image.ZP, draw.Over) }
// BorderOp draws a retangular border of size r and width n, with n positive // meaning the border is inside r, drawn with the specified draw op. func (dst *Image) BorderOp(r image.Rectangle, n int, color *Image, sp image.Point, op Op) { if n < 0 { r = r.Inset(n) sp = sp.Add(image.Pt(n, n)) n = -n } dst.Display.mu.Lock() defer dst.Display.mu.Unlock() draw(dst, image.Rect(r.Min.X, r.Min.Y, r.Max.X, r.Min.Y+n), color, sp, nil, sp, op) pt := image.Pt(sp.X, sp.Y+r.Dy()-n) draw(dst, image.Rect(r.Min.X, r.Max.Y-n, r.Max.X, r.Max.Y), color, pt, nil, pt, op) pt = image.Pt(sp.X, sp.Y+n) draw(dst, image.Rect(r.Min.X, r.Min.Y+n, r.Min.X+n, r.Max.Y-n), color, pt, nil, pt, op) pt = image.Pt(sp.X+r.Dx()-n, sp.Y+n) draw(dst, image.Rect(r.Max.X-n, r.Min.Y+n, r.Max.X, r.Max.Y-n), color, pt, nil, pt, op) }
func HOG(f *rimg64.Multi, conf Config) *rimg64.Multi { const eps = 0.0001 // Leave a one-pixel border to compute derivatives. inside := image.Rectangle{image.ZP, f.Size()}.Inset(1) // Leave a half-cell border. half := conf.CellSize / 2 valid := inside.Inset(half) // Number of whole cells inside valid region. cells := valid.Size().Div(conf.CellSize) if cells.X <= 0 || cells.Y <= 0 { return nil } // Remove one cell on all sides for output. out := cells.Sub(image.Pt(2, 2)) // Region to iterate over. size := cells.Mul(conf.CellSize).Add(image.Pt(2*half, 2*half)) vis := image.Rectangle{inside.Min, inside.Min.Add(size)} // Accumulate edges into cell histograms. hist := rimg64.NewMulti(cells.X, cells.Y, 2*conf.Angles) quantizer := makeQuantizer(conf.Angles) for a := vis.Min.X; a < vis.Max.X; a++ { for b := vis.Min.Y; b < vis.Max.Y; b++ { x, y := a-half-vis.Min.X, b-half-vis.Min.Y // Pick channel with strongest gradient. grad, v := maxGrad(f, a, b) v = math.Sqrt(v) // Snap to orientation. q := quantizer.quantize(grad) // Add to 4 histograms around pixel using bilinear interpolation. xp := (float64(x)+0.5)/float64(conf.CellSize) - 0.5 yp := (float64(y)+0.5)/float64(conf.CellSize) - 0.5 // Extract integer and fractional part. ixp, vx0 := modf(xp) iyp, vy0 := modf(yp) // Complement of fraction part. vx1 := 1 - vx0 vy1 := 1 - vy0 if ixp >= 0 && iyp >= 0 { addToMulti(hist, ixp, iyp, q, vx1*vy1*v) } if ixp+1 < cells.X && iyp >= 0 { addToMulti(hist, ixp+1, iyp, q, vx0*vy1*v) } if ixp >= 0 && iyp+1 < cells.Y { addToMulti(hist, ixp, iyp+1, q, vx1*vy0*v) } if ixp+1 < cells.X && iyp+1 < cells.Y { addToMulti(hist, ixp+1, iyp+1, q, vx0*vy0*v) } } } // compute energy in each block by summing over orientations norm := rimg64.New(cells.X, cells.Y) for x := 0; x < cells.X; x++ { for y := 0; y < cells.Y; y++ { for d := 0; d < conf.Angles; d++ { s := hist.At(x, y, d) + hist.At(x, y, d+conf.Angles) addTo(norm, x, y, s*s) } } } feat := rimg64.NewMulti(out.X, out.Y, conf.Channels()) for x := 0; x < out.X; x++ { for y := 0; y < out.Y; y++ { a, b := x+1, y+1 // Normalization factors. var n [4]float64 n[0] = 1 / math.Sqrt(adjSum(norm, a, b, a+1, b+1)+eps) n[1] = 1 / math.Sqrt(adjSum(norm, a, b, a+1, b-1)+eps) n[2] = 1 / math.Sqrt(adjSum(norm, a, b, a-1, b+1)+eps) n[3] = 1 / math.Sqrt(adjSum(norm, a, b, a-1, b-1)+eps) var off int // Contrast-sensitive features. if !conf.NoContrastVar { for d := 0; d < 2*conf.Angles; d++ { h := hist.At(a, b, d) var sum float64 for _, ni := range n { val := h * ni if !conf.NoClip { val = math.Min(val, 0.2) } sum += val } feat.Set(x, y, off+d, sum/2) } off += 2 * conf.Angles } // Contrast-insensitive features. if !conf.NoContrastInvar { for d := 0; d < conf.Angles; d++ { h := hist.At(a, b, d) + hist.At(a, b, conf.Angles+d) var sum float64 for _, ni := range n { val := h * ni if !conf.NoClip { val = math.Min(val, 0.2) } sum += val } feat.Set(x, y, off+d, sum/2) } off += conf.Angles } // Texture features. if !conf.NoTexture { for i, ni := range n { var sum float64 for d := 0; d < 2*conf.Angles; d++ { h := hist.At(a, b, d) val := h * ni if !conf.NoClip { val = math.Min(val, 0.2) } sum += val } feat.Set(x, y, off+i, sum/math.Sqrt(float64(2*conf.Angles))) } off += 4 } } } return feat }