Stuck with Go concurrency - go

I can't seem to figure out what to do next. My goal is to create an array of all the sub images from the original image using the SubImage function from the image package. I am able to partition an image in the imageSplit() function and pass to imageReceiver() function via a channel.
I actually receive the data in function imageReceiver(), but I don't know how to append to an array and use it after receiving all the images from imageSplit() function.
// Partitions Image
func Partition(src image.Image) []image.Image {
newImg := image.NewNRGBA64(src.Bounds())
r := newImg.Rect
dx, dy := r.Dx(), r.Dy()
// partitionNum
pNum := 3
// partition x
px, py := (dx / pNum), (dy / pNum)
imgChan := make(chan image.Image)
imgStorage := make([]image.Image, 0)
for i := 1; i < pNum; i++ {
for j := 1; j < pNum; j++ {
startX, startY := ((px * i) - px), ((py * j) - py)
endX, endY := (px * i), (py * j)
go imageSplit(imgChan, newImg, startX, startY, endX, endY)
go imageReceiver(imgChan)
}
}
return imgStorage
}
// Creates sub-images of img
func imageSplit(imgChan chan image.Image, img *image.NRGBA64, startX, startY, endX, endY int) {
r := image.Rect(startX, startY, endX, endY)
subImg := img.SubImage(r)
imgChan <- subImg
}
// Receive sub-image from channel
func imageReceiver(imgChan chan image.Image) {
img := <-imgChan
spew.Dump(img.Bounds())
}
I thought of creating a global array of image.Image but I'm unsure if this is the correct way to "save" all the sub images.
I guess the reason this is a bit confusing is because this is the first time I'm working with concurrency in Go.
Thanks for any help :)

There are a few options for how you can do this but I would say your basic problem is that your receiver doesn't do aggregation and if you changed it so it did it would not be thread safe.
The simple choice to modify your receiver to do aggregation would be to allocate an Image array before the loop and pass a pointer to it into the receiver method which would then just use append when it reads of the channel. But then you would have a bunch of different goroutines fighting for access to the same array. So really, you don't want the aggregation to be multithreaded. If it is you need a locking mechanism in order to write to the collection.
Instead you want to block after the loop. The simplest way to do that would just be to put the body of your receiver right there inline after the loop like;
imgs := []image.Image{}
img := <-imgChan
imgs = append(imgs, img)
spew.Dump(img.Bounds())
The problem is in the real world then your software would block on that line and be unresponsive (have no way of dying or exiting or anything) so instead you'd typically use a channel select where you have at least 2 channels/cases, an abort channel that the caller of Partition can use to kill it if it needs to exit and the case that receives from imgChan. That would look a little more like this;
imgs := []image.Image{}
select {
case img := <-imgChan
imgs = append(imgs, img)
spew.Dump(img.Bounds())
case _ := <-abortChan:
return MyCustomError();
}
Which make it so your aggregation is not concurrent, only the work to produce the results which I personally think is the better design. I could explain how to lock in your receiver method as well but I'm sure you can find plenty of examples of mutex's ect.

Related

How can i draw the spring motion in the gif file in golang?

Gif file that i have to make
This gif file is what i have to make.
I draw a mass circle like this
func (s *SpSim) circleXY(l, i int) [2]int {
r := s.Ginfo.CR
xi := int(float64(r) * math.Cos(2*math.Pi*float64(i)/100))
xi += s.Ginfo.Pad + s.Ginfo.SprWidth/2
yi := int(float64(r) * math.Sin(2*math.Pi*float64(i)/100))
yi += l
return [2]int{xi, yi}
}
but I can't think how to draw the spring part for the gif file.
How can I make a spring attached to the ceiling and the mass?
I'm trying to make a function that draws the spring like this
func (s *SpSim) addSpring(c *image.Paletted, count int) {
}
but I can't fill the function TT

Getting all pixel values(rgba)

I'm new at Go and trying to improve my skills. Currently I'm working with images and I need to have all pixels' red value of an image. I know I can use the code below to achieve this but it seemed slow to me(~485 msecs),
pixList := make([]uint8, width*height)
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
r, _, _, _ := img.At(x, y).RGBA()
var rNew uint8 = uint8(float32(r)*(255.0/65535.0))
pixList[(x*height)+y] = rNew
}
}
Is there any faster way to do this? Any built-in functions to get all pixel values at once?
Edit: I'm now using the Pix to get all pixel data but still my Pix list is not giving what I'm looking for.
new code:
pixList := img.(*image.Paletted).Pix
newPixList := make([]uint8, width*height)
fmt.Println(len(pixList))//gives width*height, shouldn't it be width*height*4?
for index := 0; index < width*height; index++ {
newPixList[index] = pixList[index*4]//this part gives index out of range error, because the pixList is length of width*height, i dunno why
}
I think it's not behaving my image as it's an rgba image, maybe a conversion could work. Any ideas?
Thanks.
You can't make this pattern performant, because this requires an interface method call for every pixel. For fast access to the image data, you access the image's data directly. Take the image.RGBA type for example:
type RGBA struct {
// Pix holds the image's pixels, in R, G, B, A order. The pixel at
// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
Pix []uint8
// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
Stride int
// Rect is the image's bounds.
Rect Rectangle
}
The docs for each image type include the data layout and indexing formula. For this type you could extract all red pixels from the Pix slice with:
w, h := img.Rect.Dx(), img.Rect.Dy()
pixList := make([]uint8, w*h)
for i := 0; i < w*h; i++ {
pixList[i] = img.Pix[i*4]
}
If you need to convert other image types, you can use the existing methods to do the color conversion, but first assert the correct image type and use the native *At method to avoid the interface call. Extracting the approximate red values from a YCbCr image :
w, h := img.Rect.Dx(), img.Rect.Dy()
pixList := make([]uint8, w*h)
for x := 0; x < w; x++ {
for y := 0; y < h; y++ {
r, _, _, _ := img.YCbCrAt(x, y).RGBA()
pixList[(x*h)+y] = uint8(r >> 8)
}
}
return pixList
Similar to how the YCbCr image above has no "red" pixels (the value needs to be computed for each individual pixel), a paletted image has no individual RGBA values for the pixels, and needs to be looked up in the image's palette. You could take this one step further and predetermine the color model of the palette colors to remove the Color.RGBA() interface call to speed this up even more like so:
palette := make([]*color.RGBA, len(img.Palette))
for i, c := range img.Palette {
palette[i] = c.(*color.RGBA)
}
pixList := make([]uint8, len(img.Pix))
for i, p := range img.Pix {
pixList[i] = palette[p].R
}

Take FFT of an Image in Google Go

How do you take the FFT of an image in Google Go?
The Go DSP library (github.com/mjibson/go-dsp/fft) has a function for a 2D FFT with the following signature:
func FFT2Real(x [][]float64) [][]complex128
How do I convert an image from the standard go image types to float64? Is this the right approach?
Here is a link to the documentation.
You have two options, both involve copying the pixels. You can either use the methods provided by the Image interface, namely At(x,y) or you can assert the image to one of the image types provided by the image packet and access the Pix attribute directly.
Since you will most likely be using a Gray image, you could easily assert your image to type *image.Gray and access the pixels directly but for the sake of abstraction I did not in my example:
inImage, _, err := image.Decode(inFile)
// error checking
bounds := inImage.Bounds()
realPixels := make([][]float64, bounds.Dy())
for y := 0; y < bounds.Dy(); y++ {
realPixels[y] = make([]float64, bounds.Dx())
for x := 0; x < bounds.Dx(); x++ {
r, _, _, _ := inImage.At(x, y).RGBA()
realPixels[y][x] = float64(r)
}
}
This way you read all the pixels of your image inImage and store them as float64 values in a two-dimensional slice, ready to be processed by fft.FFT2Real:
// apply discrete fourier transform on realPixels.
coeffs := fft.FFT2Real(realPixels)
// use inverse fourier transform to transform fft
// values back to the original image.
coeffs = fft.IFFT2(coeffs)
// write everything to a new image
outImage := image.NewGray(bounds)
for y := 0; y < bounds.Dy(); y++ {
for x := 0; x < bounds.Dx(); x++ {
px := uint8(cmplx.Abs(coeffs[y][x]))
outImage.SetGray(x, y, color.Gray{px})
}
}
err = png.Encode(outFile, outImage)
In the code above I applied FFT on the pixels stored in realPixels and then, to see whether it worked, used inverse FFT on the result. The expected result is the original image.
A full example can be found here.

Modifying a gif image in go...not setting transparency correctly

I have some code which performs the following logical operations:
Read in and decode a gif image to a *GIF using gif.DecodeAll
Modify some pixels in each frame of the *GIF using image.Set
Write out the resulting modified image using gif.EncodeAll
Here's some code snippets to help demonstrate what the code is doing (error handling, file closing, etc removed for brevity):
f, err := os.Open(filename)
reader := bufio.NewReader(f)
g, err := gif.DecodeAll(reader)
err = modify_image(g)
of, err := os.Create("out.gif")
writer := bufio.NewWriter(of)
err = gif.EncodeAll(writer, g)
Here's the modify_image function:
func modify_image(img *gif.GIF) error {
for i := 0; i < len(img.Image); i++ {
err := modify_frame(img.Image[i])
}
return nil
}
And modify_frame:
func modify_frame(frame *image.Paletted) error {
xmin := frame.Rect.Min.X
ymin := frame.Rect.Min.Y
xmax := frame.Rect.Max.X
ymax := frame.Rect.Max.Y
for y := ymin; y < ymax; y++ {
for x := xmin; x < xmax; x++ {
if should_turn_pixel_transparent(frame, x, y) {
frame.Set(x, y, color.RGBA64{0, 0, 0, 0})
}
}
}
return nil
}
The out.gif that this code produces has the correct pixels turned transparent, but as the animation proceeds, the pixels which I turned transparent are not "clearing"; i.e. as these transparent pixels are written over non-transparent pixels, the non-transparent pixels underneath are still displayed.
My (brief) understanding is that there are two different methods for representing transparency in gifs. I don't know if I need to use index transparency versus alpha transparency, or if I'm just doing things entirely wrong. Any advice would be appreciated.
This is often omitted or not covered in various golang tutorials for generating gifs, but along with setting the delay Delay slice for each frame in the Image slice, it is also optional to set Disposal for each frame of the gif. DisposalNone is used of the slice does not have a member corresponding to the current frame index.
Disposal options are:
const (
DisposalNone = 0x01 // dont dispose of previous frames
DisposalBackground = 0x02 // dispose of specific colour in previous frames defined by GIF.BackgroundIndex
DisposalPrevious = 0x03 // dispose of the previous frame
)
The following is the resulting gif for each type of disposal.
DisposalNone:
DisposalBackground:
DisposalPrevious:

code block in goroutine produces strange wrong results

i have a big N*1 name array
i am currently using goroutine to calculate the edit distance of a name among each other
the question is the results at [B] [C] are different, maybe like
ABC BCD 7
ABC BCD 3
there are 20000 records in names
var names []string
divide names into two chunks
nameCount := len(names)
procs := 2
chunkSize := nameCount / procs
channel
ch := make(chan int)
var wg sync.WaitGroup
for i := 0; i < procs; i++ { //create two goroutines
start := i * chunkSize
end := (i+1)*chunkSize - 1
fmt.Println(start, end) //get slice start and end
wg.Add(1)
go func(slices []string, allnames []string) {
for _, slice := range slices {
minDistance = 256
distance := 0
sum := 0
for _, name := range allnames {
distance = calcEditDist(slice, name) //get the LD [A]
sum += 1
if distance > 0 && distance < minDistance {
minDistance = distance
fmt.Println(slice, name, distance) //[B]
fmt.Println(slice, name, calcEditDist(slice, name)) //[C]
} else if distance == minDistance {
fmt.Println(slice, name, distance)
fmt.Println(slice, name, calcEditDist(slice, name))
}
}
// for _, name := range allnames {
// fmt.Println(slice, name)
// }
ch <- sum
// fmt.Println(len(allnames), slice)
break
}
wg.Done()
}(names[start:end], names)
}
i placed the calcEditDist #https://github.com/copywrite/keyboardDistance/blob/master/parallel.go
PS:
if i declare
var dp [max][max]int
in calcEditDist as local variable instead of global, the results are right, but is incredibly slow
UPDATE 1
Thanks all buddy,i take the great advice below in three steps
1) i shrinked the dp to a much reasonable size, like 100 or even smaller, DONE
2) i put the dp declaration in each goroutine and pass its pointer as Nick said, DONE
3) later i will try to dynamically alloc dp, LATER
the performance improved steeply, ╰(°▽°)╯
As you've identified in your posting, having dp as a global variable is the problem.
Allocating it each time in CalcEditDistance is too slow.
You have two possible solutions.
1) you only need 1 dp array per go-routine, so allocate it in the for loop loop and pass a pointer to it (don't pass the array directly as arrays pass by value which will involve a lot of copying!)
for i := 0; i < procs; i++ { //create two goroutines
start := i * chunkSize
end := (i+1)*chunkSize - 1
fmt.Println(start, end) //get slice start and end
wg.Add(1)
go func(slices []string, allnames []string) {
var dp [max][max]int // allocate
for _, slice := range slices {
minDistance = 256
distance := 0
sum := 0
for _, name := range allnames {
distance = calcEditDist(slice, name, &dp) // pass dp pointer here
Change calcEditDist to take the dp
func CalcEditDist(A string, B string, dp *[max][max]int) int {
lenA := len(A)
lenB := len(B)
2) Re-write your calcEditDistance so it doesn't need the massive O(N^2) dp array.
If you study the function carefully it only ever accesses a row up and a column to the left, so all the storage you actually need is a previous row and a previous columns which you could allocate dynamically at very little cost. This would make it scale to any length of string too.
That would need a bit of careful thought though!

Resources