func getGray(src *image.Gray, x, y, borderMethod int) uint8 { bound := src.Bounds() if x < 0 { switch borderMethod { case BORDER_COPY: x = 0 default: return 0 } } else if x >= bound.Max.X { switch borderMethod { case BORDER_COPY: x = bound.Max.X - 1 default: return 0 } } if y < 0 { switch borderMethod { case BORDER_COPY: y = 0 default: return 0 } } else if y >= bound.Max.Y { switch borderMethod { case BORDER_COPY: y = bound.Max.Y - 1 default: return 0 } } i := (y-bound.Min.Y)*src.Stride + (x - bound.Min.X) return src.Pix[i] }
func nearestGray(in *image.Gray, out *image.Gray, scale float64, coeffs []bool, offset []int, filterLength int) { newBounds := out.Bounds() maxX := in.Bounds().Dx() - 1 for x := newBounds.Min.X; x < newBounds.Max.X; x++ { row := in.Pix[x*in.Stride:] for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ { var gray float32 var sum float32 start := offset[y] ci := y * filterLength for i := 0; i < filterLength; i++ { if coeffs[ci+i] { xi := start + i switch { case xi < 0: xi = 0 case xi >= maxX: xi = maxX } gray += float32(row[xi]) sum++ } } offset := (y-newBounds.Min.Y)*out.Stride + (x - newBounds.Min.X) out.Pix[offset] = floatToUint8(gray / sum) } } }
func resizeGray(in *image.Gray, out *image.Gray, scale float64, coeffs []int16, offset []int, filterLength int) { newBounds := out.Bounds() maxX := in.Bounds().Dx() - 1 for x := newBounds.Min.X; x < newBounds.Max.X; x++ { row := in.Pix[(x-newBounds.Min.X)*in.Stride:] for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ { var gray int32 var sum int32 start := offset[y] ci := y * filterLength for i := 0; i < filterLength; i++ { coeff := coeffs[ci+i] if coeff != 0 { xi := start + i switch { case xi < 0: xi = 0 case xi >= maxX: xi = maxX } gray += int32(coeff) * int32(row[xi]) sum += int32(coeff) } } offset := (y-newBounds.Min.Y)*out.Stride + (x - newBounds.Min.X) out.Pix[offset] = clampUint8(gray / sum) } } }
func New(im image.Gray) *Integral { rect := im.Bounds() width := rect.Dx() height := rect.Dy() data := make([]uint32, width*height) for x := rect.Min.X; x < rect.Max.X; x++ { for y := rect.Min.Y; y < rect.Max.Y; y++ { if x == 0 && y == 0 { data[0] = uint32(im.Pix[0]) } else if x == 0 && y != 0 { data[y*height+x] = data[(y-1)*height+x] + uint32(im.Pix[y*im.Stride+x]) } else if y == 0 && x != 0 { data[y*height+x] = data[y*height+x-1] + uint32(im.Pix[y*im.Stride+x]) } else { data[y*height+x] = data[(y-1)*height+x] + data[y*height+x-1] - data[(y-1)*height+x-1] + uint32(im.Pix[y*im.Stride+x]) } } } intImg := &Integral{ Data: data, Width: width, Height: height, } return intImg }
func Contrast(picture *image.Gray, contrast uint8) *image.Gray { bounds := picture.Bounds() newPic := image.NewGray(bounds) average := getAverage(picture) for x := 0; x < bounds.Dx(); x++ { for y := 0; y < bounds.Dy(); y++ { pixel := picture.At(x, y).(color.Gray).Y if pixel > average { if pixel+contrast < pixel { pixel = 0xff } else { pixel += contrast } } else if pixel < average { if pixel-contrast > pixel { pixel = 0x00 } else { pixel -= contrast } } newPic.Set(x, y, color.Gray{pixel}) } } return newPic }
func valueAt(img *image.Gray, x, y float32) float32 { dx, dy := x/float32(screenWidth), y/float32(screenHeight) b := img.Bounds().Max px, py := int(dx*float32(b.X)), int(dy*float32(b.Y)) v := float32(img.At(px, py).(color.Gray).Y) / 255 return v }
func GenerateFractal(im *image.Gray) { z := &cn{} c := &cn{} g := color.Gray{} for x := 0; x < 1000; x++ { for y := 0; y < 1000; y++ { c.r = (*width * float64(x) / float64(1000)) - *width/float64(2) c.i = (*height * float64(y) / float64(1000)) - *height/float64(2) c.r += *centerx c.i += *centery z.r = 0 z.i = 0 zrsqr := z.r * z.r zisqr := z.i * z.i var i uint8 = 0 for zrsqr+zisqr < 4.0 && i < 255 { i++ z.i = square(z.r+z.i) - zrsqr - zisqr z.i += c.i z.r = zrsqr - zisqr + c.r zrsqr = square(z.r) zisqr = square(z.i) } g.Y = i im.SetGray(x, y, g) } } }
func drawRect(img *image.Gray, c color.Gray, xPos, yPos, width, height float64) { for h := 0.0; h < height; h += 1.0 { for w := 0.0; w < width; w += 1.0 { img.SetGray(int(xPos+w), int(yPos+h), c) } } }
func Blobify(img *image.Gray) Blobs { var blobs Blobs visited := make([]bool, img.Bounds().Max.X*img.Bounds().Max.Y) // Scan for first/next blob. x, y := 0, 0 for { x, y = nextPixel(x, y, img, visited) if x < 0 || y < 0 { for _, b := range blobs.blobs { // Only compute bridges for wide blobs if float64(b.Bounds.Dx()) >= blobs.avgWidth()*1.75 { b.computeBridges(blobs.avgWidth()) } } log.Printf("Returning Blobs with count: %d\n", len(blobs.blobs)) return blobs } // Extract blob. b := blobAt(x, y, img, visited) x = b.Bounds.Max.X + 1 blobs.addBlob(b) } }
// checkCircle checks that a circle with a center in (x, y) and a radius r fits to the base image and all pixels are high. func checkCircle(base *image.Gray, level byte, pxSize, x, y, r float64) bool { width := float64(base.Bounds().Dx()) * pxSize height := float64(base.Bounds().Dy()) * pxSize if x < r || x > width-r || y < r || y > height-r { return false } x0 := int((x - r) / pxSize) y0 := int((y - r) / pxSize) x1 := int((x + r) / pxSize) y1 := int((y + r) / pxSize) for cy := y0; cy <= y1; cy++ { i0 := cy * base.Stride for cx := x0; cx <= x1; cx++ { if !inside(x, y, r, (x-r)+float64(cx-x0)*pxSize, (y-r)+float64(cy-y0)*pxSize) { continue } if base.Pix[i0+cx] != level { // circle hits background //fmt.Printf("checkCircle(pxSize=%f, x=%f, y=%f, r=%f, i0=%d, cx=%d, base.Pix[i0+cx]=%d\n", // pxSize, x, y, r, i0, cx, base.Pix[i0+cx]) return false } } } return true }
func fillTriangle(base *image.Gray, level byte, bbox image.Rectangle, ox, oy float64) []Point { basePxSize := *pxSize / float64(*n) width := float64(base.Bounds().Dx()) * basePxSize height := float64(base.Bounds().Dy()) * basePxSize dy := (*toolDiameter) / 2 dx := dy * 1.73205080757 // sqrt(3) var centers []Point for i := 0; ; i++ { cx := ox + float64(i)*dx if cx >= width { break } if cx < float64(bbox.Min.X-1)*basePxSize || cx >= float64(bbox.Max.X+1)*basePxSize { continue } for j := 0; ; j++ { cy := oy + float64(j)*dy if cy >= height { break } if cy < float64(bbox.Min.Y-1)*basePxSize || cy >= float64(bbox.Max.Y+1)*basePxSize { continue } if (i+j)%2 == 1 { continue } if checkCircle(base, level, basePxSize, cx, cy, (*toolDiameter)/2) { centers = append(centers, Point{cx, cy}) } } } return centers }
func fillQuad(base *image.Gray, level byte, bbox image.Rectangle, ox, oy float64) []Point { basePxSize := *pxSize / float64(*n) width := float64(base.Bounds().Dx()) * basePxSize height := float64(base.Bounds().Dy()) * basePxSize dx := *toolDiameter dy := *toolDiameter var centers []Point for i := 0; ; i++ { cx := ox + float64(i)*dx if cx >= width { break } if cx < float64(bbox.Min.X-1)*basePxSize || cx >= float64(bbox.Max.X+1)*basePxSize { //fmt.Printf("bbox={%f,%f}-{%f,%f}, cx: %f, skip...\n", // float64(bbox.Min.X)*basePxSize, float64(bbox.Min.Y)*basePxSize, float64(bbox.Max.X)*basePxSize, float64(bbox.Max.Y)*basePxSize, cx) continue } for j := 0; ; j++ { cy := oy + float64(j)*dy if cy >= height { break } if cy < float64(bbox.Min.Y-1)*basePxSize || cy >= float64(bbox.Max.Y+1)*basePxSize { //fmt.Printf("bbox={%f,%f}-{%f,%f}, cy: %f, skip...\n", // float64(bbox.Min.X)*basePxSize, float64(bbox.Min.Y)*basePxSize, float64(bbox.Max.X)*basePxSize, float64(bbox.Max.Y)*basePxSize, cy) continue } if checkCircle(base, level, basePxSize, cx, cy, (*toolDiameter)/2) { centers = append(centers, Point{cx, cy}) } } } return centers }
//BackProjectGray computes back projection of img // in Gray16 by performing an addition // of backprojection by line. // 16Gray avoids white noise. func BackProjectGray(img image.Gray) (*image.Gray16, error) { size := img.Bounds().Size() width := size.Y nbProj := size.X step := 180.0 / float64(nbProj) out := image.NewGray16(image.Rect(0, 0, width, width)) for X := 0; X < nbProj; X++ { //Extract a 1D-projection (one row Y of sinogram) line := img.SubImage(image.Rect(X, 0, X+1, width)).(*image.Gray) // 3- Do the backprojection and rotate accordingly wideLine := resize.Resize(uint(width), uint(width), line, resize.Lanczos3).(*image.Gray) θ := manipulator.Rad(float64(X)*step) + math.Pi/2 rotatedWideLine := image.NewGray(image.Rect(0, 0, width, width)) err := graphics.Rotate(rotatedWideLine, wideLine, &graphics.RotateOptions{Angle: θ}) if err != nil { return out, err } // 4- Add the rotated backprojection in the output image for x := 0; x < width; x++ { for y := 0; y < width; y++ { point := uint16(out.At(x, y).(color.Gray16).Y) + uint16(rotatedWideLine.At(x, y).(color.Gray).Y) out.Set(x, y, color.Gray16{uint16(point)}) } } } return out, nil }
// GreyscaleDct Computes the Dct of a greyscale image func GreyscaleDct(img image.Gray) uint64 { // func DctImageHashOne(img image.Image) ([][]float64) { R := img.Bounds() N := R.Dx() // width M := R.Dy() // height DCTMatrix := make([][]float64, N) for u := 0; u < N; u++ { DCTMatrix[u] = make([]float64, M) for v := 0; v < M; v++ { DCTMatrix[u][v] = dctPoint(img, u, v, N, M) // fmt.Println( "DCTMatrix[", u, "][", v, "] is ", DCTMatrix[u][v]) } } total := 0.0 for u := 0; u < N/2; u++ { for v := 0; v < M/2; v++ { total += DCTMatrix[u][v] } } total -= DCTMatrix[0][0] avg := total / float64(((N/2)*(M/2))-1) fmt.Println("got average ", avg) var hash uint64 for u := 0; u < N/2; u++ { for v := 0; v < M/2; v++ { hash = hash * 2 if DCTMatrix[u][v] > avg { hash++ } } } return hash }
func ImageEnhanceGrey(img *image.Gray, enhanceDegress float32, enhanceOffset float32) *image.RGBA { rgbFunc := func(xpos, ypos int) (r0, g0, b0, a0 uint8) { gray := img.GrayAt(xpos, ypos) return gray.Y, gray.Y, gray.Y, gray.Y } imgEnhanced := imenhance(enhanceDegress, enhanceOffset, [3]bool{true, true, true}, false, img.Rect, rgbFunc) return imgEnhanced }
func emptyCol(m *image.Gray, r image.Rectangle, x int) bool { for y := r.Min.Y; y < r.Max.Y; y++ { if m.GrayAt(x, y).Y > 0 { return false } } return true }
func newAtFuncGray(p *image.Gray) AtFunc { return func(x, y int) (r, g, b, a uint32) { i := p.PixOffset(x, y) yy := uint32(p.Pix[i]) yy |= yy << 8 return yy, yy, yy, 0xffff } }
func emptyRow(m *image.Gray, r image.Rectangle, y int) bool { for x := r.Min.X; x < r.Max.X; x++ { if m.GrayAt(x, y).Y > 0 { return false } } return true }
func meanHeight(g *image.Gray) uint8 { b := g.Bounds() var total uint64 for i := b.Min.X; i < b.Max.X; i++ { for j := b.Min.Y; j < b.Max.Y; j++ { total += uint64(g.GrayAt(i, j).Y) } } return uint8(total / uint64((b.Dx() * b.Dy()))) }
func getAverage(picture *image.Gray) uint8 { var sum uint64 = 0 bounds := picture.Bounds() for x := 0; x < bounds.Dx(); x++ { for y := 0; y < bounds.Dy(); y++ { sum += uint64(picture.At(x, y).(color.Gray).Y) } } return uint8(sum / uint64(bounds.Dx()*bounds.Dy())) }
// Interpolate uint8/pixel images. func interpolate1x8(src *image.Gray, dstW, dstH int) image.Image { srcRect := src.Bounds() srcW := srcRect.Dx() srcH := srcRect.Dy() ww, hh := uint64(dstW), uint64(dstH) dx, dy := uint64(srcW), uint64(srcH) n, sum := dx*dy, make([]uint64, dstW*dstH) for y := 0; y < srcH; y++ { pixOffset := src.PixOffset(0, y) for x := 0; x < srcW; x++ { // Get the source pixel. val64 := uint64(src.Pix[pixOffset]) pixOffset++ // Spread the source pixel over 1 or more destination rows. py := uint64(y) * hh for remy := hh; remy > 0; { qy := dy - (py % dy) if qy > remy { qy = remy } // Spread the source pixel over 1 or more destination columns. px := uint64(x) * ww index := (py/dy)*ww + (px / dx) for remx := ww; remx > 0; { qx := dx - (px % dx) if qx > remx { qx = remx } qxy := qx * qy sum[index] += val64 * qxy index++ px += qx remx -= qx } py += qy remy -= qy } } } dst := image.NewGray(image.Rect(0, 0, dstW, dstH)) index := 0 for y := 0; y < dstH; y++ { pixOffset := dst.PixOffset(0, y) for x := 0; x < dstW; x++ { dst.Pix[pixOffset] = uint8(sum[index] / n) pixOffset++ index++ } } return dst }
func GrayImageToMatrix(src image.Gray) (*matrix.Dense, error) { bounds := src.Bounds() mtx := make([][]float64, bounds.Max.X) for x := 0; x < bounds.Max.X; x++ { mtx[x] = make([]float64, bounds.Max.Y) for y := 0; y < bounds.Max.Y; y++ { _, _, b, _ := src.At(x, y).RGBA() mtx[x][y] = float64(b) } } return matrix.NewDense(mtx) }
func toGray(o *ora.ORA, name string) (*image.Gray, error) { var p *image.Gray if l := o.Layer(name); l != nil { p = image.NewGray(o.Bounds()) i, err := l.Image() if err != nil { return nil, err } draw.Draw(p, image.Rect(0, 0, p.Bounds().Max.X, p.Bounds().Max.Y), i, image.Point{}, draw.Src) } return p, nil }
func tightBounds(m *image.Gray) (r image.Rectangle) { r = m.Bounds() for ; r.Min.Y < r.Max.Y && emptyRow(m, r, r.Min.Y+0); r.Min.Y++ { } for ; r.Min.Y < r.Max.Y && emptyRow(m, r, r.Max.Y-1); r.Max.Y-- { } for ; r.Min.X < r.Max.X && emptyCol(m, r, r.Min.X+0); r.Min.X++ { } for ; r.Min.X < r.Max.X && emptyCol(m, r, r.Max.X-1); r.Max.X-- { } return r }
// grayToY stores the 8x8 region of m whose top-left corner is p in yBlock. func grayToY(m *image.Gray, p image.Point, yBlock *block) { b := m.Bounds() xmax := b.Max.X - 1 ymax := b.Max.Y - 1 pix := m.Pix for j := 0; j < 8; j++ { for i := 0; i < 8; i++ { idx := m.PixOffset(min(p.X+i, xmax), min(p.Y+j, ymax)) yBlock[8*j+i] = int32(pix[idx]) } } }
func scaleGray(src *image.Gray, scale uint8) *image.Gray { bounds := src.Bounds() dst := image.NewGray(bounds) copy(dst.Pix, src.Pix) for y := bounds.Min.Y; y < bounds.Max.Y; y++ { for x := bounds.Min.X; x < bounds.Max.X; x++ { dst.SetGray(x, y, color.Gray{grayAt(src, x, y).Y * scale}) } } return dst }
func drawRect(img *image.Gray, r image.Rectangle, c color.Gray) { // Draw top and bottom lines for x := r.Min.X - 1; x <= r.Max.X; x++ { img.SetGray(x, r.Min.Y-1, c) img.SetGray(x, r.Max.Y+1, c) } // Draw side lines for y := r.Min.Y - 1; y <= r.Max.Y; y++ { img.SetGray(r.Min.X-1, y, c) img.SetGray(r.Max.X+1, y, c) } }
func GrayImageToMatrix(src image.Gray) (*mat64.Dense, error) { bounds := src.Bounds() rows := bounds.Max.Y cols := bounds.Max.X mtx := make([]float64, rows*cols) for x := 0; x < cols; x++ { for y := 0; y < rows; y++ { _, _, b, _ := src.At(x, y).RGBA() mtx[y*cols+x] = float64(b) } } return mat64.NewDense(rows, cols, mtx), nil }
func (entity *Entity) deviation(model *image.Gray) float64 { deviation := 0.0 actual := entity.render() for x := 0; x < entity.width; x++ { for y := 0; y < entity.height; y++ { actualColor := float64(actual.At(x, y).(color.Gray).Y) modelColor := float64(model.At(x, y).(color.Gray).Y) dev := actualColor - modelColor deviation += dev * dev } } return deviation }
func dctPoint(img image.Gray, u, v, N, M int) float64 { sum := 0.0 for i := 0; i < N; i++ { for j := 0; j < M; j++ { _, _, b, _ := img.At(i, j).RGBA() // sum += math.Cos( ( float64(2*i+1)/float64(2*N) ) * float64( u ) * math.Pi ) * // math.Cos( ( float64(2*j+1)/float64(2*M) ) * float64( v ) * math.Pi ) * // float64(b) sum += math.Cos(math.Pi/(float64(N))*(float64(i)+1/2)*float64(u)) * math.Cos(math.Pi/(float64(M))*(float64(j)+1/2)*float64(v)) * float64(b) } } return sum * ((coefficient(u) * coefficient(v)) / 4.0) }