diff options
Diffstat (limited to 'sauvola.go')
-rw-r--r-- | sauvola.go | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/sauvola.go b/sauvola.go new file mode 100644 index 0000000..3ba4359 --- /dev/null +++ b/sauvola.go @@ -0,0 +1,76 @@ +package preproc + +import ( + "image" + "image/color" + + "rescribe.xyz/preproc/integralimg" +) + +// Implements Sauvola's algorithm for text binarization, see paper +// "Adaptive document image binarization" (2000) +func Sauvola(img *image.Gray, ksize float64, windowsize int) *image.Gray { + b := img.Bounds() + new := image.NewGray(b) + + for y := b.Min.Y; y < b.Max.Y; y++ { + for x := b.Min.X; x < b.Max.X; x++ { + window := surrounding(img, x, y, windowsize) + m, dev := meanstddev(window) + threshold := m * (1 + ksize*((dev/128)-1)) + if img.GrayAt(x, y).Y < uint8(threshold) { + new.SetGray(x, y, color.Gray{0}) + } else { + new.SetGray(x, y, color.Gray{255}) + } + } + } + + return new +} + +// Implements Sauvola's algorithm using Integral Images, see paper +// "Efficient Implementation of Local Adaptive Thresholding Techniques Using Integral Images" +// and +// https://stackoverflow.com/questions/13110733/computing-image-integral +func IntegralSauvola(img *image.Gray, ksize float64, windowsize int) *image.Gray { + b := img.Bounds() + new := image.NewGray(b) + + integrals := integralimg.ToAllIntegralImg(img) + + for y := b.Min.Y; y < b.Max.Y; y++ { + for x := b.Min.X; x < b.Max.X; x++ { + m, dev := integrals.MeanStdDevWindow(x, y, windowsize) + threshold := m * (1 + ksize*((dev/128)-1)) + if img.GrayAt(x, y).Y < uint8(threshold) { + new.SetGray(x, y, color.Gray{0}) + } else { + new.SetGray(x, y, color.Gray{255}) + } + } + } + + return new +} + +// PreCalcedSauvola Implements Sauvola's algorithm using precalculated Integral Images +// TODO: have this be the root function that the other two reference +func PreCalcedSauvola(integrals integralimg.WithSq, img *image.Gray, ksize float64, windowsize int) *image.Gray { + b := img.Bounds() + new := image.NewGray(b) + + for y := b.Min.Y; y < b.Max.Y; y++ { + for x := b.Min.X; x < b.Max.X; x++ { + m, dev := integrals.MeanStdDevWindow(x, y, windowsize) + threshold := m * (1 + ksize*((dev/128)-1)) + if img.GrayAt(x, y).Y < uint8(threshold) { + new.SetGray(x, y, color.Gray{0}) + } else { + new.SetGray(x, y, color.Gray{255}) + } + } + } + + return new +} |