Skip to content

Instantly share code, notes, and snippets.

@Lokno
Last active August 29, 2015 14:07
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 Lokno/f8c86c6e912bc929d666 to your computer and use it in GitHub Desktop.
Save Lokno/f8c86c6e912bc929d666 to your computer and use it in GitHub Desktop.
A Go-lang script that composes an anaglyph image from two images
// Author : Jonathan Decker
// Description : Takes a stereo image (side-by-side) or
// two images for each eye and composes them into an anaglyph image
// usage: anaglyph.go [-s,--single <side-by-side>|<left> <right>] <anaglyph.png> [RGB]
//
// parameters:
// -s,--single <side-by-side> - One image file with side-by-side images one for each eye
// <left> <right> - Two image files, one for each eye.
// <anaglyph.png> - path to write the composite PNG image.
// [RGB] - (Optional) How images are distributed between the eyes.
// write a three character sequence of 'L' (left eye) and 'R' (right eye)
// (default RLL - red comes from right image, blue and green come from left)
package main
import (
"image"
"image/jpeg"
"image/png"
"image/gif"
"os"
"fmt"
"image/color"
"strings"
"time"
"runtime"
)
func stereo(dst *image.RGBA, lft, rgt image.Image, x0, y0, w, h, offset int, rLft, gLft, bLft bool, done chan bool) {
for x := x0; x < x0+w; x++ {
for y := y0; y < y0+h; y++ {
lr,lg,lb,_ := lft.At(x,y).RGBA()
rr,rg,rb,_ := rgt.At(x+offset,y).RGBA()
cr := rr
cg := rg
cb := rb
if rLft {
cr = lr
}
if gLft {
cg = lg
}
if bLft {
cb = lb
}
dst.SetRGBA(x,y,color.RGBA{uint8(cr >> 8),uint8(cg >> 8),uint8(cb >> 8),uint8(255)})
}
}
done <- true
}
func readImage( filename string ) (image.Image) {
infile, inerr := os.Open(filename)
var img image.Image
if inerr == nil {
var imgerr error
fileNameLen := len(filename)
fileExtension := filename[fileNameLen-4 : fileNameLen]
fileExtension = strings.ToLower(fileExtension)
if fileExtension == ".png" {
img, imgerr = png.Decode(infile)
} else if fileExtension == ".jpg" || filename[fileNameLen-5:fileNameLen] == ".jpeg" {
img, imgerr = jpeg.Decode(infile)
} else if fileExtension == ".gif" {
img, imgerr = gif.Decode(infile)
} else {
fmt.Printf("Error: Image Format Not Supported\n")
infile.Close()
os.Exit(-1)
}
if imgerr != nil {
fmt.Printf("Error: Could not decode image\n")
}
infile.Close()
} else {
fmt.Printf("Error: Could not open file\n")
os.Exit(-1)
}
return img
}
const BSIZE int = 64
const interations float64 = 1
func main() {
argc := len(os.Args)
if argc < 4 {
fmt.Println(" usage anaglyph.go [-s,--single <side-by-side>|<left> <right>] <anaglyph.png> [RGB]")
os.Exit(1)
}
var outfile *os.File
var outerr error
isSideBySide := false
if os.Args[1] == "-s" || os.Args[1] == "--single" {
isSideBySide = true
}
outfile, outerr = os.Create(os.Args[3])
channels := "RLL"
rLft := false
gLft := true
bLft := true
if argc == 5 {
channels = os.Args[4]
}
if len(channels) == 3 {
rLft = false
gLft = false
bLft = false
if channels[0] == 'L' {
rLft = true
}
if channels[1] == 'L' {
gLft = true
}
if channels[2] == 'L' {
bLft = true
}
} else {
fmt.Println("Unexpected channel parameter, defaulting to RLL...")
}
runtime.GOMAXPROCS(8)
if outerr == nil {
var lftImage image.Image
var rgtImage image.Image
offset := 0
if isSideBySide {
lftImage = readImage(os.Args[2])
} else {
lftImage = readImage(os.Args[1])
rgtImage = readImage(os.Args[2])
}
bnds := lftImage.Bounds()
w := bnds.Max.X - bnds.Min.X
h := bnds.Max.Y - bnds.Min.Y
if w < 1 || w % 2 != 0 {
fmt.Println("Error: Invalid Width")
os.Exit(2)
}
if isSideBySide {
w /= 2
offset = w
rgtImage = lftImage
}
rgba := image.NewRGBA(image.Rect(0,0,w,h))
xBlocks := w / BSIZE
yBlocks := h / BSIZE
if w % BSIZE != 0 {
xBlocks++
}
if h % BSIZE != 0 {
yBlocks++
}
avgTime := 0.0
for i := 0; i < int(interations); i++ {
done := make(chan bool)
start := time.Now()
for x := 0; x < xBlocks; x++ {
for y := 0; y < yBlocks; y++ {
wBlockSize := BSIZE
hBlockSize := BSIZE
if x == xBlocks-1 {
wBlockSize = w - x*BSIZE
}
if y == yBlocks-1 {
hBlockSize = h - y*BSIZE
}
go stereo(rgba,lftImage,rgtImage,x*BSIZE,y*BSIZE,wBlockSize,hBlockSize,offset,rLft,gLft,bLft,done)
}
}
for x := 0; x < xBlocks; x++ {
for y := 0; y < yBlocks; y++ {
<-done
}
}
avgTime += time.Since(start).Seconds()
}
fmt.Printf("%fms\n", (avgTime / interations)*1000)
imgerr2 := png.Encode(outfile, rgba)
if imgerr2 != nil {
fmt.Printf("Error: could not encode PNG")
}
} else {
fmt.Println("Error: Could not open file for writing")
}
outfile.Close()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment