<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/RandomByte/colorfinder"
	"image"
	"image/color"
	"image/draw"
	_ "image/jpeg"
	"log"
	"math"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"syscall"
	"time"
)

type SubImager interface {
	SubImage(r image.Rectangle) image.Image
}

func main() {
	log.Println(runtime.GOMAXPROCS(8))

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt, os.Kill, syscall.SIGTERM)
	defer signal.Stop(sig)

	cam := Cam{}
	defer cam.Kill()

	cam.Setup()

	for {
		select {
		case <-time.After(1 * time.Millisecond):
			loop()
		case s := <-sig:
			log.Println("Got signal:", s)
			log.Println("Quitting...")
			return
		}
	}
}

func loop() {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("Recovered", r)
		}
	}()
	img := loadImage()
	colors := computeDominatorColors(img)
	log.Println(colors)

	sendToServer(colors)
}

func loadImage() *image.Image {
	file, err := os.Open("pic.jpg")
	if err != nil {
		log.Panic("No picture found", err)
	}
	defer file.Close()

	img, _, err := image.Decode(file)
	if err != nil {
		log.Panic(err)
	}
	bound := img.Bounds()
	rgbaImg := image.NewRGBA(bound)
	draw.Draw(rgbaImg, bound, img, bound.Min, draw.Src)

	var ret image.Image = rgbaImg
	return &ret
}

func computeDominatorColors(img *image.Image) [6]color.RGBA {
	log.Println("Computing dominant colors...")
	screen := *getScreen(img)

	/*

	   Dividing screen into 6 areas

	              A         B         A
	    ----- -----------------------------
	          |       |           |       |
	    50%   |   0   |     2     |   4   |
	          |       |           |       |
	    ----- -----------------------------
	          |       |           |       |
	    50%   |   1   |     3     |   5   |
	          |       |           |       |
	    ----- -----------------------------
	          |  20%  |    40%    |  20%  |

	*/
	var (
		areas  [6]image.Image
		colors [6]color.RGBA
	)

	bounds := screen.Bounds()

	x0 := float64(bounds.Dx() / 100)
	xA := int(math.Floor(x0 * 20))

	y := int(math.Floor(float64(bounds.Dy() / 2)))

	areaRect := image.Rect(bounds.Min.X, bounds.Min.Y, bounds.Min.X+xA, bounds.Min.Y+y)
	areas[0] = screen.(SubImager).SubImage(areaRect)

	areaRect = image.Rect(bounds.Min.X, bounds.Min.Y+y, bounds.Min.X+xA, bounds.Max.Y)
	areas[1] = screen.(SubImager).SubImage(areaRect)

	areaRect = image.Rect(bounds.Min.X+xA, bounds.Min.Y, bounds.Max.X-xA, bounds.Min.Y+y)
	areas[2] = screen.(SubImager).SubImage(areaRect)

	areaRect = image.Rect(bounds.Min.X+xA, bounds.Min.Y+y, bounds.Max.X-xA, bounds.Max.Y)
	areas[3] = screen.(SubImager).SubImage(areaRect)

	areaRect = image.Rect(bounds.Max.X-xA, bounds.Min.Y, bounds.Max.X, bounds.Min.Y+y)
	areas[4] = screen.(SubImager).SubImage(areaRect)

	areaRect = image.Rect(bounds.Max.X-xA, bounds.Min.Y+y, bounds.Max.X, bounds.Max.Y)
	areas[5] = screen.(SubImager).SubImage(areaRect)

	processed := make(chan color.RGBA, 6)

	for i := 0; i < len(areas); i++ {
		go processArea(areas[i], processed)
	}

	for i := 0; i < len(areas); i++ {
		log.Println("Processed", i)
		colors[i] = <-processed
	}

	return colors
}

func processArea(area image.Image, processed chan color.RGBA) {
	color := colorfinder.Find(area.(*image.RGBA))
	processed <- color
}

func getScreen(img *image.Image) *image.Image {
	return img
	// Full res is 2592 x 1944  e.g. 1 / 2592 * x
	// screenRect := image.Rect(1335, 747, 2184, 1231)
	// screen := (*img).(SubImager).SubImage(screenRect)
	// return &screen
}

func sendToServer(colors [6]color.RGBA) {
	conn, err := net.Dial("udp", "192.168.2.6:64001")
	if err != nil {
		fmt.Println(err)
		return
	}
	json, err := json.Marshal(colors)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Fprintf(conn, string(json))
	conn.Close()
}

type Cam struct {
	Cmd *exec.Cmd
}

func (c *Cam) Setup() {
	// Start raspistill in signal mode
	log.Println("Initializing raspistill process...")
	c.Cmd = exec.Command("raspistill", "-v", "-n", "-s", "-t", "0", "--thumb", "none", "-o", "pic.jpg", "-roi", "0.51,0.38,0.33,0.25", "-w", "648", "-h", "486", "-tl", "0", "-t", "0")

	err := c.Cmd.Start()
	if err != nil {
		log.Panic(err)
	}
	// Should wait for "Waiting for SIGUSR1" in the stdout - but was unable to get it running :(
	// So we just assume that nothing bad will happen when sending signals to it too early
	// Also, just in case, we wait a sec
	time.Sleep(1000 * time.Millisecond)
}

func (c *Cam) Snapshot() {
	log.Println("Triggering snapshot...")
	err := c.Cmd.Process.Signal(syscall.SIGUSR1)
	if err != nil {
		log.Panic(err)
	}
<commit_msg>Camera interfacing: correct roi and enable burst mode<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/RandomByte/colorfinder"
	"image"
	"image/color"
	"image/draw"
	_ "image/jpeg"
	"log"
	"math"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"syscall"
	"time"
)

type SubImager interface {
	SubImage(r image.Rectangle) image.Image
}

func main() {
	log.Println(runtime.GOMAXPROCS(8))

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt, os.Kill, syscall.SIGTERM)
	defer signal.Stop(sig)

	cam := Cam{}
	defer cam.Kill()

	cam.Setup()

	for {
		select {
		case <-time.After(1 * time.Millisecond):
			loop()
		case s := <-sig:
			log.Println("Got signal:", s)
			log.Println("Quitting...")
			return
		}
	}
}

func loop() {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("Recovered", r)
		}
	}()
	img := loadImage()
	colors := computeDominatorColors(img)
	log.Println(colors)

	sendToServer(colors)
}

func loadImage() *image.Image {
	file, err := os.Open("pic.jpg")
	if err != nil {
		log.Panic("No picture found", err)
	}
	defer file.Close()

	img, _, err := image.Decode(file)
	if err != nil {
		log.Panic(err)
	}
	bound := img.Bounds()
	rgbaImg := image.NewRGBA(bound)
	draw.Draw(rgbaImg, bound, img, bound.Min, draw.Src)

	var ret image.Image = rgbaImg
	return &ret
}

func computeDominatorColors(img *image.Image) [6]color.RGBA {
	log.Println("Computing dominant colors...")
	screen := *getScreen(img)

	/*

	   Dividing screen into 6 areas

	              A         B         A
	    ----- -----------------------------
	          |       |           |       |
	    50%   |   0   |     2     |   4   |
	          |       |           |       |
	    ----- -----------------------------
	          |       |           |       |
	    50%   |   1   |     3     |   5   |
	          |       |           |       |
	    ----- -----------------------------
	          |  20%  |    40%    |  20%  |

	*/
	var (
		areas  [6]image.Image
		colors [6]color.RGBA
	)

	bounds := screen.Bounds()

	x0 := float64(bounds.Dx() / 100)
	xA := int(math.Floor(x0 * 20))

	y := int(math.Floor(float64(bounds.Dy() / 2)))

	areaRect := image.Rect(bounds.Min.X, bounds.Min.Y, bounds.Min.X+xA, bounds.Min.Y+y)
	areas[0] = screen.(SubImager).SubImage(areaRect)

	areaRect = image.Rect(bounds.Min.X, bounds.Min.Y+y, bounds.Min.X+xA, bounds.Max.Y)
	areas[1] = screen.(SubImager).SubImage(areaRect)

	areaRect = image.Rect(bounds.Min.X+xA, bounds.Min.Y, bounds.Max.X-xA, bounds.Min.Y+y)
	areas[2] = screen.(SubImager).SubImage(areaRect)

	areaRect = image.Rect(bounds.Min.X+xA, bounds.Min.Y+y, bounds.Max.X-xA, bounds.Max.Y)
	areas[3] = screen.(SubImager).SubImage(areaRect)

	areaRect = image.Rect(bounds.Max.X-xA, bounds.Min.Y, bounds.Max.X, bounds.Min.Y+y)
	areas[4] = screen.(SubImager).SubImage(areaRect)

	areaRect = image.Rect(bounds.Max.X-xA, bounds.Min.Y+y, bounds.Max.X, bounds.Max.Y)
	areas[5] = screen.(SubImager).SubImage(areaRect)

	processed := make(chan color.RGBA, 6)

	for i := 0; i < len(areas); i++ {
		go processArea(areas[i], processed)
	}

	for i := 0; i < len(areas); i++ {
		log.Println("Processed", i)
		colors[i] = <-processed
	}

	return colors
}

func processArea(area image.Image, processed chan color.RGBA) {
	color := colorfinder.Find(area.(*image.RGBA))
	processed <- color
}

func getScreen(img *image.Image) *image.Image {
	return img
	// Full res is 2592 x 1944  e.g. 1 / 2592 * x
	// screenRect := image.Rect(1335, 747, 2184, 1231)
	// screen := (*img).(SubImager).SubImage(screenRect)
	// return &screen
}

func sendToServer(colors [6]color.RGBA) {
	conn, err := net.Dial("udp", "192.168.2.6:64001")
	if err != nil {
		fmt.Println(err)
		return
	}
	json, err := json.Marshal(colors)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Fprintf(conn, string(json))
	conn.Close()
}

type Cam struct {
	Cmd *exec.Cmd
}

func (c *Cam) Setup() {
	// Start raspistill in signal mode
	log.Println("Initializing raspistill process...")
	c.Cmd = exec.Command("raspistill", "-v", "-n", "-s", "-t", "0", "--thumb", "none", "-o", "pic.jpg", "-roi", "0.51,0.35,0.33,0.25", "-w", "648", "-h", "486", "-tl", "0", "-bm")

	err := c.Cmd.Start()
	if err != nil {
		log.Panic(err)
	}
	// Should wait for "Waiting for SIGUSR1" in the stdout - but was unable to get it running :(
	// So we just assume that nothing bad will happen when sending signals to it too early
	// Also, just in case, we wait a sec
	time.Sleep(1000 * time.Millisecond)
}

func (c *Cam) Snapshot() {
	log.Println("Triggering snapshot...")
	err := c.Cmd.Process.Signal(syscall.SIGUSR1)
	if err != nil {
		log.Panic(err)
	}

{'fraction_non_alphanumeric': 0.1960190393768931, 'fraction_numerical': 0.024340112505408913, 'mean_word_length': 2.570876786404017, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7162472', 'n_tokens_mistral': 3870, 'n_tokens_neox': 3587, 'n_words': 762}