Drawing Circles with two radius in Golang - image

I've looked around but can't find anything useful for drawing circles in golang.
I'd like to draw a draw with 2 given (inner and outer) radius and color all pixels in between.
One possible method would be to iterate through each pixel and color it until the ring has been created. Although, that seems really inefficient.
Any help on this would be greatly appreciated! :)

Please read this related question: Draw a rectangle in Golang?
To sum it up: the standard Go library does not provide primitive drawing or painting capabilities.
So yes, either you have to use a 3rd party library to draw a circle (such as github.com/llgcode/draw2d), or you have to do it yourself. Don't worry, it's not hard at all.
Drawing a single circle
First pick a circle drawing algorithm which is simple and efficient. I recommend the Midpoint circle algorithm.
You will find the algorithm on the linked Wikipedia page. Note: you do not have to understand it if you want to use it.
But we do need to implement the algorithm in Go. Which is rather simple:
func drawCircle(img draw.Image, x0, y0, r int, c color.Color) {
x, y, dx, dy := r-1, 0, 1, 1
err := dx - (r * 2)
for x > y {
img.Set(x0+x, y0+y, c)
img.Set(x0+y, y0+x, c)
img.Set(x0-y, y0+x, c)
img.Set(x0-x, y0+y, c)
img.Set(x0-x, y0-y, c)
img.Set(x0-y, y0-x, c)
img.Set(x0+y, y0-x, c)
img.Set(x0+x, y0-y, c)
if err <= 0 {
y++
err += dy
dy += 2
}
if err > 0 {
x--
dx += 2
err += dx - (r * 2)
}
}
}
That's all it takes. Just pass a draw.Image you want to draw on, and the parameters of the circle you want to draw (center point, radius and the color).
Let's see it in action. Let's create an image, draw a circle on it, and save the image to a file. This is all it takes:
img := image.NewRGBA(image.Rect(0, 0, 100, 100))
drawCircle(img, 40, 40, 30, color.RGBA{255, 0, 0, 255})
buf := &bytes.Buffer{}
if err := png.Encode(buf, img); err != nil {
panic(err)
}
if err := ioutil.WriteFile("circle.png", buf.Bytes(), 0666); err != nil {
panic(err)
}
Note: you could also encode the image directly to an os.File and "skip" the in-memory buffer. This is just for demonstration, and to verify our implementation works.
Drawing a ring (filling space between 2 circles)
This one isn't that trivial if you want to implement it yourself, but using a 3rd party lib here could really come handy.
Although most of them don't contain ring-painting support, they do have circle drawing support, and you can set the width of the line used to draw the circle.
So, set the line width to the value that is the difference of the 2 radius of your circles. And draw a circle with a new radius that is the arithmetic center of the 2 original radius.
Here's the algorithm (this is not runnable code):
// Helper functions abstracting the library you choose:
func setColor(c color.Color) {}
func setLineWidth(width float64) {}
func drawCircle(r, x, y float64) {}
// fillRing draws a ring, where r1 and r2 are 2 concentric circles,
// the boundaries of the ring, (x, y) being the center point.
func fillRing(r1, r2, x, y float64, c color.color) {
// Set drawing color:
setColor(c)
// Set line width:
width := r2 - r1
if width < 0 {
width = -width
}
setLineWidth(width)
// And finally draw a circle which will be a ring:
r := (r2 + r1) / 2
drawCircle(r, x, y)
}

Related

Drop Shadow with Golang based on alpha

I need to drop shadow from an object of type image.Image which has got an alpha channel. The goal is not to have the rectangle shadowed, but the alpha.
What I wanted to do is:
take out the alpha channel
turn it into a black RGB image
expand to N pixels (N=the size of the blur)
apply a gaussian blur
apply it as a background
The last point is quite simple, thanks to the "image/draw" API (I have no problem to cut an image in circle, and apply the mask, for example).
Outputting the alpha channel seems simple, too (for each pixel, apply a 255*alpha multiplication on R, G, and B, or use a grayscale image, and finally invert the white color to black)
It's clearly the dilation and blurring that I have a problem with.
I have nothing against the fact that the image changes size for this operation (at worst I will reduce the original image before transformation)
The question is "how to dilate and blur the alpha channel" with Go on an image.Image?
OK, after a while, I finally made this.
I rebuild the alpha and devide it by 2 (this will be a paramters).
I'm using github.com/disintegration/imaging package to blur the alpha.
func DropShadow(img image.Image, size float64) image.Image {
bounds := img.Bounds()
sizeInt := int(math.Ceil(size)) * 4
final := imaging.New(bounds.Dx()+sizeInt, bounds.Dy()+sizeInt, color.Alpha{})
for x := 0; x < bounds.Dx(); x++ {
for y := 0; y < bounds.Dy(); y++ {
_, _, _, a := img.At(x, y).RGBA()
final.Set(x+sizeInt/2, y+sizeInt/2, color.RGBA{0x0, 0x0, 0x0, uint8(a / 2)})
}
}
final = imaging.Blur(final, size)
final = imaging.Overlay(final, img, image.Point{sizeInt / 2, sizeInt / 2}, 1)
return final
}
It's only a bit curious that I need to scale by 4 the image to not have the shadow sticking to the border. But it does the job...

Golang making RGBA images display weird colors

So I'm making some rgba images pixel by pixel following a certain pattern and saving them as png later on and noticed that when alpha channel es changed with certain colors it changes the whole pixel color when stored as png.
I made a test to show what is currently happening:
img := image.NewRGBA(image.Rect(0, 0, 250, 250))
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
f.Read(b)
img.SetRGBA(x, y, color.RGBA{
249,
214,
133,
255,
})
}
}
var buff bytes.Buffer
err := png.Encode(&buff, img)
if err != nil {
log.Println(err)
return
}
This will print an image of color #F9D685. But if I change alpha into 200 it will print another one with #6844BC and transparency instead of printing the original color with it's transparency.
Is there a way to solve this? I believe that it's because I'm missing something but can't really figure it out and didn't find anything similar to what's happening to me on google/here.
That one is simple:
go doc color.RGBA
package color // import "image/color"
type RGBA struct {
R, G, B, A uint8
}
RGBA represents a traditional 32-bit alpha-premultiplied color, having 8
bits for each of red, green, blue and alpha.
An alpha-premultiplied color component C has been scaled by alpha (A), so
has valid values 0 <= C <= A.
You might be looking for color.NRGBA.
(Always, really always, consult the documentation of the involved types and functions. Always.)

Go draw over image mask

I am trying to draw over an image using a template, the template image is the following
I want to colorize the image red, green, blue and yellow colors with custom colors and achieve something like this:
In order to achieve this I currently use this image as a base
And then draw over the template using draw.Draw(outfitImage, outfitImage.Bounds(), generatorImage, image.ZP, draw.Over)
This however gives a very weird result (nothing near the expected result), this is how I replace pixels
func paintPixels(img *image.NRGBA, base color.Color, dst color.Color) {
br, bg, bb, ba := base.RGBA()
dr, dg, db, _ := dst.RGBA()
for x := 0; x < img.Bounds().Dx(); x++ {
for y := 0; y < img.Bounds().Dy(); y++ {
r, g, b, a := img.At(x, y).RGBA()
if br == r && bg == g && bb == b && ba == a {
img.Set(x, y, color.RGBA{uint8(dr), uint8(dg), uint8(db), 255})
}
}
}
}
The result can vary depending on the alpha value I use when colorizing the image template. So I cant think of a way to achieve the expected result, I guess I should use a mask with draw.DrawMask but I have no clue where to start or how to achieve the result I am looking for
You look like you're just replacing pixels with the colour if all components match. If you look at the compositing methods in bild/blend you should find one that suits you for combining images - you probably want Opacity or Multiply modes and could extract code from this file:
https://github.com/anthonynsimon/bild/blob/master/blend/blend.go

How to get the geometry of a specific pixel in an image.RGBA or any other type?

I wish there was something like image.Point struct but instead it was pixel based, if that makes sense.
Say I have loaded and decoded an image.RGBA with size(bounds) of 300x300. How can I get the exact coordinate of the middle of the image in image.Point or fixed.Point26_6?
image.RGBA is a concrete implementation of the general image.Image interface.
It has an Image.Bounds() method:
// Bounds returns the domain for which At can return non-zero color.
// The bounds do not necessarily contain the point (0, 0).
Bounds() Rectangle
Important to note that the top-left corner of the image might not be at the zero point (0, 0) (although generally it is).
So the geometry of the image is handed to you as a value of image.Rectangle:
type Rectangle struct {
Min, Max Point
}
To handle the general case (where top-left might not be (0, 0)), you have to account both the Min and Max points to to calculate the center point:
cx := (r.Min.X + r.Max.X)/2
cy := (r.Min.Y + r.Max.Y)/2
Another solution is to use Rectangle.Dx() and Rectangle.Dy():
cx := r.Min.X + r.Dx()/2
cy := r.Min.Y + r.Dy()/2
And there is an image.Point struct type. To get the center point as a value of image.Point:
cp := image.Point{(r.Min.X + r.Max.X) / 2, (r.Min.Y + r.Max.Y) / 2}
Or:
cp := image.Point{r.Min.X + r.Dx()/2, r.Min.Y + r.Dy()/2}
See this example:
r := image.Rect(0, 0, 300, 100)
fmt.Println(r)
cp := image.Point{(r.Min.X + r.Max.X) / 2, (r.Min.Y + r.Max.Y) / 2}
fmt.Println(cp)
cp = image.Point{r.Min.X + r.Dx()/2, r.Min.Y + r.Dy()/2}
fmt.Println(cp)
Output (try it on the Go Playground):
(0,0)-(300,100)
(150,50)
(150,50)

Calculation error with area of shapes in GoLang [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 6 years ago.
I have this piece of code that is suppose to print the area of individual shapes and then print the total area (sum of the individual areas), but there seem to be a problem somewhere in the addition when I use interfaces and variadic functions. The program is written in GoLang and below is the code;
/* Program that interacts with shapes */
/* Calculating the area of basic shapes e.g Circle, Rectangle */
package main
import ("fmt"; "math")
/* Adding the interface support */
type Shape interface {
area() float64
}
/* Struct for Circle */
type Circle struct {
x, y, r float64
}
/* Struct for Rectangle */
type Rectangle struct {
x1, y1, x2, y2 float64
}
/* Calculation of distance */
func distance(x1, y1, x2, y2 float64) float64 {
a := x2 - x1
b := y2 - y1
return math.Sqrt(a*a + b*b)
}
/* Area of the rectangle */
func (r *Rectangle) area() float64 {
l := distance(r.x1, r.y1, r.x1, r.y2)
w := distance(r.x1, r.y1, r.x2, r.y1)
return l * w
}
/* Area of the circle */
func (c *Circle) area() float64 {
return math.Pi * c.r * c.r
}
/* Interface is really useful when finding the total area i.e. the sum of
all the areas of each of the shapes
*/
func totalArea(shapes ...Shape) float64 {
var area float64
for _, s := range shapes {
area += s.area()
}
return area
}
/* This is the main function */
func main() {
c := Circle{0, 0, 5}
r := Rectangle{0, 0, 10, 10}
fmt.Println("Area of the rectangle is: ", r.area())
fmt.Println("Area of the circle is: ", c.area())
fmt.Println("Sum of the areas: ", totalArea(&c, &r))
}
I ran this code on my Mac OS X El Capitan, core i5, 8GB RAM and below is my output
Area of the rectangle is: 100
Area of the circle is: 78.53981633974483
Sum of the areas: 178.53981633974485
From the results as you can see, there is a small issue, the expected sum of the areas should be: 178.53981633974483 but I get 178.53981633974485 which is 0.00000000000002 different or deviation from the expected results, please can anyone help me out with why it is like this?
I am not quite sure if its a problem with the math library in GoLang since it just has to do a normal addition of the two areas? Or is it that GoLang recalculates the area before passing it to totalArea() then does some approximation I don't quite get it? Or is it my computer (one can never tell)?
Thanks for your help in advance.
This is the behaviour of floating point arithmetic and its precision rather than anything specific to golang.
Theres a few good resources regarding float precision.
here is a snippet that illustrates your issue more simply:
https://play.golang.org/p/Jhlnt0L13T
If you do need arbitrary precision then you may want to look at:
https://golang.org/pkg/math/big/

Resources