commit 3836eb5f83441a04f8e2c89a02d12fc0996b42d9 Author: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Sat Dec 7 13:53:45 2024 +0100 feat: Add edge detection filter diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8920079 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +assets +image.png +.idea diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..41c5ef8 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module myzel394.app/image-stuff + +go 1.23.3 + +require gonum.org/v1/gonum v0.15.1 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..87a0b55 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +gonum.org/v1/gonum v0.15.1 h1:FNy7N6OUZVUaWG9pTiD+jlhdQ3lMP+/LcTpJ6+a8sQ0= +gonum.org/v1/gonum v0.15.1/go.mod h1:eZTZuRFrzu5pcyjN5wJhcIhnUdNijYxX1T2IcrOGY0o= diff --git a/image_analyzer.go b/image_analyzer.go new file mode 100644 index 0000000..05d3216 --- /dev/null +++ b/image_analyzer.go @@ -0,0 +1,110 @@ +package main + +import ( + "image" + "image/color" + "math" +) + +type ImageAnalyzer struct { + image.Image +} + +// Calculate the energy using the dual-gradient energy function +func getEnergy( + firstPixel color.Color, + secondPixel color.Color, +) float64 { + firstRed, firstGreen, firstBlue, _ := firstPixel.RGBA() + firstRed, firstGreen, firstBlue = firstRed >> 8, firstGreen >> 8, firstBlue >> 8 + secondRed, secondGreen, secondBlue, _ := secondPixel.RGBA() + secondRed, secondGreen, secondBlue = secondRed >> 8, secondGreen >> 8, secondBlue >> 8 + + return float64( + math.Abs(float64(firstRed - secondRed)) + + math.Abs(float64(firstGreen - secondGreen)) + + math.Abs(float64(firstBlue - secondBlue)), + ) +} + +// Calculate a 0-255 grayscale value from a color using the NTSC formula +func colorToGray(color color.Color) float64 { + red, green, blue, _ := color.RGBA() + red, green, blue = red >> 8, green >> 8, blue >> 8 + + return 0.299 * float64(red) + + 0.587 * float64(green) + + 0.114 * float64(blue) +} + +func sumSlice(slice []float64) float64 { + var sum float64 + for _, value := range slice { + sum += value + } + return sum +} + +func (image *ImageAnalyzer) CalculateEnergyAt(x int, y int) float64 { + northPixel := image.At( + x, + max(0, y - 1), + ) + northEastPixel := image.At( + min(image.Bounds().Max.X, x + 1), + max(0, y - 1), + ) + eastPixel := image.At( + min(image.Bounds().Max.X, x + 1), + y, + ) + southEastPixel := image.At( + min(image.Bounds().Max.X, x + 1), + min(image.Bounds().Max.Y, y + 1), + ) + southPixel := image.At( + x, + min(image.Bounds().Max.Y, y + 1), + ) + southWestPixel := image.At( + max(0, x - 1), + min(image.Bounds().Max.Y, y + 1), + ) + westPixel := image.At( + max(0, x - 1), + y, + ) + northWestPixel := image.At( + max(0, x - 1), + max(0, y - 1), + ) + + thisPixel := image.At( + x, + y, + ) + + _ = thisPixel + _ = northPixel + _ = northEastPixel + _ = southPixel + + horizontalMatrix := []float64{ + colorToGray(northWestPixel), 0, -colorToGray(northEastPixel), + 2 * colorToGray(westPixel), 0, -2 * colorToGray(eastPixel), + colorToGray(southWestPixel), 0, -colorToGray(southEastPixel), + } + verticalMatrix := []float64{ + colorToGray(northWestPixel), 2 * colorToGray(northPixel), colorToGray(northEastPixel), + 0, 0, 0, + -colorToGray(southWestPixel), -2 * colorToGray(southPixel), -colorToGray(southEastPixel), + } + + g_x := sumSlice(horizontalMatrix) + g_y := sumSlice(verticalMatrix) + + return math.Sqrt( + math.Pow(g_x, 2) + + math.Pow(g_y, 2), + ) +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..21f946a --- /dev/null +++ b/main.go @@ -0,0 +1,35 @@ +package main + +import ( + "image" + "image/color" + "image/png" + _ "image/png" + "os" +) + +func main() { + // Read image + reader, _ := os.Open("./assets/surfer.png") + rawImage, _, _ := image.Decode(reader) + readImage := ImageAnalyzer{Image: rawImage} + + bounds := readImage.Bounds() + width := bounds.Max.X + height := bounds.Max.Y + writeImage := image.NewRGBA(bounds) + + // Main action + for x := range width { + for y := range height { + energy := uint8(readImage.CalculateEnergyAt(x, y)) + + color := color.RGBA{energy, energy, energy, 255} + writeImage.Set(x, y, color) + } + } + + // Out image + writer, _ := os.Create("image.png") + png.Encode(writer, writeImage) +}