Skip to content

Commit

Permalink
feat: apply OTSU's method for default threshold
Browse files Browse the repository at this point in the history
  • Loading branch information
taga3s committed Aug 18, 2024
1 parent 864e758 commit 5ed4478
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 27 deletions.
60 changes: 55 additions & 5 deletions internal/ascii_art/ascii_art.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package asciiart
import (
"image"
"image/color"
"math"
"math/rand"
"strings"
)
Expand All @@ -11,11 +12,6 @@ const (
validChars = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
)

func selectRandomly(chars string) string {
r := rand.Intn(len(chars))
return string(chars[r])
}

// `Generate` generates an ASCII art from an image.
func Generate(dest image.Image, threshold int) string {
srcBounds := dest.Bounds()
Expand Down Expand Up @@ -44,3 +40,57 @@ func Generate(dest image.Image, threshold int) string {

return asciiArt.String()
}

func selectRandomly(chars string) string {
r := rand.Intn(len(chars))
return string(chars[r])
}

// `CalcOTSUThreshold` calculates the threshold value using the OTSU's method.
func CalcOTSUThreshold(dest image.Image, ySize, xSize int) int {
histogram := make([]int, 256) // 0 - 255 histogram

for y := 0; y < ySize; y++ {
for x := 0; x < xSize; x++ {
c := color.GrayModel.Convert(dest.At(x, y))
gray, _ := c.(color.Gray)
histogram[gray.Y]++
}
}

t := 0
max := 0.0

for i := 0; i < 256; i++ {
w1, w2 := 0, 0 // pixel number
sum1, sum2 := 0, 0 // total gray value
m1, m2 := 0.0, 0.0 // average gray value

for j := 0; j < i; j++ {
w1 += histogram[j]
sum1 += histogram[j] * j
}

for j := i; j < 256; j++ {
w2 += histogram[j]
sum2 += j * histogram[j]
}

if 0 < w1 {
m1 = float64(sum1) / float64(w1)
}

if 0 < w2 {
m2 = float64(sum2) / float64(w2)
}

tmp := float64(w1) * float64(w2) * math.Pow(m1-m2, 2)

if max < tmp {
max = tmp
t = i
}
}

return t
}
58 changes: 36 additions & 22 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
)

const (
DefaultThreshold = 128
DefaultMagnification = 1.0
)

Expand All @@ -22,33 +21,24 @@ type Inputs struct {
}

func main() {
inputs := Inputs{}

app := &cli.App{
Flags: []cli.Flag{
&cli.IntFlag{
Name: "threshold",
Aliases: []string{"t"},
Usage: "the threshold for ASCII Art Generation",
Value: DefaultThreshold,
Destination: &inputs.threshold,
Name: "threshold",
Aliases: []string{"t"},
Usage: "the threshold for ASCII Art Generation",
},
&cli.Float64Flag{
Name: "magnification",
Aliases: []string{"m"},
Usage: "the magnification factor for ASCII Art Generation",
Value: DefaultMagnification,
Destination: &inputs.magnification,
Name: "magnification",
Aliases: []string{"m"},
Usage: "the magnification factor for ASCII Art Generation",
},
},
Action: func(c *cli.Context) error {
if c.NArg() != 1 {
return fmt.Errorf("invalid number of arguments")
err := runApp(c)
if err != nil {
return err
}
inputs.path = c.Args().Get(0)

run(&inputs)

return nil
},
}
Expand All @@ -58,20 +48,44 @@ func main() {
}
}

func run(inputs *Inputs) {
func runApp(c *cli.Context) error {
inputs := Inputs{}
if c.NArg() != 1 {
return fmt.Errorf("invalid number of arguments")
}
inputs.path = c.Args().Get(0)

// Load the image
srcImg, err := img.Load(inputs.path)
if err != nil {
log.Fatalf("Error: %v", err)
return err
}

if c.IsSet("magnification") {
inputs.magnification = c.Float64("magnification")
} else {
inputs.magnification = DefaultMagnification
}

// Resize the image
resizedImg := img.Resize(srcImg, inputs.magnification)

if c.IsSet("threshold") {
inputs.threshold = c.Int("threshold")
} else {
inputs.threshold = asciiArt.CalcOTSUThreshold(resizedImg, resizedImg.Bounds().Dy(), resizedImg.Bounds().Dx())
}

// Generate the ASCII Art
output := asciiArt.Generate(resizedImg, inputs.threshold)

// Print the ASCII Art
fmt.Print(output)

err = img.UnSync(resizedImg)
if err != nil {
log.Fatalf("Error: %v", err)
return err
}

return nil
}

0 comments on commit 5ed4478

Please sign in to comment.