I'm drawing a section of an image, however I'd like to apply rounded corners to it. I can't find any way of doing this.
In the draw() method:
img_section = img.get(gaze_x, gaze_y, gaze_size_x, gaze_size_y);
image(img_section, gaze_x, gaze_y);
You could copy the image and then manually set the corner pixels using the set() function.
You could just draw a rounded rectangle around the image- if the image will be placed on a background with a single color, just draw a rounded rectangle with the same color as the image.
Or you could come up with an image mask and draw that on top of your image.
package utils
import (
"ddkt365-poster/library/log"
"image"
"image/color"
"math"
)
// Settable Settable
type Settable interface {
Set(x, y int, c color.Color)
}
var empty = color.RGBA{255, 255, 255, 0}
// Convert Convert
func Convert(m *image.Image, rate float64) {
b := (*m).Bounds()
w, h := b.Dx(), b.Dy()
r := (float64(min(w, h)) / 2) * rate
log.Error("bounds:%v", r)
sm, ok := (*m).(Settable)
if !ok {
// Check if image is YCbCr format.
ym, ok := (*m).(*image.YCbCr)
if !ok {
log.Error("errInvalidFormat")
return
}
*m = yCbCrToRGBA(ym)
sm = (*m).(Settable)
}
// Parallelize?
for y := 0.0; y <= r; y++ {
l := math.Round(r - math.Sqrt(2*y*r-y*y))
for x := 0; x <= int(l); x++ {
sm.Set(x-1, int(y)-1, empty)
}
for x := 0; x <= int(l); x++ {
sm.Set(w-x, int(y)-1, empty)
}
for x := 0; x <= int(l); x++ {
sm.Set(x-1, h-int(y), empty)
}
for x := 0; x <= int(l); x++ {
sm.Set(w-x, h-int(y), empty)
}
}
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func yCbCrToRGBA(m image.Image) image.Image {
b := m.Bounds()
nm := image.NewRGBA(b)
for y := 0; y < b.Dy(); y++ {
for x := 0; x < b.Dx(); x++ {
nm.Set(x, y, m.At(x, y))
}
}
return nm
}
// Image with rounded corners (Go image/draw package)
if i.BorderRadius > 0 {
utils.Convert(&img, (float64(i.BorderRadius) / 100))
}
draw.Draw(canvs, img.Bounds().Add(image.Pt(i.X, i.Y)), img, image.ZP, draw.Over)
Related
I'm trying to implement a Gaussian Blur on golang image.Image objects. For the following image:
The output image generated is:
As one can see, the output image contains some unprocessed borders that corresponds to the current implementation decision to not process the edges, which leads me to think that I might have messed up on calculations somehow (what I mean is, this part of the implementation works, so I can discard off-by-one errors while iterating through image pixels). I've reviewed this code many times, but I can't find my mistake. I would really appreciate some help and considerations on the implementation, that could help me solve the problem. The code is contained below. If any edits or clarifications are necessary, please let me know!
package main
import (
"image"
"image/color"
"image/draw"
"image/jpeg"
"math"
"os"
)
func main() {
f, err := os.Open("dog.jpeg")
if err != nil {
panic(err)
}
img, err := jpeg.Decode(f)
if err != nil {
panic(err)
}
newImg := gaussianBlur(img, 3)
out, err := os.Create("dog-blurred.jpeg")
if err != nil {
panic(err)
}
err = jpeg.Encode(out, newImg, nil)
if err != nil {
panic(err)
}
}
func applyGaussianFunction(x, y, stdDev float64) float64 {
// eFactor := 1 / (2 * math.Pi * stdDev*stdDev);
ePowNominator := -(x*x + y*y);
ePowDenominator := 2 * stdDev*stdDev;
return math.Pow(math.E, (ePowNominator/ePowDenominator));
}
func generateKernel(radius int) [][]float64 {
size := 1 + (radius * 2);
kernel := make([][]float64, size);
stdDev := math.Max(float64(radius / 2), 1);
sum := float64(0);
for i := 0; i < size; i++ {
kernel[i] = make([]float64, size);
}
for i := -radius; i < radius + 1; i++ {
for j := -radius; j < radius + 1; j++ {
val := applyGaussianFunction(float64(j), float64(i), stdDev);
kernel[i + radius][j + radius] = val;
sum += val;
}
}
for i := 0; i < size; i++ {
for j := 0; j < size; j++ {
kernel[i][j] /= sum;
}
}
return kernel;
}
func makeImageRGBA(src image.Image) *image.RGBA {
b := src.Bounds().Size();
rgba := image.NewRGBA(image.Rect(0, 0, b.X, b.Y));
draw.Draw(rgba, rgba.Bounds(), src, image.Pt(0, 0), draw.Src);
return rgba;
}
func gaussianBlur(img image.Image, radius int) image.Image {
size := img.Bounds().Size();
rgbaImg := image.NewRGBA(image.Rect(0, 0, size.X, size.Y));
kernel := generateKernel(radius);
for y := radius; y < size.Y - radius; y++ {
for x := radius; x < size.X - radius; x++ {
var nr, ng, nb, na float64 = 0, 0, 0, 0;
for i := -radius; i < radius + 1; i++ {
for j := -radius; j < radius + 1; j++ {
// NEW: Get pixels from original Image
pr, pg, pb, pa := img.At(x - j, y - i).RGBA();
nr += float64(pr) * kernel[i + radius][j + radius];
ng += float64(pg) * kernel[i + radius][j + radius];
nb += float64(pb) * kernel[i + radius][j + radius];
na += float64(pa) * kernel[i + radius][j + radius];
}
}
// Handle overflow by using 64-bit alphapremultiplied values
rgbaImg.Set(x, y, color.RGBA64{uint16(nr), uint16(ng), uint16(nb), uint16(na)});
}
}
return rgbaImg;
}
EDITS
I modified the code so that pixels are read from the original image, not from rgbaImg
I've also commented eFactor from the applyGaussianFunction function, since I'm already normalizing the kernel with the sum variable
Modified .Set method to use 64-bit RGBA struct
This is the newly generated image
Those black borders are easy to solve, I'm already working them out. This is not a part of the problem anymore.
You're reading from the same image that you're writing to. You shall read from the original image instead:
pr, pg, pb, pa := img.At(x+j, y+i).RGBA()
EDIT:
Additionally, Image.At returns color.RGBA, and func (color.RGBA) RGBA returns colors in the 0 to 0xFFFF range. However color.RGBA constructor expects them to be in 0 to 255 range. You may want to use color.RGBA64 when writing the result:
rgbaImg.Set(x, y, color.RGBA64{uint16(nr), uint16(ng), uint16(nb), uint16(na)});
Am looking to do custom cropping on a set of images, Instead of cropping normally, using height and width i want the flexibility of getting an output image that is cropped like a polygon or an hexagon for example, Am using the library github.com/fogleman/gg, and the built in module "image", and github.com/disintegration/imaging, but I didn't find a way to customize the cropping, i also looked for an online SaaS to do this, like imgix or imageresizer.io, but they don't seem to offer that, i know golang is the right language for this maybe i didn't look hard enough, please Help
my sample Code looks like:
var image image.Image
dc := NewContext(1000, 1000)
image = imaging.Fill(profile, 800, 750, imaging.Center, imaging.Lanczos)
// Cropping needs to happen here
dc.DrawImage(image, 123, 250)
A bit longer than expected but here you have PNG image cropping with transparent background to a rectangle. You can modify the code for different shapes by changing the getPixAlpha function.
Just add the package name and it should include the imports, then add an image test.png and it should create a test-output.png
Note: You may want to make some minor modifications for using it as a service.
type Pixel struct {
R int
G int
B int
A int
}
func LogPanic(err error, msg string) {
if err != nil {
log.Printf("ERROR: %v %s", err, msg)
panic(err)
}
}
func getPixAlpha(x, y, halfWidth int) int {
if x < halfWidth-y || x > halfWidth+y {
return 0
}
if y > halfWidth+x {
return 0
}
if x > halfWidth*3-y && y > halfWidth*3-x {
return 0
}
return int(255)
}
func getPixels(file io.Reader) ([][]Pixel, error) {
img, _, err := image.Decode(file)
LogPanic(err, "error reading image")
bounds := img.Bounds()
width, height := bounds.Max.X, bounds.Max.Y
var pixels [][]Pixel
for x := 0; x < width; x++ {
var row []Pixel
for y := 0; y < height; y++ {
row = append(row, rgbaToPixel(img.At(x, y).RGBA()))
}
pixels = append(pixels, row)
}
return pixels, nil
}
func rgbaToPixel(r uint32, g uint32, b uint32, a uint32) Pixel {
return Pixel{int(r / 257), int(g / 257), int(b / 257), int(a / 257)}
}
func getRgbaPic(pixels [][]Pixel) [][]Pixel {
dx := len(pixels)
dy := len(pixels[0])
for x := 0; x < dx; x++ {
for y := 0; y < dy; y++ {
pixels[x][y].A = getPixAlpha(x, y, len(pixels)/2)
}
}
return pixels
}
func main() {
file, err := os.Open("./test.png")
LogPanic(err, "Error opening file")
defer file.Close()
pixels, err := getPixels(file)
LogPanic(err, "Error reading image")
pixels = getRgbaPic(pixels)
img := image.NewRGBA(image.Rect(0, 0, len(pixels), len(pixels[0])))
for x := 0; x < len(pixels); x++ {
for y := 0; y < len(pixels[0]); y++ {
img.Set(x, y, color.RGBA{
uint8(pixels[x][y].R),
uint8(pixels[x][y].G),
uint8(pixels[x][y].B),
uint8(pixels[x][y].A),
})
}
}
buf := &bytes.Buffer{}
err = png.Encode(buf, img)
LogPanic(err, "Error encoding")
err = ioutil.WriteFile("test-output.png", buf.Bytes(), 0666)
LogPanic(err, "Error writing file")
}
I have a very big rectangle (100,000 x 100,000) and i am trying to position a lot of circles with different sizes randomly on it. My current solution is to store all previously used coordinate pairs in a map and then randomly generate a new pair and check if it exists in the map.
func randomCoords(xCoordinateMap map[int]bool, yCoordinateMap map[int]bool, radius int) (int, int) {
x := rand.Intn((width-radius)-radius) + radius
y := rand.Intn((height-radius)-radius) + radius
for xCoordinateMap[x] && yCoordinateMap[y] {
x = rand.Intn((width-radius)-radius) + radius
y = rand.Intn((height-radius)-radius) + radius
}
xCoordinateMap[x] = true
yCoordinateMap[y] = true
return x, y
}
Because i'm generating a lot of coordinates, this method can get a little slow. Is there a better and most importantly faster way of getting random coordinates on a rectangle and maybe also a way to get them without the circles overlapping?
Figuring out circle overlap without storing the coordinates of previously added circles is quite tricky. The good thing is that after you've added a circle, it will cover an area with the given radius. Without using more targeted algorithms and continuing to rely on randomness you'll have check against the circles that you have and determine whether they overlap or not, that is done through basic Geometry formulas such as distance between centers, here's an example it's not heavily optimized but it should give you a starting point it does not check whether the circle's center + radius are within bounds of the canvas, it includes code to draw the result into an output file, in the example I'm using a small canvas but it could be adjusted to your rectangle size, the code should produce an image like this:
NOTE: The code was not written in an optimized way, there are many things that could be improved, for example using pointers instead of structs or removing looping when drawing or a better algorithm instead of using randomness to generate the X, Y and Radius for each circle.
package main
import (
"fmt"
"image"
"image/color"
"image/png"
"math"
"math/rand"
"os"
)
const (
width int = 100
height int = 200
)
type Circle struct {
Center image.Point
Radius int
}
func main() {
circles := map[Circle]bool{}
bounds := image.Rectangle{image.Point{0, 0}, image.Point{width, height}}
for i := 0; i < 20; i++ {
c := randomCircle(bounds)
if overlaped(c, circles) {
continue
}
circles[c] = true
}
fmt.Println(circles)
file, err := os.Create("out.png")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
draw(width, height, circles, file)
file.Close()
}
// Determines if the circle overlaps with any in the given
// circles collection.
func overlaped(c Circle, circles map[Circle]bool) bool {
for circle := range circles {
if overlap(circle, c) {
return true
}
}
return false
}
// Create a random circle within the
func randomCircle(rect image.Rectangle) Circle {
radius := randomRadius(rect.Max.X, rect.Max.Y) - 1
x := randDim(width-radius, 0)
y := randDim(height-radius, 0)
return Circle{
Center: image.Point{X: x, Y: y},
Radius: radius,
}
}
func randomRadius(width, height int) int {
if width < height {
return rand.Intn(width / 2)
} else {
return rand.Intn(height / 2)
}
}
func randDim(max, min int) int {
return rand.Intn(max) + min
}
func distance(a, b image.Point) int {
return int(math.Sqrt(math.Pow(float64(b.X-a.X), 2) + math.Pow(float64(b.Y-a.Y), 2)))
}
func overlap(a, b Circle) bool {
return distance(a.Center, b.Center) < a.Radius+b.Radius
}
// Utility function to draw into a file object
func draw(width, height int, circles map[Circle]bool, file *os.File) error {
img := image.NewRGBA(image.Rect(0, 0, width, height))
// Looping is probably very inefficient, but I'm not that familiar with the draw package
for circle := range circles {
for a := 0; a < 360; a++ {
var rads float64 = float64(a) * 0.017453
x := float64(circle.Center.X) + float64(circle.Radius)*math.Cos(rads)
y := float64(circle.Center.Y) + float64(circle.Radius)*math.Sin(rads)
img.Set(int(x), int(y), color.RGBA{R: 255, G: 0, B: 0, A: 255})
}
}
for x := 0; x < width; x++ {
img.Set(int(x), 0, color.RGBA{R: 0, G: 0, B: 255, A: 255})
img.Set(int(x), height-1, color.RGBA{R: 0, G: 0, B: 255, A: 255})
}
for y := 0; y < height; y++ {
img.Set(width-1, y, color.RGBA{R: 0, G: 0, B: 255, A: 255})
img.Set(0, y, color.RGBA{R: 0, G: 0, B: 255, A: 255})
}
return png.Encode(file, img)
}
I'm looking to convert my array to a PNG image. It is currently an RGB8 encoded image. I can do so using the following code:
s2 := make([]uint8, 2048*2448*3)
err = dset.Read(&s2)
if err != nil {
panic(err)
}
var (
width = 2048
height = 2448
rgb = 3
)
to1D := func(x, y int) int {
return (x * height * rgb) + (rgb * y)
}
img := image.NewRGBA(image.Rect(0, 0, width, height))
for ix := 0; ix < width; ix++ {
for iy := 0; iy < height; iy++ {
cords := to1D(ix, iy)
img.SetRGBA(ix, iy, color.RGBA{R: s2[cords], G: s2[cords+1], B: s2[cords+2], A: 255})
}
}
Is there a better way to add an alpha channel that doesn't involve looping through each pixel and setting it individually?
Thank you!
I am trying to return the pixels that have changed and their color. The following func works fine, but it does not give me the 255,255,255 value i require. Is it possible to convert it to the format required?
I already looked at the documentation here -> https://golang.org/pkg/image/color/
I also tried different conversions manually, but i cannot get it to work. Does someone know how to convert this in golang?
type Pixel struct {
x, y int
r, g, b, a uint32
}
func diffImages(imgOne *image.RGBA, imgTwo *image.RGBA) []Pixel {
var pixels []Pixel
bounds := imgOne.Bounds()
diff := false
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
r, g, b, a := imgOne.At(x, y).RGBA()
rt, gt, bt, at := imgTwo.At(x, y).RGBA()
if r != rt || g != gt || b != bt || a != at {
diff=true
}
if diff == true {
pixel := new(Pixel)
pixel.x = x
pixel.y = y
pixel.r = rt
pixel.g = gt
pixel.b = bt
pixel.a = at
pixels = append(pixels, *pixel)
}
diff = false
}
}
return pixels
}
If there is another better or faster way to get the required output than i am willing to accept.
Note: I am new to go.
Do you mean this? I did other refactors, your code seemed needlessly complex.
I haven't tested this, didn't test images.
// Pixels are pixels.
type Pixel struct {
x, y int
color color.NRGBA
}
func diffImages(imgOne image.RGBA, imgTwo image.RGBA) []Pixel {
var pixels []Pixel
bounds := imgOne.Bounds()
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
if !reflect.DeepEqual(imgOne.Pix, imgTwo.Pix) {
rt, gt, bt, at := imgTwo.At(x, y).RGBA()
pixel := new(Pixel)
pixel.x = x
pixel.y = y
pixel.color.R = uint8(rt)
pixel.color.G = uint8(gt)
pixel.color.B = uint8(bt)
pixel.color.A = uint8(at)
pixels = append(pixels, *pixel)
}
}
}
return pixels
}