2016-04-12 10 views
5

मैं जेपीईजी छवि फ़ाइल खोलना चाहता हूं, इसे एन्कोड करना चाहता हूं, कुछ पिक्सेल रंग बदल सकता हूं, और फिर इसे वापस सहेजना चाहता हूं।एक पिक्सेल का रंग बदलें - गो लैंग छवि

मैं इस

imgfile, err := os.Open("unchanged.jpeg") 
defer imgfile.Close() 
if err != nil { 
    fmt.Println(err.Error()) 
} 

img,err := jpeg.Decode(imgfile) 
if err != nil { 
    fmt.Println(err.Error()) 
} 
img.Set(0, 0, color.RGBA{85, 165, 34, 1}) 
img.Set(1,0,....) 

outFile, _ := os.Create("changed.jpeg") 
defer outFile.Close() 
jpeg.Encode(outFile, img, nil) 

मैं सिर्फ एक काम कर समाधान के साथ आया नहीं कर सकते हैं की तरह कुछ करने के लिए डिफ़ॉल्ट छवि प्रकार है कि मैं छवि फ़ाइल एन्कोडिंग विधि सेट नहीं है के बाद मिलता है के बाद से करना चाहते हैं ।

क्या कोई यह समझा सकता है कि यह कैसे करें? बहुत बहुत धन्यवाद।

+0

संबंधित/संभावित डुप्लिकेट [गोलांग में एक आयत ड्रा करें?] (Http://stackoverflow.com/questions/28992396/draw-a-rectangle-in-golang) – icza

+0

निष्पक्ष होने के लिए, मैं उस उत्तर को समझ नहीं पा रहा हूं। इसे दो बार पढ़ने के बाद भी मुझे नहीं पता कि सेट विधि का उपयोग करना कैसा है। –

+0

ठीक है, नीचे मेरा जवाब देखें। – icza

उत्तर

10

सफल डिकोडिंग image.Decode() (और यह भी jpeg.Decode() जैसे विशिष्ट डिकोडिंग कार्यों) image.Image का मान प्रदान पर देना चाहिए। image.Image एक इंटरफ़ेस है जो किसी छवि के केवल पढ़ने के दृश्य को परिभाषित करता है: यह छवि को बदलने/खींचने के तरीकों को प्रदान नहीं करता है।

image पैकेज कई image.Image कार्यान्वयन प्रदान करता है जो आपको छवि पर बदलने/खींचने की अनुमति देता है, आमतौर पर Set(x, y int, c color.Color) विधि के साथ।

image.Decode() हालांकि आप कभी भी गारंटी नहीं है कि वापस आ छवि छवि प्रकार image पैकेज में निर्धारित किसी भी हो जाएगा नहीं देता है, या छवि के गतिशील प्रकार एक Set() विधि (यह हो सकता है, लेकिन कोई गारंटी) है भी कि । पंजीकृत कस्टम छवि डिकोडर्स आपको image.Image मान को कस्टम कार्यान्वयन के रूप में वापस कर सकते हैं (जिसका अर्थ है image पैकेज में परिभाषित छवि प्रकार नहीं)।

यदि (गतिशील प्रकार की) छवि में Set() विधि है, तो आप type assertion का उपयोग कर सकते हैं और इसे खींचने के लिए Set() विधि का उपयोग कर सकते हैं।यह है कि यह कैसे किया जा सकता है है: छवि एक Set() विधि नहीं है

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

imgfile, err := os.Open("unchanged.jpg") 
if err != nil { 
    panic(err.Error()) 
} 
defer imgfile.Close() 

img, err := jpeg.Decode(imgfile) 
if err != nil { 
    panic(err.Error()) 
} 

if cimg, ok := img.(Changeable); ok { 
    // cimg is of type Changeable, you can call its Set() method (draw on it) 
    cimg.Set(0, 0, color.RGBA{85, 165, 34, 255}) 
    cimg.Set(0, 1, color.RGBA{255, 0, 0, 255}) 
    // when done, save img as usual 
} else { 
    // No luck... see your options below 
} 

हैं, तो आप जो image.Image लागू करता है एक कस्टम प्रकार को लागू करने से "अपने दृश्य को ओवरराइड" के लिए चुन सकते हैं, लेकिन इसकी At(x, y int) color.Color विधि में (जो पिक्सेल के रंगों को वापस/आपूर्ति करता है) यदि आप छवि को बदल सकते हैं, तो आप नए रंगों को वापस कर देंगे, और मूल छवि के पिक्सल लौटाएंगे जहां आप छवि को नहीं बदलेंगे।

image.Image इंटरफ़ेस को कार्यान्वित करना एम्बेड करके सबसे आसान किया जाता है, इसलिए आपको केवल इच्छित परिवर्तनों को लागू करने की आवश्यकता है। इस प्रकार यह किया जा सकता है:

type MyImg struct { 
    // Embed image.Image so MyImg will implement image.Image 
    // because fields and methods of Image will be promoted: 
    image.Image 
} 

func (m *MyImg) At(x, y int) color.Color { 
    // "Changed" part: custom colors for specific coordinates: 
    switch { 
    case x == 0 && y == 0: 
     return color.RGBA{85, 165, 34, 255} 
    case x == 0 && y == 1: 
     return color.RGBA{255, 0, 0, 255} 
    } 
    // "Unchanged" part: the colors of the original image: 
    return m.Image.At(x, y) 
} 

इसका उपयोग करना: बेहद सरल। छवि लोड के रूप में तुमने किया था, लेकिन जब बचत, जो बदल छवि सामग्री (रंग) जब यह एनकोडर से पूछा है प्रदान करने का ख्याल रखना होगा हमारे MyImg प्रकार का एक मूल्य प्रदान करते हैं: आप के लिए है, तो

jpeg.Encode(outFile, &MyImg{img}, nil) 

कई पिक्सेल बदलें, At() विधि में सभी को शामिल करना व्यावहारिक नहीं है। इसके लिए हम अपने MyImg का विस्तार कर सकते हैं ताकि हमारे Set() कार्यान्वयन हो सकें जो पिक्सेल को संग्रहीत करता है जिसे हम बदलना चाहते हैं। उदाहरण कार्यान्वयन:

type MyImg struct { 
    image.Image 
    custom map[image.Point]color.Color 
} 

func NewMyImg(img image.Image) *MyImg { 
    return &MyImg{img, map[image.Point]color.Color{}} 
} 

func (m *MyImg) Set(x, y int, c color.Color) { 
    m.custom[image.Point{x, y}] = c 
} 

func (m *MyImg) At(x, y int) color.Color { 
    // Explicitly changed part: custom colors of the changed pixels: 
    if c := m.custom[image.Point{x, y}]; c != nil { 
     return c 
    } 
    // Unchanged part: colors of the original image: 
    return m.Image.At(x, y) 
} 

यह का उपयोग करना:

// Load image as usual, then 

my := NewMyImg(img) 
my.Set(0, 0, color.RGBA{85, 165, 34, 1}) 
my.Set(0, 1, color.RGBA{255, 0, 0, 255}) 

// And when saving, save 'my' instead of the original: 
jpeg.Encode(outFile, my, nil) 

आप अधिक से अधिक पिक्सेल बदलने के लिए है, तो यह अधिक लाभदायक हो सकता है सिर्फ एक नई छवि है जो अपनी पिक्सल को बदलने का समर्थन करता है बनाने के लिए है, उदा image.RGBA, उस पर मूल छवि खींचें और फिर इच्छित पिक्सल को बदलने के लिए आगे बढ़ें।

किसी छवि को दूसरे पर आकर्षित करने के लिए, आप image/draw पैकेज का उपयोग कर सकते हैं।

cimg := image.NewRGBA(img.Bounds()) 
draw.Draw(cimg, img.Bounds(), img, image.Point{}, draw.Over) 

// Now you have cimg which contains the original image and is changeable 
// (it has a Set() method) 
cimg.Set(0, 0, color.RGBA{85, 165, 34, 255}) 
cimg.Set(0, 1, color.RGBA{255, 0, 0, 255}) 

// And when saving, save 'cimg' of course: 
jpeg.Encode(outFile, cimg, nil) 

उपरोक्त कोड केवल प्रदर्शन के लिए है। "वास्तविक जीवन" छवियों में Image.Bounds() एक आयताकार वापस कर सकता है जो (0;0) बिंदु से शुरू नहीं होता है, इस मामले में इसे कार्य करने के लिए कुछ समायोजन की आवश्यकता होगी।

+0

यहां तक ​​कि उन पैकेजों के लिए जाने वाले स्रोत को देखकर, मुझे नहीं पता कि आप यह निर्धारित करने में सक्षम थे कि आप सेट के साथ एक इंटरफ़ेस बना सकते हैं इस पर। आप उस निष्कर्ष पर कैसे पहुंचे? –

+0

@ जस्टिन स्वयं अलग कंक्रीट 'छवि।'छवि' पैकेज में छवि 'कार्यान्वयन में सभी' सेट (एक्स, वाई int, c color.color) 'विधि है। इसलिए मानक लाइब्रेरी के छवि डिकोडिंग फ़ंक्शन एक छवि कार्यान्वयन को वापस करने की अत्यधिक संभावना रखते हैं जिसमें यह 'सेट()' विधि होगी। इसलिए हमें पहले यह जांचना चाहिए। अगर छवि में 'सेट()' विधि नहीं है, तो हम अपनी कस्टम 'सेट()' विधि को जो कुछ भी पसंद करते हैं उसका नाम दे सकते हैं (इससे कोई फर्क नहीं पड़ता कि हम केवल इसे कॉल करेंगे), मैंने अभी भी वही इस्तेमाल किया स्पष्टता के लिए विधि हस्ताक्षर। – icza

0

छवि डीकोड image interface देता है जिसमें छवि पिक्सेल चौड़ाई और ऊंचाई प्राप्त करने के लिए Bounds विधि होती है।

img, _, err := image.Decode(imgfile) 
if err != nil { 
    fmt.Println(err.Error()) 
} 
size := img.Bounds().Size() 

एक बार जब आप चौड़ाई और ऊंचाई (y समन्वय के लिए एक x के लिए और एक) छोरों के लिए दो नेस्टेड साथ पिक्सल से अधिक पुनरावृति कर सकते हैं।

for x := 0; x < size.X; x++ { 
    for y := 0; y < size.Y; y++ { 
     color := color.RGBA{ 
      uint8(255 * x/size.X), 
      uint8(255 * y/size.Y), 
      55, 
      255} 
     m.Set(x, y, color) 
    } 
} 

एक बार जब आप छवि मैनिपुलेशन के साथ होते हैं तो आप फ़ाइल को एन्कोड कर सकते हैं। लेकिन क्योंकि image.Image में Set विधि नहीं है, तो आप एक नई आरजीबीए छवि बना सकते हैं, जो RGBA संरचना देता है, जिस पर आप Set विधि का उपयोग कर सकते हैं।

m := image.NewRGBA(image.Rect(0, 0, width, height)) 
outFile, err := os.Create("changed.jpg") 
if err != nil { 
    log.Fatal(err) 
} 
defer outFile.Close() 
png.Encode(outFile, m) 
+0

मैं इसका उपयोग नहीं कर सकता। मैं अभी भी सेट विधि का उपयोग नहीं कर सकता, क्योंकि मेरी एन्कोडेड छवि प्रकार छवि है। छवि, जिसमें सेट विधि नहीं है। पूरी छवि पर लूपिंग वह नहीं है जो मैं करना चाहता हूं, मुझे केवल कुछ पिक्सेल बदलने की जरूरत है। उत्तर के लिए धन्यवाद –

+0

एक नई आरजीबीए छवि बनाने के बारे में, जो आरजीबीए इंटरफ़ेस देता है, जिस पर आप 'सेट' विधि 'm: = image.NewRGBA (image.Rect (0, 0, चौड़ाई, ऊंचाई) का उपयोग कर सकते हैं।) ' –

+0

आठ, मैंने सोचा कि मैं सीधे अपने एन्कोडेड छवि पर पिक्सल खींच सकता हूं। नई छवि बनाना और पुरानी एन्कोडेड छवि की सामग्री की प्रतिलिपि बनाना, इसलिए मैं कुछ पिक्सल बदल सकता हूं जो मेरे लिए थोड़ा अजीब लगता है। –

0

छवि। छवि डिफ़ॉल्ट रूप से अपरिवर्तनीय है, लेकिन आकर्षित करें। छवि उत्परिवर्तनीय है।

आप draw.Image करने के लिए एक प्रकार का रूपांतरण करते हैं, कि तुम एक सेट विधि

img.(draw.Image).Set(0,0, color.RGBA{85, 165, 34, 1}) 
+2

मैंने पहले ऐसा करने की कोशिश की। मुझे यह त्रुटि मिल रही है: "* image.YCbCr ड्रॉ नहीं है। छवि: गायब विधि सेट करें" –

संबंधित मुद्दे