2013-02-01 21 views
5

PNGファイルを読み込んでもう一方のチャンネル(R、G、B)を可能な選択。Golang - 画像と画像/ PNGを使用している画像のPNGチャンネルを入れ替えよう

しかし、image.At(x、y)によって返されたcolor.Colorオブジェクトから整数を抽出する方法はわかりません。それを書き戻すことは、スワップされたチャンネルで新しいRGBAカラーを作成できるようになると、おそらくimage.Set(x、y、color)で簡単になります。ここで

私は(あなたはかなり最後のループにスキップすることができます)今の私:

package main 

import (
"flag" 
"fmt" 
//"image" 
"image/color" 
"image/png" 
"os" 
) 

type Choice struct { 
value string 
valid bool 
} 

func (c *Choice) validate() { 
goodchoices := []string{"R", "G", "B"} 
for _, v := range goodchoices { 
    if c.value == v { 
     c.valid = true 
    } 
} 
} 

func main() { 

var fname string 
var c1 Choice 
var c2 Choice 

flag.StringVar(&c1.value, "c1", "", "The color channel to swap - R or G or B ") 
flag.StringVar(&c2.value, "c2", "", "The color channel to swap with - R or G or B ") 
flag.StringVar(&fname, "f", "", "A .png image (normal map)") 
flag.Parse() 

c1.validate() 
c2.validate() 

if c1.valid == true && c2.valid == true { 
    fmt.Println("We could proceed..") 
    fmt.Println("Swapping channels:", c1.value, "<->", c2.value, "In", fname) //for testing 
} else { 
    fmt.Println("Invalid channel... Please use R, G or B.") 
    return 
} 

file, err := os.Open(fname) 
if err != nil { 
    fmt.Println(err) 
    return 
} 
defer file.Close() 

pic, err := png.Decode(file) 
if err != nil { 
    fmt.Fprintf(os.Stderr, "%s: %v\n", fname, err) 
    return 
} 

b := pic.Bounds() 

for y := b.Min.Y; y < b.Max.Y; y++ { 
    for x := b.Min.X; x < b.Max.X; x++ { 
     col := pic.At(x, y) 
     ???? How do I swap the channels in col ???? 
    } 
} 
} 

私はあなたの答えでそれを考慮してください、一般的に移動し、プログラミングは本当に新しいです。ありがとうございました。

+1

私はRGBA png画像を使用しています(これはBlender3Dからエクスポートされたノーマルマップです)。 – Zoltan

答えて

7

私はそれがそうであると思ったよりも難しかったです。誰かがより良いアイデアを考え出すことができるのだろうか?

png.Decodeが返す具体的なタイプがわからないという問題があります。画像タイプのいずれかが返される可能性があります。 Setメソッドを持たないimage.Imageインターフェイスのみがあります。 picSetを使用する -

は、最初のピクセルを設定することができ、すべての画像の種類は

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

次はpicは、そのインターフェイス(それがいない場合はパニックになります行くを実装しているかどうかを見る満たすインタフェースを定義し、そのラウンドを取得するには、[OK]を形成していることがあなたを悩ます場合)

// Get an interface which can set pixels 
picSet := pic.(ImageSet) 

今、あなたのループは次のようになります - あなたのアイデアを見ることができるように、私は赤と緑のスワップ。

for y := b.Min.Y; y < b.Max.Y; y++ { 
    for x := b.Min.X; x < b.Max.X; x++ { 
     col := pic.At(x, y) 
     r, g, b, a := col.RGBA() 
     // Swap green and red 
     newCol := color.RGBA{uint8(g>>8), uint8(r>>8), uint8(b>>8), uint8(a>>8)} 
     picSet.Set(x, y, newCol) 
    } 
} 

I、次いで48ビット、24ビット画像とuint16sためuint8sとそれぞれのためにカスタマイズされたコードを有する、本の高性能版は、それがあった画像タイプを決定するために型のスイッチを使用しなければならないと思われます画像など

Here is the complete working例がありますか。それはあなたがそれをダウンロードする必要がありますが、しかし、遊び場で動作しません。


更新:ちょうどあなたのコメントに気づきました。あなたがRGBAイメージを持っていることが分かっているなら、タイプアサーションを使って基礎イメージを得ることができます。

+0

まさに私が探していたもの..ありがとう!パレット画像で余分な仕事をして申し訳ありません。:)私はそれを投稿の本体に含めるべきでした。驚くばかり。 ちょうど好奇心から:私は交換するために選んだチャンネルを調べるために内部ループの内側にスイッチ/ケーステストを書く必要があるようです。それは(とても)非効率的だと感じます。 – Zoltan

+0

できるスイッチは3つしかないので、3つの関数を記述して、必要なものを処理するための関数テーブルを使用します。 (または、スイッチを使用して関数ポインタを選択する)。次に、ポインタを使ってループ内で選択した関数を呼び出すだけで、素早く素早く呼び出すことができます。 –

+0

本当に..ありがとう! – Zoltan

関連する問題