Skip to content

Instantly share code, notes, and snippets.

@hnatar
Created January 3, 2019 21:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hnatar/575c5880ca30d0408bbd01a0c64ff696 to your computer and use it in GitHub Desktop.
Save hnatar/575c5880ca30d0408bbd01a0c64ff696 to your computer and use it in GitHub Desktop.
Compression
package main
import (
"image"
"image/color"
_ "image/jpeg"
"image/png"
"math"
"os"
)
func blocky(out *image.RGBA, img *image.Image, xs, xe, ys, ye int, size int) {
// Sanity check
if xs >= xe && ys >= ye {
return
}
// Compute the mean RGB color for each pixel in region
mr, mg, mb, cnt := 0.0, 0.0, 0.0, 0.0
for y := ys; y <= ye; y++ {
for x := xs; x <= xe; x++ {
r, g, b, _ := (*img).At(x, y).RGBA()
r, g, b = r/257, g/257, b/257
mr, mg, mb, cnt = mr+float64(r), mg+float64(g), mb+float64(b), cnt+1.0
}
}
mr, mg, mb = mr/cnt, mg/cnt, mb/cnt
// Compute the MSE
e := 0.0
for y := ys; y <= ye; y++ {
for x := xs; x <= xe; x++ {
r, g, b, _ := (*img).At(x, y).RGBA()
r, g, b = r/257, g/257, b/257
e += math.Pow(mr-float64(r), 2) + math.Pow(mg-float64(g), 2) + math.Pow(mb-float64(b), 2)
}
}
e /= cnt
// Check if we can stop
if e <= 1000.0 {
for y := ys; y <= ye; y++ {
for x := xs; x <= xe; x++ {
out.Set(x, y, color.RGBA{uint8(mr), uint8(mg), uint8(mb), 255})
}
}
return
}
if xe-xs+1 <= size || ye-ys+1 <= size {
for y := ys; y <= ye; y++ {
for x := xs; x <= xe; x++ {
out.Set(x, y, color.RGBA{uint8(mr), uint8(mg), uint8(mb), 255})
}
}
return
}
// Cannot; Divide into quadrants and solve recursively
// Base case of small pixel sizes (e.g. 1x1) will satisfy
// MSE threshold and return before this
xm := xs + int(xe-xs)/2
ym := ys + int(ye-ys)/2
if xm-xs > 0 && ym-ys > 0 {
blocky(out, img, xs, xm-1, ys, ym-1, size)
}
if xm-xs > 0 && ye-ym+1 > 0 {
blocky(out, img, xs, xm-1, ym, ye, size)
}
if xe-xm+1 > 0 && ym-ys > 0 {
blocky(out, img, xm, xe, ys, ym-1, size)
}
if xe-xm+1 > 0 && ye-ym+1 > 0 {
blocky(out, img, xm, xe, ym, ye, size)
}
}
func main() {
// Arg parsing not done, but format:
// go run blocky.go --in <inputjpeg> --out <outputpng>
f, ok := os.Open(os.Args[2])
if ok != nil {
panic("Cat not found :(")
}
defer f.Close()
src, _, ok := image.Decode(f)
if ok != nil {
panic("Image reading went wrong")
}
dims := src.Bounds()
x0, x1, y0, y1 := dims.Min.X, dims.Max.X-1, dims.Min.Y, dims.Max.Y-1
m := image.NewRGBA(src.Bounds())
// Block size
blocky(m, &src, x0, x1, y0, y1, 512)
out, ok := os.Create(os.Args[4])
if ok != nil {
panic("Could not open file for writing")
}
defer out.Close()
png.Encode(out, m)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment