并行Golang中的RGBA到灰度

时间:2017-03-02 18:31:23

标签: image go parallel-processing image-manipulation

我编写了一个程序,可以将RGBA图像依次转换为灰度图像。我现在正试图将其转换为并行运行。

我有点理解我需要这样做,但我很难开始。

这是我到目前为止所拥有的。

   package main

import (
"image"
"image/color"
"image/jpeg"
"log"
"os"
)

var lum float64


type ImageSet interface {
Set(x, y int, c color.Color)
}

func rgbtogray(r uint32, g uint32, b uint32)  float64{
    lum = 0.299*float64(r) + 0.587*float64(g) + 0.114*float64(b)
    return lum
}


func main() {
file, err := os.Open("flower.jpg")
if err != nil {
    log.Fatal(err)
}
defer file.Close()

img, err := jpeg.Decode(file)
if err != nil {
    log.Fatal(os.Stderr, "%s: %v\n", "flower.jpg", err)
}

channel1 := make(chan float64)
channel2 := make(chan float64)


b := img.Bounds()
imgSet := image.NewRGBA(b)

halfImage := b.Max.X/2
fullImage := b.Max.X

for y := 0; y < b.Max.Y; y++ {
      go func() {
        for x := 0; x < halfImage; x++ {
          oldPixel := img.At(x, y)
          r, g, b, _ := oldPixel.RGBA()
        channel1 <- rgbtogray(r, g, b)
        pixel := color.Gray{uint8(lum / 256)}
        imgSet.Set(x, y, pixel)
      }
      }()

      go func() {
        for x := halfImage; x< fullImage; x++ {
          oldPixel := img.At(x, y)
          r, g, b, _ := oldPixel.RGBA()
        channel2 <- rgbtogray(r, g, b)
        pixel := color.Gray{uint8(lum / 256)}
        imgSet.Set(x, y, pixel)
      }
      }()


}

    outFile, err := os.Create("changed.jpg")
    if err != nil {
      log.Fatal(err)
    }
    defer outFile.Close()
    jpeg.Encode(outFile, imgSet, nil)

}

这会运行但只会返回黑色图像。我知道我这样做的方式是错的,但我不是100%我需要走的路线。

我的想法是将图像分割到中间,让一个通道在左边的像素上工作,一个通道在右边的像素上工作。在向下移动到下一个y坐标之前等等。

我已经尝试将go函数中的所有代码移动到我的rgbatogray函数中但是我遇到了多个错误与传递变量等有关。最好是创建另一个处理拆分等的函数因为我认为我调用我的go函数应该看起来像:

go func() {
      channel1 <- rgbtogray(r, g, b)
}()
go func() {
      channel2 <- rgbtogray(r, g, b)
}()

我不确定接下来我应该采取什么步骤,所以任何提示和帮助都会非常感激。

2 个答案:

答案 0 :(得分:2)

以下是@ JimB在评论中提出的建议。它利用YCbCr中JPEG图像的事实来处理图像设置,使用一个goroutine为每个图像设置Cb和Cr组件为128.

func set(wg *sync.WaitGroup, a []uint8, v uint8) {
    for i := 0; i < len(a); i++ {
        a[i] = v
    }
    wg.Done()
}

func gray(i *image.YCbCr) {
    var wg sync.WaitGroup
    wg.Add(2)
    go set(&wg, i.Cb, 128)
    go set(&wg, i.Cr, 128)
    wg.Wait()
}

func main() {
    i, err := jpeg.Decode(os.Stdin)
    if err != nil {
        log.Fatalf("decoding image: %v", err)
    }
    gray(i.(*image.YCbCr))
    err = jpeg.Encode(os.Stdout, i, nil)
    if err != nil {
        log.Fatalf("encoding image: %v", err)
    }
}

结果很简单。

当然可以扩展为创建更多goroutine(可能每个可用核心一个)分配Cb&amp;的切片。每个Cr阵列都要进行处理。

答案 1 :(得分:0)

如何创建从图像读取的像素管道,转换为灰色并最终设置为新图像,其中所有步骤同时运行并且每个步骤可以在内部并行化?

然后Go的运行时将使用所有可用内核并行化任务。

此实施有效:

package main

import (
    "image"
    "image/color"
    "image/jpeg"
    "log"
    "os"
    "sync"
)

type Setter interface {
    Set(x, y int, c color.Color)
}

type Pixel struct {
    X, Y int
    C    color.Color
}

func sendPixels(in image.Image, out chan Pixel) {
    b := in.Bounds()
    for x := 0; x < b.Max.X; x++ {
        for y := 0; y < b.Max.Y; y++ {
            out <- Pixel{x, y, in.At(x, y)}
        }
    }
    close(out)
}

func convertToGray(in chan Pixel, out chan Pixel) {
    var wg sync.WaitGroup
    for p := range in {
        wg.Add(1)
        go func(p Pixel) {
            r, g, b, _ := p.C.RGBA()
            l := 0.299*float64(r) + 0.587*float64(g) + 0.114*float64(b)
            out <- Pixel{p.X, p.Y, color.Gray{uint8(l / 256)}}
            wg.Done()
        }(p)
    }
    wg.Wait()
    close(out)
}

func buildImage(in chan Pixel, out Setter, done chan int) {
    for p := range in {
        out.Set(p.X, p.Y, p.C)
    }
    close(done)
}

func main() {
    i, err := jpeg.Decode(os.Stdin)
    if err != nil {
        log.Fatalf("decoding image: %v", err)
    }

    a := make(chan Pixel, 1000)
    go sendPixels(i, a)

    b := make(chan Pixel, 1000)
    go convertToGray(a, b)

    c := image.NewRGBA(i.Bounds())
    d := make(chan int)
    go buildImage(b, c, d)

    <-d

    err = jpeg.Encode(os.Stdout, c, nil)
    if err != nil {
        log.Fatalf("encoding image: %v", err)
    }
}

哪个可以运行测试:

go run main.go <in.jpg >out.jpg