diff --git a/Makefile b/Makefile index ea0eb27..0889637 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,9 @@ build_linux: package: build_linux docker build -t dhogborg/gosser:latest . + +push: + docker push dhogborg/gosser:latest lint: golint . diff --git a/internal/ssocr/ssocr.go b/internal/ssocr/ssocr.go index 0fda7c7..18ab682 100644 --- a/internal/ssocr/ssocr.go +++ b/internal/ssocr/ssocr.go @@ -66,11 +66,11 @@ func (s *SSOCR) Scan(imagefile string) string { segm := s.extractPosition(img, a) var position *SsDigit - if len(predefs) == 0 { - position = NewSsDigit(segm) - } else { + if len(predefs) > a { position = predefs[a] position.Image = segm + } else { + position = NewSsDigit(segm) } position.Position = a @@ -112,19 +112,43 @@ func (s *SSOCR) extractPosition(img image.Image, position int) image.Image { bounds := img.Bounds() rgba := image.NewRGBA(bounds) - // copy the generic image data to a greyscale image model - if g, ok := copyImage(img, rgba).(*image.RGBA); ok { - rgba = g - } + copyImage(img, rgba) segmentWidth := int(float64(bounds.Dx()) / float64(s.Positions)) segmentInset := int(float64(segmentWidth) * float64(position)) // extract a subimage with the positions inset - subrect := image.Rect(bounds.Min.X+segmentInset, bounds.Min.Y, bounds.Min.X+segmentInset+segmentWidth, bounds.Max.Y) + subrect := image.Rect( + bounds.Min.X+segmentInset, + bounds.Min.Y, + bounds.Min.X+segmentInset+segmentWidth, + bounds.Max.Y, + ) + return rgba.SubImage(subrect) } +// Direction identifiers +const ( + North = iota + South = iota + West = iota + East = iota +) + +// Segment identifiers +const ( + NorthPole = 1 << iota // 1 + NorthWest = 1 << iota // 2 + NorthEast = 1 << iota // 4 + Equator = 1 << iota // 8 + SouthWest = 1 << iota // 16 + SouthEast = 1 << iota // 32 + SouthPole = 1 << iota // 64 +) + +// SsDigit has a position (n:th digit in image), a north and a south origin, +// and segments added together for charater matching. type SsDigit struct { Position int Image image.Image @@ -132,25 +156,9 @@ type SsDigit struct { NorthPoint []int `json:"north"` SouthPoint []int `json:"south"` - // segments - NorthPole bool - NorthWest bool - NorthEast bool - - Equator bool - - SouthWest bool - SouthEast bool - SouthPole bool + Segments int } -const ( - NORTH = iota - SOUTH = iota - WEST = iota - EAST = iota -) - func NewSsDigit(img image.Image) *SsDigit { return &SsDigit{ Image: img, @@ -183,12 +191,20 @@ func (s *SsDigit) Scan() { "base_value": nBaseValue, }).Debug("North origin") - s.NorthPole = s.isActiveSegment(nBaseValue, s.minValue(northOrigin, quarterHeight, NORTH)) - s.NorthWest = s.isActiveSegment(nBaseValue, s.minValue(northOrigin, quarterWidth, WEST)) - s.NorthEast = s.isActiveSegment(nBaseValue, s.minValue(northOrigin, quarterWidth, EAST)) + if s.isActiveSegment(nBaseValue, s.minValue(northOrigin, quarterHeight, North)) { + s.Segments += NorthPole + } + if s.isActiveSegment(nBaseValue, s.minValue(northOrigin, quarterWidth, West)) { + s.Segments += NorthWest + } + if s.isActiveSegment(nBaseValue, s.minValue(northOrigin, quarterWidth, East)) { + s.Segments += NorthEast + } // center, use north origin - s.Equator = s.isActiveSegment(nBaseValue, s.minValue(northOrigin, quarterHeight, SOUTH)) + if s.isActiveSegment(nBaseValue, s.minValue(northOrigin, quarterHeight, South)) { + s.Segments += Equator + } // South origin points // the south is slanted to the left @@ -208,9 +224,15 @@ func (s *SsDigit) Scan() { "base_value": sBaseValue, }).Debug("South origin") - s.SouthWest = s.isActiveSegment(sBaseValue, s.minValue(southOrigin, quarterWidth, WEST)) - s.SouthEast = s.isActiveSegment(sBaseValue, s.minValue(southOrigin, quarterWidth, EAST)) - s.SouthPole = s.isActiveSegment(sBaseValue, s.minValue(southOrigin, quarterHeight, SOUTH)) + if s.isActiveSegment(sBaseValue, s.minValue(southOrigin, quarterWidth, West)) { + s.Segments += SouthWest + } + if s.isActiveSegment(sBaseValue, s.minValue(southOrigin, quarterWidth, East)) { + s.Segments += SouthEast + } + if s.isActiveSegment(sBaseValue, s.minValue(southOrigin, quarterHeight, South)) { + s.Segments += SouthPole + } // debug output the segments if DEBUG { @@ -232,24 +254,23 @@ func (s *SsDigit) isActiveSegment(baseValue, crossValue uint32) bool { func (s *SsDigit) String() string { - characters := map[string]*SsDigit{ - "0": &SsDigit{NorthPole: true, NorthWest: true, NorthEast: true, SouthWest: true, SouthEast: true, SouthPole: true}, - "1": &SsDigit{NorthEast: true, SouthEast: true}, - "2": &SsDigit{NorthPole: true, NorthEast: true, Equator: true, SouthWest: true, SouthPole: true}, - "3": &SsDigit{NorthPole: true, NorthEast: true, Equator: true, SouthEast: true, SouthPole: true}, - "4": &SsDigit{NorthWest: true, NorthEast: true, Equator: true, SouthEast: true}, - "5": &SsDigit{NorthPole: true, NorthWest: true, Equator: true, SouthEast: true, SouthPole: true}, - "6": &SsDigit{NorthPole: true, NorthWest: true, Equator: true, SouthWest: true, SouthEast: true, SouthPole: true}, - "7": &SsDigit{NorthPole: true, NorthEast: true, SouthEast: true}, - "8": &SsDigit{NorthPole: true, NorthWest: true, NorthEast: true, Equator: true, SouthWest: true, SouthEast: true, SouthPole: true}, - "9": &SsDigit{NorthPole: true, NorthWest: true, NorthEast: true, Equator: true, SouthEast: true}, - } - - for c, d := range characters { - if s.Equals(d) { - return c - } + characters := map[int]string{ + NorthPole + NorthEast + NorthWest + SouthEast + SouthWest + SouthPole: "0", + NorthEast + SouthEast: "1", + NorthPole + NorthEast + Equator + SouthWest + SouthPole: "2", + NorthPole + NorthEast + Equator + SouthEast + SouthPole: "3", + NorthEast + NorthWest + Equator + SouthEast: "4", + NorthPole + NorthWest + Equator + SouthEast + SouthPole: "5", + NorthPole + NorthWest + Equator + SouthEast + SouthWest + SouthPole: "6", + NorthPole + NorthEast + SouthEast: "7", + NorthPole + NorthEast + NorthWest + Equator + SouthEast + SouthWest + SouthPole: "8", + NorthPole + NorthEast + NorthWest + Equator + SouthWest + SouthPole: "9", + } + + if c, ok := characters[s.Segments]; ok { + return c } + return "-" } @@ -261,7 +282,7 @@ func (s *SsDigit) AppendTo(lines []string) []string { pl := s.Dotstrings() for i := range lines { - lines[i] += pl[i] + " " + lines[i] += pl[i] + " " } return lines } @@ -281,76 +302,60 @@ func (s *SsDigit) Dotstrings() []string { []string{" ", " ", " "}, []string{" ", " ", " "}, } - - if s.NorthPole { + if (s.Segments & NorthPole) == NorthPole { dots[0] = []string{"*", "*", "*"} } - if s.NorthWest { + if (s.Segments & NorthWest) == NorthWest { dots[0][0] = "*" dots[1][0] = "*" dots[2][0] = "*" } - if s.NorthEast { + if (s.Segments & NorthEast) == NorthEast { dots[0][2] = "*" dots[1][2] = "*" dots[2][2] = "*" } - if s.Equator { + if (s.Segments & Equator) == Equator { dots[2] = []string{"*", "*", "*"} } - if s.SouthWest { + if (s.Segments & SouthWest) == SouthWest { dots[2][0] = "*" dots[3][0] = "*" dots[4][0] = "*" } - if s.SouthEast { + if (s.Segments & SouthEast) == SouthEast { dots[2][2] = "*" dots[3][2] = "*" dots[4][2] = "*" } - if s.SouthPole { + if (s.Segments & SouthPole) == SouthPole { dots[4] = []string{"*", "*", "*"} } lines := []string{} for _, l := range dots { - lines = append(lines, strings.Join(l, "")) + lines = append(lines, strings.Join(l, " ")) } return lines } -// Equals returns true if the receiver and compration -// object have the same segment configuration -func (s *SsDigit) Equals(comp *SsDigit) bool { - return (s.NorthPole == comp.NorthPole) && - (s.NorthWest == comp.NorthWest) && - (s.NorthEast == comp.NorthEast) && - (s.Equator == comp.Equator) && - (s.SouthWest == comp.SouthWest) && - (s.SouthEast == comp.SouthEast) && - (s.SouthPole == comp.SouthPole) -} - func (s *SsDigit) minValue(origin image.Point, length, direction int) uint32 { - // Direction legend: - // North: origin.Y-- - // West: origin.X-- - // East: origin.X++ - // South: origin.Y++ directionMap := map[int]image.Point{ - NORTH: image.Point{X: 0, Y: -1}, - WEST: image.Point{X: -1, Y: 0}, - EAST: image.Point{X: 1, Y: 0}, - SOUTH: image.Point{X: 0, Y: 1}, + North: image.Point{X: 0, Y: -1}, + West: image.Point{X: -1, Y: 0}, + East: image.Point{X: 1, Y: 0}, + South: image.Point{X: 0, Y: 1}, } - bounds := s.Image.Bounds() point := origin pointMod := directionMap[direction] + img := s.Image + bounds := img.Bounds() minValue, _, _, _ := s.Image.At(point.X, point.Y).RGBA() + for a := 0; a < length; a++ { point = point.Add(pointMod) @@ -362,20 +367,23 @@ func (s *SsDigit) minValue(origin image.Point, length, direction int) uint32 { break } - pValue, _, _, _ := s.Image.At(point.X, point.Y).RGBA() - // minValue = (minValue + pValue) / 2 - if minValue > pValue { - minValue = pValue + red, _, _, _ := img.At(point.X, point.Y).RGBA() + if minValue > red { + minValue = red } if DEBUG { if img, ok := s.Image.(*image.RGBA); ok { - img.Set(point.X, point.Y, color.RGBA{uint8(pValue), 255, 0, 255}) + img.Set(point.X, point.Y, color.RGBA{uint8(red), 255, 0, 255}) } } - } + log.WithFields(log.Fields{ + "value": minValue, + "dir": direction, + }).Info("minvalue") + return minValue } @@ -388,7 +396,7 @@ type imageTarget interface { // copyImage copies the contents of source to target // converting the color to the target color model. -func copyImage(source image.Image, target imageTarget) imageTarget { +func copyImage(source image.Image, target imageTarget) { b := source.Bounds() for y := b.Min.Y; y < b.Max.Y; y++ { for x := b.Min.X; x < b.Max.X; x++ { @@ -397,6 +405,4 @@ func copyImage(source image.Image, target imageTarget) imageTarget { target.Set(x, y, color) } } - - return target }