Disabled image quality patch

This commit is contained in:
Eduard Urbach 2018-04-26 20:20:41 +02:00
parent 1f0adabde2
commit 4f6078943c

View File

@ -1,287 +1,289 @@
package main package main
import ( func main() {}
"bytes"
"fmt"
"image"
"image/color"
_ "image/jpeg"
"image/png"
"io/ioutil"
"os"
)
func main() { // import (
data, err := ioutil.ReadFile("input.jpg") // "bytes"
// "fmt"
// "image"
// "image/color"
// _ "image/jpeg"
// "image/png"
// "io/ioutil"
// "os"
// )
if err != nil { // func main() {
panic(err) // data, err := ioutil.ReadFile("input.jpg")
}
img, _, err := image.Decode(bytes.NewReader(data)) // if err != nil {
// panic(err)
// }
if err != nil { // img, _, err := image.Decode(bytes.NewReader(data))
panic(err)
}
improved := ImproveQuality(img) // if err != nil {
f, err := os.Create("output.png") // panic(err)
// }
if err != nil { // improved := ImproveQuality(img)
panic(err) // f, err := os.Create("output.png")
}
defer f.Close() // if err != nil {
png.Encode(f, improved) // panic(err)
} // }
// Pixel ... // defer f.Close()
type Pixel struct { // png.Encode(f, improved)
X int // }
Y int
}
// Area ... // // Pixel ...
type Area struct { // type Pixel struct {
Pixels []Pixel // X int
totalR uint64 // Y int
totalG uint64 // }
totalB uint64
totalA uint64
}
// Add ... // // Area ...
func (area *Area) Add(x, y int, r, g, b, a uint32) { // type Area struct {
area.Pixels = append(area.Pixels, Pixel{ // Pixels []Pixel
X: x, // totalR uint64
Y: y, // totalG uint64
}) // totalB uint64
// totalA uint64
// }
area.totalR += uint64(r) // // Add ...
area.totalG += uint64(g) // func (area *Area) Add(x, y int, r, g, b, a uint32) {
area.totalB += uint64(b) // area.Pixels = append(area.Pixels, Pixel{
area.totalA += uint64(a) // X: x,
} // Y: y,
// })
// AverageColor ... // area.totalR += uint64(r)
func (area *Area) AverageColor() color.Color { // area.totalG += uint64(g)
if len(area.Pixels) == 0 { // area.totalB += uint64(b)
return color.Transparent // area.totalA += uint64(a)
} // }
return color.RGBA64{ // // AverageColor ...
R: uint16(area.totalR / uint64(len(area.Pixels))), // func (area *Area) AverageColor() color.Color {
G: uint16(area.totalG / uint64(len(area.Pixels))), // if len(area.Pixels) == 0 {
B: uint16(area.totalB / uint64(len(area.Pixels))), // return color.Transparent
A: uint16(area.totalA / uint64(len(area.Pixels))), // }
}
}
const ( // return color.RGBA64{
tolerance = uint32(3000) // R: uint16(area.totalR / uint64(len(area.Pixels))),
) // G: uint16(area.totalG / uint64(len(area.Pixels))),
// B: uint16(area.totalB / uint64(len(area.Pixels))),
// A: uint16(area.totalA / uint64(len(area.Pixels))),
// }
// }
func diffAbs(a uint32, b uint32) uint32 { // const (
if a > b { // tolerance = uint32(3000)
return a - b // )
}
return b - a // func diffAbs(a uint32, b uint32) uint32 {
} // if a > b {
// return a - b
// }
// ImproveQuality returns the average color of an image in HSL format. // return b - a
func ImproveQuality(img image.Image) *image.NRGBA { // }
width := img.Bounds().Dx()
height := img.Bounds().Dy()
clone := image.NewNRGBA(image.Rect(0, 0, width, height))
areas := []*Area{}
areaIndexMap := make([]int, width*height)
for x := 0; x < width; x++ { // // ImproveQuality returns the average color of an image in HSL format.
for y := 0; y < height; y++ { // func ImproveQuality(img image.Image) *image.NRGBA {
color := img.At(x, y) // width := img.Bounds().Dx()
r, g, b, a := color.RGBA() // height := img.Bounds().Dy()
areaIndex := -1 // clone := image.NewNRGBA(image.Rect(0, 0, width, height))
// areas := []*Area{}
// areaIndexMap := make([]int, width*height)
// Find similar area // for x := 0; x < width; x++ {
for i := 0; i < len(areas); i++ { // for y := 0; y < height; y++ {
area := areas[i] // color := img.At(x, y)
avgR, avgG, avgB, _ := area.AverageColor().RGBA() // r, g, b, a := color.RGBA()
// areaIndex := -1
// Is the color similar? // // Find similar area
if diffAbs(r, avgR) <= tolerance && diffAbs(g, avgG) <= tolerance && diffAbs(b, avgB) <= tolerance { // for i := 0; i < len(areas); i++ {
areaIndex = i // area := areas[i]
break // avgR, avgG, avgB, _ := area.AverageColor().RGBA()
}
}
// Insert new area // // Is the color similar?
if areaIndex == -1 { // if diffAbs(r, avgR) <= tolerance && diffAbs(g, avgG) <= tolerance && diffAbs(b, avgB) <= tolerance {
areaIndex = len(areas) // areaIndex = i
areas = append(areas, &Area{}) // break
} // }
// }
areaIndexMap[y*width+x] = areaIndex // // Insert new area
areas[areaIndex].Add(x, y, r, g, b, a) // if areaIndex == -1 {
} // areaIndex = len(areas)
} // areas = append(areas, &Area{})
// }
fmt.Println(len(areas), "areas") // areaIndexMap[y*width+x] = areaIndex
// areas[areaIndex].Add(x, y, r, g, b, a)
// }
// }
// Reduce noise // fmt.Println(len(areas), "areas")
noiseCount := 0
for areaIndex, area := range areas { // // Reduce noise
noisePixelIndices := []int{} // noiseCount := 0
areaSurroundedBy := map[int]int{}
for i := 0; i < len(area.Pixels); i++ { // for areaIndex, area := range areas {
// If pixel is surrounded by 4 different areas, remove it // noisePixelIndices := []int{}
pixel := area.Pixels[i] // areaSurroundedBy := map[int]int{}
x := pixel.X
y := pixel.Y
left := areaIndex
right := areaIndex
top := areaIndex
bottom := areaIndex
if x > 0 { // for i := 0; i < len(area.Pixels); i++ {
left = areaIndexMap[y*width+(x-1)] // // If pixel is surrounded by 4 different areas, remove it
} // pixel := area.Pixels[i]
// x := pixel.X
// y := pixel.Y
// left := areaIndex
// right := areaIndex
// top := areaIndex
// bottom := areaIndex
if x < width-1 { // if x > 0 {
right = areaIndexMap[y*width+(x+1)] // left = areaIndexMap[y*width+(x-1)]
} // }
if y > 0 { // if x < width-1 {
top = areaIndexMap[(y-1)*width+x] // right = areaIndexMap[y*width+(x+1)]
} // }
if y < height-1 { // if y > 0 {
bottom = areaIndexMap[(y+1)*width+x] // top = areaIndexMap[(y-1)*width+x]
} // }
differentNeighbors := 0 // if y < height-1 {
// bottom = areaIndexMap[(y+1)*width+x]
// }
if left != areaIndex { // differentNeighbors := 0
differentNeighbors++
}
if right != areaIndex { // if left != areaIndex {
differentNeighbors++ // differentNeighbors++
} // }
if top != areaIndex { // if right != areaIndex {
differentNeighbors++ // differentNeighbors++
} // }
if bottom != areaIndex { // if top != areaIndex {
differentNeighbors++ // differentNeighbors++
} // }
// Determine surrounding area // if bottom != areaIndex {
areaIndexScore := map[int]int{} // differentNeighbors++
// }
areaIndexScore[left]++
areaIndexScore[right]++
areaIndexScore[top]++
areaIndexScore[bottom]++
areaSurroundedBy[left]++
areaSurroundedBy[right]++
areaSurroundedBy[top]++
areaSurroundedBy[bottom]++
newAreaIndex := -1
bestScore := 0
for checkIndex, score := range areaIndexScore {
if score > bestScore {
bestScore = score
newAreaIndex = checkIndex
}
}
if differentNeighbors >= 3 && bestScore >= 3 {
noiseCount++
noisePixelIndices = append(noisePixelIndices, i)
// Add to surrounding area
r, g, b, a := img.At(x, y).RGBA()
areas[newAreaIndex].Add(x, y, r, g, b, a)
area.totalR -= uint64(r)
area.totalG -= uint64(g)
area.totalB -= uint64(b)
area.totalA -= uint64(a)
}
}
// Remove noise pixels
offset := 0
for _, removal := range noisePixelIndices {
index := removal - offset
area.Pixels = append(area.Pixels[:index], area.Pixels[index+1:]...)
offset++
}
// // Determine surrounding area // // Determine surrounding area
// surroundingAreaIndex := -1 // areaIndexScore := map[int]int{}
// areaIndexScore[left]++
// areaIndexScore[right]++
// areaIndexScore[top]++
// areaIndexScore[bottom]++
// areaSurroundedBy[left]++
// areaSurroundedBy[right]++
// areaSurroundedBy[top]++
// areaSurroundedBy[bottom]++
// newAreaIndex := -1
// bestScore := 0 // bestScore := 0
// for checkIndex, score := range areaSurroundedBy { // for checkIndex, score := range areaIndexScore {
// if score > bestScore && checkIndex != areaIndex { // if score > bestScore {
// bestScore = score // bestScore = score
// surroundingAreaIndex = checkIndex // newAreaIndex = checkIndex
// } // }
// } // }
// surroundingArea := areas[surroundingAreaIndex] // if differentNeighbors >= 3 && bestScore >= 3 {
// noiseCount++
// noisePixelIndices = append(noisePixelIndices, i)
// if areaIndex != surroundingAreaIndex && len(surroundingArea.Pixels) > len(area.Pixels)*2 { // // Add to surrounding area
// // const surroundTolerance = 5000 // r, g, b, a := img.At(x, y).RGBA()
// areas[newAreaIndex].Add(x, y, r, g, b, a)
// // r1, g1, b1, a1 := area.AverageColor().RGBA() // area.totalR -= uint64(r)
// // r2, g2, b2, a2 := surroundingArea.AverageColor().RGBA() // area.totalG -= uint64(g)
// area.totalB -= uint64(b)
// area.totalA -= uint64(a)
// }
// }
// // if diffAbs(r1, r2) < surroundTolerance && diffAbs(g1, g2) < surroundTolerance && diffAbs(b1, b2) < surroundTolerance && diffAbs(a1, a2) < surroundTolerance { // // Remove noise pixels
// // // fmt.Println(areaIndex, "surrounded by", surroundingAreaIndex, "|", len(area.Pixels), len(surroundingArea.Pixels)) // offset := 0
// // // Add pixels to surrounding area // for _, removal := range noisePixelIndices {
// // for _, pixel := range area.Pixels { // index := removal - offset
// // r, g, b, a := img.At(pixel.X, pixel.Y).RGBA() // area.Pixels = append(area.Pixels[:index], area.Pixels[index+1:]...)
// // surroundingArea.Add(pixel.X, pixel.Y, r, g, b, a) // offset++
// }
// // // Determine surrounding area
// // surroundingAreaIndex := -1
// // bestScore := 0
// // for checkIndex, score := range areaSurroundedBy {
// // if score > bestScore && checkIndex != areaIndex {
// // bestScore = score
// // surroundingAreaIndex = checkIndex
// // }
// // } // // }
// // // Remove this area // // surroundingArea := areas[surroundingAreaIndex]
// // area.Pixels = nil
// // area.totalR = 0 // // if areaIndex != surroundingAreaIndex && len(surroundingArea.Pixels) > len(area.Pixels)*2 {
// // area.totalG = 0 // // // const surroundTolerance = 5000
// // area.totalB = 0
// // area.totalA = 0 // // // r1, g1, b1, a1 := area.AverageColor().RGBA()
// // // r2, g2, b2, a2 := surroundingArea.AverageColor().RGBA()
// // // if diffAbs(r1, r2) < surroundTolerance && diffAbs(g1, g2) < surroundTolerance && diffAbs(b1, b2) < surroundTolerance && diffAbs(a1, a2) < surroundTolerance {
// // // // fmt.Println(areaIndex, "surrounded by", surroundingAreaIndex, "|", len(area.Pixels), len(surroundingArea.Pixels))
// // // // Add pixels to surrounding area
// // // for _, pixel := range area.Pixels {
// // // r, g, b, a := img.At(pixel.X, pixel.Y).RGBA()
// // // surroundingArea.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 // pixelCount := 0
for _, area := range areas { // for _, area := range areas {
pixelCount += len(area.Pixels) // pixelCount += len(area.Pixels)
} // }
fmt.Println(pixelCount, "pixels", width*height) // 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()
for _, pixel := range area.Pixels { // for _, pixel := range area.Pixels {
clone.Set(pixel.X, pixel.Y, avgColor) // clone.Set(pixel.X, pixel.Y, avgColor)
} // }
} // }
return clone // return clone
} // }