From 4eb86764539a99b0d7c843d4aa81bfb2955db13c Mon Sep 17 00:00:00 2001 From: Nick White Date: Thu, 18 Apr 2019 13:24:02 +0100 Subject: Add basic cleanup tool; working, but more refinements planned. This uses integral image calculations, so they have been exported in the binarization package --- binarize/integralimg.go | 2 +- binarize/sauvola.go | 2 +- cleanup/main.go | 129 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 cleanup/main.go diff --git a/binarize/integralimg.go b/binarize/integralimg.go index 75e9cce..382b495 100644 --- a/binarize/integralimg.go +++ b/binarize/integralimg.go @@ -14,7 +14,7 @@ type integralwindow struct { height int } -func integralimg(img *image.Gray) [][]uint64 { +func Integralimg(img *image.Gray) [][]uint64 { b := img.Bounds() var oldy, oldx, oldxy uint64 var integral [][]uint64 diff --git a/binarize/sauvola.go b/binarize/sauvola.go index ee773ba..6d9c1af 100644 --- a/binarize/sauvola.go +++ b/binarize/sauvola.go @@ -35,7 +35,7 @@ func IntegralSauvola(img *image.Gray, ksize float64, windowsize int) *image.Gray b := img.Bounds() new := image.NewGray(b) - integral := integralimg(img) + integral := Integralimg(img) integralsq := integralimgsq(img) for y := b.Min.Y; y < b.Max.Y; y++ { diff --git a/cleanup/main.go b/cleanup/main.go new file mode 100644 index 0000000..05ff5f2 --- /dev/null +++ b/cleanup/main.go @@ -0,0 +1,129 @@ +package main + +import ( + "flag" + "fmt" + "image" + "image/color" + "image/draw" + _ "image/jpeg" + "image/png" + "log" + "os" + + "rescribe.xyz/go.git/binarize" +) + +type windowslice struct { + topleft uint64 + topright uint64 + bottomleft uint64 + bottomright uint64 +} + +func getwindowslice(i [][]uint64, x int, size int) windowslice { + maxy := len(i)-1 + maxx := x+size + if maxx > len(i[0])-1 { + maxx = len(i[0])-1 + } + + return windowslice { i[0][x], i[0][maxx], i[maxy][x], i[maxy][maxx] } +} + +// checkwindow checks the window from x to see whether more than +// thresh proportion of the pixels are white, if so it returns true. +func checkwindow(integral [][]uint64, x int, size int, thresh float64) bool { + height := len(integral) + window := getwindowslice(integral, x, size) + // divide by 255 as each on pixel has the value of 255 + sum := (window.bottomright + window.topleft - window.topright - window.bottomleft) / 255 + area := size * height + proportion := float64(float64(area) / float64(sum)) - 1 + return proportion <= thresh +} + +// cleanimg fills the sections of image not within the boundaries +// of lowedge and highedge with white +func cleanimg(img *image.Gray, lowedge int, highedge int) *image.Gray { + b := img.Bounds() + new := image.NewGray(b) + + // set left edge white + for x := b.Min.X; x < lowedge; x++ { + for y := b.Min.Y; y < b.Max.Y; y++ { + new.SetGray(x, y, color.Gray{255}) + } + } + // copy middle + for x := lowedge; x < highedge; x++ { + for y := b.Min.Y; y < b.Max.Y; y++ { + new.SetGray(x, y, img.GrayAt(x, y)) + } + } + // set right edge white + for x := highedge; x < b.Max.X; x++ { + for y := b.Min.Y; y < b.Max.Y; y++ { + new.SetGray(x, y, color.Gray{255}) + } + } + + return new +} + +func main() { + flag.Usage = func() { + fmt.Fprintf(os.Stderr, "Usage: cleanup [-t thresh] [-w winsize] inimg outimg\n") + flag.PrintDefaults() + } + wsize := flag.Int("w", 5, "Window size for mask finding algorithm.") + thresh := flag.Float64("t", 0.05, "Threshold for the proportion of black pixels below which a window is determined to be the edge.") + flag.Parse() + if flag.NArg() < 2 { + flag.Usage() + os.Exit(1) + } + + f, err := os.Open(flag.Arg(0)) + defer f.Close() + if err != nil { + log.Fatalf("Could not open file %s: %v\n", flag.Arg(0), err) + } + img, _, err := image.Decode(f) + if err != nil { + log.Fatalf("Could not decode image: %v\n", err) + } + b := img.Bounds() + gray := image.NewGray(image.Rect(0, 0, b.Dx(), b.Dy())) + draw.Draw(gray, b, img, b.Min, draw.Src) + + integral := binarize.Integralimg(gray) + maxx := len(integral[0])-1 + var lowedge, highedge int = 0, maxx + // find right edge + for x := maxx / 2; x < maxx - *wsize; x++ { + if checkwindow(integral, x, *wsize, *thresh) { + highedge = x + break + } + } + // find left edge + for x := maxx / 2; x > 0; x-- { + if checkwindow(integral, x, *wsize, *thresh) { + lowedge = x + break + } + } + + clean := cleanimg(gray, lowedge, highedge) + + f, err = os.Create(flag.Arg(1)) + if err != nil { + log.Fatalf("Could not create file %s: %v\n", flag.Arg(1), err) + } + defer f.Close() + err = png.Encode(f, clean) + if err != nil { + log.Fatalf("Could not encode image: %v\n", err) + } +} -- cgit v1.2.1-24-ge1ad