Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

run operations in parallel #9

Merged
merged 2 commits into from
Apr 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ linters:
- lll
- gochecknoglobals
- maligned
- interfacer
- interfacer
- gochecknoinits
36 changes: 20 additions & 16 deletions pkg/cubelut/cubelut.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"strings"

"github.com/overhq/lut/pkg/colorcube"
"github.com/overhq/lut/pkg/parallel"
"github.com/overhq/lut/pkg/util"
)

Expand Down Expand Up @@ -192,28 +193,31 @@ func (cf CubeFile) Apply(src image.Image, intensity float64) (image.Image, error

N := float64(cf.Size)

for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
px := src.At(x, y)
c := model.Convert(px).(color.NRGBA)
width, height := bounds.Dx(), bounds.Dy()
parallel.Line(height, func(start, end int) {
for y := start; y < end; y++ {
for x := 0; x < width; x++ {
px := src.At(x, y)
c := model.Convert(px).(color.NRGBA)

r := math.Floor((float64(c.R) / 255.0) * (N - 1))
g := math.Floor((float64(c.G) / 255.0) * (N - 1))
b := math.Floor((float64(c.B) / 255.0) * (N - 1))
r := math.Floor((float64(c.R) / 255.0) * (N - 1))
g := math.Floor((float64(c.G) / 255.0) * (N - 1))
b := math.Floor((float64(c.B) / 255.0) * (N - 1))

i := r + N*g + N*N*b
i := r + N*g + N*N*b

lr, lg, lb := uint8(cf.R[int(i)]*255), uint8(cf.G[int(i)]*255), uint8(cf.B[int(i)]*255)
lr, lg, lb := uint8(cf.R[int(i)]*255), uint8(cf.G[int(i)]*255), uint8(cf.B[int(i)]*255)

o := color.NRGBA{}
o.R = uint8(float64(c.R)*(1-intensity) + float64(lr)*intensity)
o.G = uint8(float64(c.G)*(1-intensity) + float64(lg)*intensity)
o.B = uint8(float64(c.B)*(1-intensity) + float64(lb)*intensity)
o.A = c.A
o := color.NRGBA{}
o.R = uint8(float64(c.R)*(1-intensity) + float64(lr)*intensity)
o.G = uint8(float64(c.G)*(1-intensity) + float64(lg)*intensity)
o.B = uint8(float64(c.B)*(1-intensity) + float64(lb)*intensity)
o.A = c.A

out.Set(x, y, o)
out.Set(x, y, o)
}
}
}
})

return out, nil
}
40 changes: 22 additions & 18 deletions pkg/imagelut/imagelut.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"math"

"github.com/overhq/lut/pkg/colorcube"
"github.com/overhq/lut/pkg/parallel"
)

// FromColorCube will create an image from a color cube
Expand Down Expand Up @@ -88,29 +89,32 @@ func Apply(src, effect image.Image, intensity float64) (image.Image, error) {
space := &image.NRGBA{}
model := space.ColorModel()

for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
// not all images use the same colour space, so ensure we convert
// them all to nrgba to be consistent with our output
px := src.At(x, y)
c := model.Convert(px).(color.NRGBA)
width, height := bounds.Dx(), bounds.Dy()
parallel.Line(height, func(start, end int) {
for y := start; y < end; y++ {
for x := 0; x < width; x++ {
// not all images use the same colour space, so ensure we convert
// them all to nrgba to be consistent with our output
px := src.At(x, y)
c := model.Convert(px).(color.NRGBA)

// find the location of the pixel in our lookup table
lutx := int((c.B/4%8)*64 + c.R/4)
luty := int(math.Floor(float64(c.B/4)/8)*64 + float64(c.G/4))
// find the location of the pixel in our lookup table
lutx := int((c.B/4%8)*64 + c.R/4)
luty := int(math.Floor(float64(c.B/4)/8)*64 + float64(c.G/4))

lut := effect.At(lutx, luty).(color.RGBA)
lut := effect.At(lutx, luty).(color.RGBA)

// create our output colour, adjusted according to the intensity
o := color.NRGBA{}
o.R = uint8(float64(c.R)*(1-intensity) + float64(lut.R)*intensity)
o.G = uint8(float64(c.G)*(1-intensity) + float64(lut.G)*intensity)
o.B = uint8(float64(c.B)*(1-intensity) + float64(lut.B)*intensity)
o.A = c.A
// create our output colour, adjusted according to the intensity
o := color.NRGBA{}
o.R = uint8(float64(c.R)*(1-intensity) + float64(lut.R)*intensity)
o.G = uint8(float64(c.G)*(1-intensity) + float64(lut.G)*intensity)
o.B = uint8(float64(c.B)*(1-intensity) + float64(lut.B)*intensity)
o.A = c.A

out.Set(x, y, o)
out.Set(x, y, o)
}
}
}
})

return out, nil
}
40 changes: 40 additions & 0 deletions pkg/parallel/parallel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Package parallel was taken from github.com/anthonynsimon/bild
// https://git.io/fjOJ2
package parallel

import (
"runtime"
"sync"
)

func init() {
runtime.GOMAXPROCS(runtime.NumCPU())
}

// Line dispatches a parameter fn into multiple goroutines by splitting the parameter length
// by the number of available CPUs and assigning the length parts into each fn.
func Line(length int, fn func(start, end int)) {
procs := runtime.GOMAXPROCS(0)
counter := length
partSize := length / procs
if procs <= 1 || partSize <= procs {
fn(0, length)
} else {
var wg sync.WaitGroup
for counter > 0 {
start := counter - partSize
end := counter
if start < 0 {
start = 0
}
counter -= partSize
wg.Add(1)
go func() {
defer wg.Done()
fn(start, end)
}()
}

wg.Wait()
}
}
48 changes: 26 additions & 22 deletions pkg/trilinear/trilinear.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"math"

"github.com/overhq/lut/pkg/colorcube"
"github.com/overhq/lut/pkg/parallel"
)

// bits per channel (we're assuming 8-bits)
Expand Down Expand Up @@ -36,29 +37,32 @@ func Interpolate(src image.Image, cube colorcube.Cube, intensity float64) (image
dKG := cube.DomainMax[1] - cube.DomainMin[1]
dKB := cube.DomainMax[2] - cube.DomainMin[2]

for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
px := src.At(x, y)
c := model.Convert(px).(color.NRGBA)

rgb := getFromRGBTrilinear(
int(c.R),
int(c.G),
int(c.B),
cube.Size,
k,
cube,
)

o := color.NRGBA{}
o.R = uint8(float64(c.R)*(1-intensity) + float64(toIntCh(rgb[0]*dKR))*intensity)
o.G = uint8(float64(c.G)*(1-intensity) + float64(toIntCh(rgb[1]*dKG))*intensity)
o.B = uint8(float64(c.B)*(1-intensity) + float64(toIntCh(rgb[2]*dKB))*intensity)
o.A = c.A

out.Set(x, y, o)
width, height := bounds.Dx(), bounds.Dy()
parallel.Line(height, func(start, end int) {
for y := start; y < end; y++ {
for x := 0; x < width; x++ {
px := src.At(x, y)
c := model.Convert(px).(color.NRGBA)

rgb := getFromRGBTrilinear(
int(c.R),
int(c.G),
int(c.B),
cube.Size,
k,
cube,
)

o := color.NRGBA{}
o.R = uint8(float64(c.R)*(1-intensity) + float64(toIntCh(rgb[0]*dKR))*intensity)
o.G = uint8(float64(c.G)*(1-intensity) + float64(toIntCh(rgb[1]*dKG))*intensity)
o.B = uint8(float64(c.B)*(1-intensity) + float64(toIntCh(rgb[2]*dKB))*intensity)
o.A = c.A

out.Set(x, y, o)
}
}
}
})

return out, nil
}
Expand Down