This commit is contained in:
Ingy döt Net 2013-04-10 21:29:02 -07:00
parent 764da6cbbb
commit db842d013d
19005 changed files with 197040 additions and 7 deletions

View file

@ -0,0 +1,91 @@
package main
import (
"fmt"
"image"
"image/color"
"image/jpeg"
"math"
"os"
)
// kf3 is a generic convolution 3x3 kernel filter that operatates on
// images of type image.Gray from the Go standard image library.
func kf3(k *[9]float64, src, dst *image.Gray) {
for y := src.Rect.Min.Y; y < src.Rect.Max.Y; y++ {
for x := src.Rect.Min.X; x < src.Rect.Max.X; x++ {
var sum float64
var i int
for yo := y - 1; yo <= y+1; yo++ {
for xo := x - 1; xo <= x+1; xo++ {
if (image.Point{xo, yo}).In(src.Rect) {
sum += k[i] * float64(src.At(xo, yo).(color.Gray).Y)
} else {
sum += k[i] * float64(src.At(x, y).(color.Gray).Y)
}
i++
}
}
dst.SetGray(x, y,
color.Gray{uint8(math.Min(255, math.Max(0, sum)))})
}
}
}
var blur = [9]float64{
1. / 9, 1. / 9, 1. / 9,
1. / 9, 1. / 9, 1. / 9,
1. / 9, 1. / 9, 1. / 9}
// blurY example function applies blur kernel to Y channel
// of YCbCr image using generic kernel filter function kf3
func blurY(src *image.YCbCr) *image.YCbCr {
dst := *src
// catch zero-size image here
if src.Rect.Max.X == src.Rect.Min.X || src.Rect.Max.Y == src.Rect.Min.Y {
return &dst
}
// pass Y channels as gray images
srcGray := image.Gray{src.Y, src.YStride, src.Rect}
dstGray := srcGray
dstGray.Pix = make([]uint8, len(src.Y))
kf3(&blur, &srcGray, &dstGray) // call generic convolution function
// complete result
dst.Y = dstGray.Pix // convolution result
dst.Cb = append([]uint8{}, src.Cb...) // Cb, Cr are just copied
dst.Cr = append([]uint8{}, src.Cr...)
return &dst
}
func main() {
// Example file used here is Lenna100.jpg from the task "Percentage
// difference between images"
f, err := os.Open("Lenna100.jpg")
if err != nil {
fmt.Println(err)
return
}
img, err := jpeg.Decode(f)
if err != nil {
fmt.Println(err)
return
}
f.Close()
y, ok := img.(*image.YCbCr)
if !ok {
fmt.Println("expected color jpeg")
return
}
f, err = os.Create("blur.jpg")
if err != nil {
fmt.Println(err)
return
}
err = jpeg.Encode(f, blurY(y), &jpeg.Options{90})
if err != nil {
fmt.Println(err)
}
}

View file

@ -0,0 +1,72 @@
package raster
import "math"
func (g *Grmap) KernelFilter3(k []float64) *Grmap {
if len(k) != 9 {
return nil
}
r := NewGrmap(g.cols, g.rows)
r.Comments = append([]string{}, g.Comments...)
// Filter edge pixels with minimal code.
// Execution time per pixel is high but there are few edge pixels
// relative to the interior.
o3 := [][]int{
{-1, -1}, {0, -1}, {1, -1},
{-1, 0}, {0, 0}, {1, 0},
{-1, 1}, {0, 1}, {1, 1}}
edge := func(x, y int) uint16 {
var sum float64
for i, o := range o3 {
c, ok := g.GetPx(x+o[0], y+o[1])
if !ok {
c = g.pxRow[y][x]
}
sum += float64(c) * k[i]
}
return uint16(math.Min(math.MaxUint16, math.Max(0,sum)))
}
for x := 0; x < r.cols; x++ {
r.pxRow[0][x] = edge(x, 0)
r.pxRow[r.rows-1][x] = edge(x, r.rows-1)
}
for y := 1; y < r.rows-1; y++ {
r.pxRow[y][0] = edge(0, y)
r.pxRow[y][r.cols-1] = edge(r.cols-1, y)
}
if r.rows < 3 || r.cols < 3 {
return r
}
// Interior pixels can be filtered much more efficiently.
otr := -g.cols + 1
obr := g.cols + 1
z := g.cols + 1
c2 := g.cols - 2
for y := 1; y < r.rows-1; y++ {
tl := float64(g.pxRow[y-1][0])
tc := float64(g.pxRow[y-1][1])
tr := float64(g.pxRow[y-1][2])
ml := float64(g.pxRow[y][0])
mc := float64(g.pxRow[y][1])
mr := float64(g.pxRow[y][2])
bl := float64(g.pxRow[y+1][0])
bc := float64(g.pxRow[y+1][1])
br := float64(g.pxRow[y+1][2])
for x := 1; ; x++ {
r.px[z] = uint16(math.Min(math.MaxUint16, math.Max(0,
tl*k[0] + tc*k[1] + tr*k[2] +
ml*k[3] + mc*k[4] + mr*k[5] +
bl*k[6] + bc*k[7] + br*k[8])))
if x == c2 {
break
}
z++
tl, tc, tr = tc, tr, float64(g.px[z+otr])
ml, mc, mr = mc, mr, float64(g.px[z+1])
bl, bc, br = bc, br, float64(g.px[z+obr])
}
z += 3
}
return r
}

View file

@ -0,0 +1,40 @@
package main
// Files required to build supporting package raster are found in:
// * This task (immediately above)
// * Bitmap
// * Grayscale image
// * Read a PPM file
// * Write a PPM file
import (
"fmt"
"raster"
)
var blur = []float64{
1./9, 1./9, 1./9,
1./9, 1./9, 1./9,
1./9, 1./9, 1./9}
var sharpen = []float64{
-1, -1, -1,
-1, 9, -1,
-1, -1, -1}
func main() {
// Example file used here is Lenna100.jpg from the task "Percentage
// difference between images" converted with with the command
// convert Lenna100.jpg -colorspace gray Lenna100.ppm
b, err := raster.ReadPpmFile("Lenna100.ppm")
if err != nil {
fmt.Println(err)
return
}
g0 := b.Grmap()
g1 := g0.KernelFilter3(blur)
err = g1.Bitmap().WritePpmFile("blur.ppm")
if err != nil {
fmt.Println(err)
}
}