From bab0631fcdb829350a76de965cf65f749de7cdd3 Mon Sep 17 00:00:00 2001 From: arnaucode Date: Wed, 28 Jun 2017 10:57:07 +0200 Subject: [PATCH] it works! --- .gitignore | 6 ++++ README.md | 8 +++++ color.go | 57 +++++++++++++++++++++++++++++++ config.json | 4 +++ errors.go | 9 +++++ imageOperations.go | 85 ++++++++++++++++++++++++++++++++++++++++++++++ knn.go | 30 ++++++++++++++++ main.go | 31 +++++++++++++++++ readConfig.go | 23 +++++++++++++ readDataset.go | 74 ++++++++++++++++++++++++++++++++++++++++ 10 files changed, 327 insertions(+) create mode 100644 .gitignore create mode 100644 color.go create mode 100644 config.json create mode 100644 errors.go create mode 100644 imageOperations.go create mode 100644 knn.go create mode 100644 main.go create mode 100644 readConfig.go create mode 100644 readDataset.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..81a4214 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +datasets +dataset +dataset_complet +*.jpg +*.jpeg +*.png diff --git a/README.md b/README.md index 56efa9c..32b3423 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,10 @@ # galdric machine learning server, for image classification + + + + - Reads all the datasets in the folder /dataset + - Each image is resized to the same size, configured in the config.json + - For the input images, calculates the euclidean distances + - Gets the nearest neighbour + - Show the result, that is the label of the object in the image diff --git a/color.go b/color.go new file mode 100644 index 0000000..e945ac5 --- /dev/null +++ b/color.go @@ -0,0 +1,57 @@ +package main + +import "fmt" + +//Color struct, defines the color +type Color struct{} + +var c Color + +//DarkGray color +func (c Color) DarkGray(t string) { + fmt.Print("\x1b[30;1m") //dark gray + fmt.Println(t) + fmt.Print("\x1b[0m") //defaultColor +} + +//Red color +func (c Color) Red(t string) { + fmt.Print("\x1b[31;1m") //red + fmt.Println(t) + fmt.Print("\x1b[0m") //defaultColor +} + +//Green color +func (c Color) Green(t string) { + fmt.Print("\x1b[32;1m") //green + fmt.Println(t) + fmt.Print("\x1b[0m") //defaultColor +} + +//Yellow color +func (c Color) Yellow(t string) { + fmt.Print("\x1b[33;1m") //yellow + fmt.Println(t) + fmt.Print("\x1b[0m") //defaultColor +} + +//Blue color +func (c Color) Blue(t string) { + fmt.Print("\x1b[34;1m") //blue + fmt.Println(t) + fmt.Print("\x1b[0m") //defaultColor +} + +//Purple color +func (c Color) Purple(t string) { + fmt.Print("\x1b[35;1m") //purple + fmt.Println(t) + fmt.Print("\x1b[0m") //defaultColor +} + +//Cyan color +func (c Color) Cyan(t string) { + fmt.Print("\x1b[36;1m") //cyan + fmt.Println(t) + fmt.Print("\x1b[0m") //defaultColor +} diff --git a/config.json b/config.json new file mode 100644 index 0000000..82c99c9 --- /dev/null +++ b/config.json @@ -0,0 +1,4 @@ +{ + "imgWidth": 300, + "imgHeigh": 300 +} diff --git a/errors.go b/errors.go new file mode 100644 index 0000000..9e83a92 --- /dev/null +++ b/errors.go @@ -0,0 +1,9 @@ +package main + +import "fmt" + +func check(err error) { + if err != nil { + fmt.Println(err) + } +} diff --git a/imageOperations.go b/imageOperations.go new file mode 100644 index 0000000..9793fd1 --- /dev/null +++ b/imageOperations.go @@ -0,0 +1,85 @@ +package main + +import ( + "bytes" + "image" + "image/jpeg" + "image/png" + + "github.com/nfnt/resize" +) + +type imgRGBA [][]float64 + +func dataToImage(data []byte, imageName string) (image.Image, error) { + //var histogram imgRGBA + reader := bytes.NewReader(data) + //var imageExtension = strings.Split(imageName, ".")[1] + var img image.Image + var err error + /*switch imageExtension { + case "png": + img, err = png.Decode(reader) + case "jpg": + img, err = jpeg.Decode(reader) + case "jpeg": + img, err = jpeg.Decode(reader) + default: + img = nil + } + */ + img, err = jpeg.Decode(reader) + if err != nil { + return img, err + } + return img, err +} + +func imageToData(img image.Image, imageName string) ([]byte, error) { + buf := new(bytes.Buffer) + //var imageExtension = strings.Split(imageName, ".")[1] + var err error + /*switch imageExtension { + case "png": + err = png.Encode(buf, img) + case "jpg": + err = jpeg.Encode(buf, img, nil) + case "jpeg": + err = jpeg.Encode(buf, img, nil) + default: + img = nil + }*/ + err = jpeg.Encode(buf, img, nil) + if err != nil { + return buf.Bytes(), err + } + return buf.Bytes(), err +} + +func imageToPNG(img image.Image) ([]byte, error) { + buf := new(bytes.Buffer) + var err error + err = png.Encode(buf, img) + return buf.Bytes(), err +} + +func imageToHistogram(img image.Image) [][]float64 { + bounds := img.Bounds() + + //generate the histogram + var histogram [][]float64 + for y := bounds.Min.Y; y < bounds.Max.Y; y++ { + for x := bounds.Min.X; x < bounds.Max.X; x++ { + r, g, b, a := img.At(x, y).RGBA() + var pixel []float64 + pixel = append(pixel, float64(r), float64(g), float64(b), float64(a)) + histogram = append(histogram, pixel) + } + } + return histogram +} + +func Resize(img image.Image) image.Image { + r := resize.Resize(uint(config.ImgWidth), uint(config.ImgHeigh), img, resize.Lanczos3) + return r +} diff --git a/knn.go b/knn.go new file mode 100644 index 0000000..c030dc6 --- /dev/null +++ b/knn.go @@ -0,0 +1,30 @@ +package main + +func euclideanDist(img1, img2 [][]float64) float64 { + var dist float64 + + for i := 0; i < len(img1); i++ { + for j := 0; j < len(img1[i]); j++ { + dist += (img1[i][j] - img2[i][j]) * (img1[i][j] - img2[i][j]) + } + } + + return dist +} + +func knn(dataset Dataset, input [][]float64) string { + d := euclideanDist(dataset["Leopards"][0], input) + label := "lamp" + for k, v := range dataset { + //fmt.Println(k) + for i := 0; i < len(v); i++ { + //fmt.Println(i) + dNew := euclideanDist(v[i], input) + if dNew < d { + d = dNew + label = k + } + } + } + return label +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..aa9ea85 --- /dev/null +++ b/main.go @@ -0,0 +1,31 @@ +package main + +import ( + "fmt" + "strconv" + "time" +) + +func main() { + readConfig("./config.json") + + c.Cyan("reading images datasets") + tStart := time.Now() + dataset := readDataset("./dataset") + fmt.Print("time spend reading images: ") + fmt.Println(time.Since(tStart)) + fmt.Println("total folders scanned: " + strconv.Itoa(len(dataset))) + + numImages := 0 + for _, v := range dataset { + numImages = numImages + len(v) + } + c.Cyan("total images in dataset: " + strconv.Itoa(numImages)) + + //we have the images in the dataset variable + //now, can take images + testFile := readImage("./test.jpg") + r := knn(dataset, testFile) + fmt.Println("seems to be a " + r) + +} diff --git a/readConfig.go b/readConfig.go new file mode 100644 index 0000000..d2d634b --- /dev/null +++ b/readConfig.go @@ -0,0 +1,23 @@ +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" +) + +type Config struct { + ImgWidth int `json:"imgWidth"` + ImgHeigh int `json:"imgHeigh"` +} + +var config Config + +func readConfig(path string) { + file, err := ioutil.ReadFile(path) + if err != nil { + fmt.Println("error: ", err) + } + content := string(file) + json.Unmarshal([]byte(content), &config) +} diff --git a/readDataset.go b/readDataset.go new file mode 100644 index 0000000..2fc2339 --- /dev/null +++ b/readDataset.go @@ -0,0 +1,74 @@ +package main + +import ( + "fmt" + "io/ioutil" + "strconv" +) + +//each image is [][]float64, is a array of pixels +type ImgDataset [][][]float64 + +type Dataset map[string]ImgDataset + +func byteArrayToFloat64Array(b []byte) []float64 { + var f []float64 + for i := 0; i < len(b); i++ { + val, _ := strconv.ParseFloat(string(b[i]), 64) + /*fmt.Print(string(b[i]) + "-") + fmt.Println(val)*/ + f = append(f, val) + } + return f +} + +func readImage(path string) [][]float64 { + //open image file + /*reader, err := os.Open(path) + check(err) + defer reader.Close()*/ + + dat, err := ioutil.ReadFile(path) + check(err) + + imageRaw, err := dataToImage(dat, path) + check(err) + + //resize the image to standard size + image := Resize(imageRaw) + + //convert the image to histogram(RGBA) + histogram := imageToHistogram(image) + //convert image to bytes + /*imgBytes, err := imageToData(image, path) + check(err)*/ + + //imgFloat := byteArrayToFloat64Array(imgBytes) + return histogram +} +func readDataset(path string) map[string]ImgDataset { + //dataset := make(map[string]ImgDataset) + dataset := make(Dataset) + + folders, _ := ioutil.ReadDir(path) + for _, folder := range folders { + fmt.Println(folder.Name()) + + var imgDataset ImgDataset + + folderFiles, _ := ioutil.ReadDir(path + "/" + folder.Name()) + for _, file := range folderFiles { + image := readImage(path + "/" + folder.Name() + "/" + file.Name()) + + imgDataset = append(imgDataset, image) + + /*fmt.Println(folder.Name()) + fmt.Println(file.Name())*/ + } + + //add the foldername to the Dataset map + dataset[folder.Name()] = imgDataset + } + + return dataset +}