Almost finished with blob removal

This commit is contained in:
Eduard Urbach 2018-04-11 22:25:10 +02:00
parent 47af959f24
commit 176caa4a15

View File

@ -18,13 +18,12 @@ func main() {
panic(err) panic(err)
} }
img, format, err := image.Decode(bytes.NewReader(data)) img, _, err := image.Decode(bytes.NewReader(data))
if err != nil { if err != nil {
panic(err) panic(err)
} }
fmt.Println(img.Bounds().Dx(), img.Bounds().Dy(), format)
improved := ImproveQuality(img) improved := ImproveQuality(img)
f, err := os.Create("output.png") f, err := os.Create("output.png")
@ -46,7 +45,6 @@ type Pixel struct {
// Area ... // Area ...
type Area struct { type Area struct {
color.Color
Pixels []Pixel Pixels []Pixel
totalR uint64 totalR uint64
totalG uint64 totalG uint64
@ -69,6 +67,10 @@ func (area *Area) Add(x, y int, r, g, b, a uint32) {
// AverageColor ... // AverageColor ...
func (area *Area) AverageColor() color.Color { func (area *Area) AverageColor() color.Color {
if len(area.Pixels) == 0 {
return color.Transparent
}
return color.RGBA64{ return color.RGBA64{
R: uint16(area.totalR / uint64(len(area.Pixels))), R: uint16(area.totalR / uint64(len(area.Pixels))),
G: uint16(area.totalG / uint64(len(area.Pixels))), G: uint16(area.totalG / uint64(len(area.Pixels))),
@ -78,7 +80,7 @@ func (area *Area) AverageColor() color.Color {
} }
const ( const (
tolerance = uint32(3000) tolerance = uint32(10000)
) )
func diffAbs(a uint32, b uint32) uint32 { func diffAbs(a uint32, b uint32) uint32 {
@ -94,7 +96,7 @@ func ImproveQuality(img image.Image) *image.NRGBA {
width := img.Bounds().Dx() width := img.Bounds().Dx()
height := img.Bounds().Dy() height := img.Bounds().Dy()
clone := image.NewNRGBA(image.Rect(0, 0, width, height)) clone := image.NewNRGBA(image.Rect(0, 0, width, height))
areas := []Area{} areas := []*Area{}
areaIndexMap := make([]int, width*height) areaIndexMap := make([]int, width*height)
for x := 0; x < width; x++ { for x := 0; x < width; x++ {
@ -118,7 +120,7 @@ func ImproveQuality(img image.Image) *image.NRGBA {
// Insert new area // Insert new area
if areaIndex == -1 { if areaIndex == -1 {
areaIndex = len(areas) areaIndex = len(areas)
areas = append(areas, Area{}) areas = append(areas, &Area{})
} }
areaIndexMap[y*width+x] = areaIndex areaIndexMap[y*width+x] = areaIndex
@ -128,95 +130,147 @@ func ImproveQuality(img image.Image) *image.NRGBA {
fmt.Println(len(areas), "areas") fmt.Println(len(areas), "areas")
pixelCount := 0
for _, area := range areas {
pixelCount += len(area.Pixels)
}
// fmt.Println(pixelCount, "pixels", width*height)
// Reduce noise // Reduce noise
noiseCount := 0 noiseCount := 0
for r := 0; r < 30; r++ { for areaIndex, area := range areas {
for areaIndex, area := range areas { removals := []int{}
removals := []int{} areaSurroundedBy := map[int]int{}
for i := 0; i < len(area.Pixels); i++ { for i := 0; i < len(area.Pixels); i++ {
// If pixel is surrounded by 4 different areas, remove it // If pixel is surrounded by 4 different areas, remove it
pixel := area.Pixels[i] pixel := area.Pixels[i]
x := pixel.X x := pixel.X
y := pixel.Y y := pixel.Y
left := areaIndex left := areaIndex
right := areaIndex right := areaIndex
top := areaIndex top := areaIndex
bottom := areaIndex bottom := areaIndex
if x > 0 { if x > 0 {
left = areaIndexMap[y*width+(x-1)] left = areaIndexMap[y*width+(x-1)]
} }
if x < width-1 { if x < width-1 {
right = areaIndexMap[y*width+(x+1)] right = areaIndexMap[y*width+(x+1)]
} }
if y > 0 { if y > 0 {
top = areaIndexMap[(y-1)*width+x] top = areaIndexMap[(y-1)*width+x]
} }
if y < height-1 { if y < height-1 {
bottom = areaIndexMap[(y+1)*width+x] bottom = areaIndexMap[(y+1)*width+x]
} }
differentNeighbors := 0 differentNeighbors := 0
if left != areaIndex { if left != areaIndex {
differentNeighbors++ differentNeighbors++
} }
if right != areaIndex { if right != areaIndex {
differentNeighbors++ differentNeighbors++
} }
if top != areaIndex { if top != areaIndex {
differentNeighbors++ differentNeighbors++
} }
if bottom != areaIndex { if bottom != areaIndex {
differentNeighbors++ differentNeighbors++
} }
// Determine surrounding area // Determine surrounding area
areaIndexScore := map[int]int{} areaIndexScore := map[int]int{}
areaIndexScore[left]++
areaIndexScore[right]++
areaIndexScore[top]++
areaIndexScore[bottom]++
newAreaIndex := -1 areaIndexScore[left]++
bestScore := 0 areaIndexScore[right]++
areaIndexScore[top]++
areaIndexScore[bottom]++
for checkIndex, score := range areaIndexScore { areaSurroundedBy[left]++
if score > bestScore { areaSurroundedBy[right]++
bestScore = score areaSurroundedBy[top]++
newAreaIndex = checkIndex areaSurroundedBy[bottom]++
}
}
if differentNeighbors == 4 && bestScore >= 3 { newAreaIndex := -1
noiseCount++ bestScore := 0
removals = append(removals, i)
// Add to surrounding area for checkIndex, score := range areaIndexScore {
r, g, b, a := img.At(x, y).RGBA() if score > bestScore {
areas[newAreaIndex].Add(x, y, r, g, b, a) bestScore = score
newAreaIndex = checkIndex
} }
} }
offset := 0 if differentNeighbors >= 3 && bestScore >= 3 {
noiseCount++
removals = append(removals, i)
for _, removal := range removals { // Add to surrounding area
area.Pixels = append(area.Pixels[:removal-offset], area.Pixels[removal-offset+1:]...) r, g, b, a := img.At(x, y).RGBA()
offset++ areas[newAreaIndex].Add(x, y, r, g, b, a)
} }
} }
// Remove noise pixels
// offset := 0
// for _, removal := range removals {
// index := removal - offset
// area.Pixels = append(area.Pixels[:index], area.Pixels[index+1:]...)
// // area.Pixels = area.Pixels[:index+copy(area.Pixels[index:], area.Pixels[index+1:])]
// offset++
// }
// Determine surrounding area
surroundingAreaIndex := -1
bestScore := 0
for checkIndex, score := range areaSurroundedBy {
if score > bestScore {
bestScore = score
surroundingAreaIndex = checkIndex
}
}
if areaIndex != surroundingAreaIndex {
// fmt.Println(areaIndex, "surrounded by", surroundingAreaIndex, "|", len(area.Pixels), len(areas[surroundingAreaIndex].Pixels))
// // Add pixels to surrounding area
// for _, pixel := range area.Pixels {
// r, g, b, a := img.At(pixel.X, pixel.Y).RGBA()
// areas[surroundingAreaIndex].Add(pixel.X, pixel.Y, r, g, b, a)
// }
// // Remove this area
// area.Pixels = nil
// area.totalR = 0
// area.totalG = 0
// area.totalB = 0
// area.totalA = 0
}
} }
fmt.Println(noiseCount, "noise pixels") fmt.Println(noiseCount, "noise pixels")
pixelCount = 0
for _, area := range areas {
pixelCount += len(area.Pixels)
}
fmt.Println(pixelCount, "pixels", width*height)
// Build image from areas // Build image from areas
for _, area := range areas { for _, area := range areas {
avgColor := area.AverageColor() avgColor := area.AverageColor()