2016-02-05 9 views
5

मैं एक हास्केल प्रोग्राम लिख रहा हूं जो big mapsKnytt Stories विश्व फ़ाइलों से खींचता है। मैं छवि फ़ाइलों को बनाने के लिए friday पैकेज का उपयोग करता हूं, और मुझे कई ग्राफिक्स परतों को लिखना होगा जिन्हें मैंने spritesheets से एक साथ रखा था। अभी, मैं इस के लिए मेरे अपने बदसूरत समारोह का उपयोग करें:`शुक्रवार पैकेज बहुत धीमा है

enter image description here

हैं "नीचे" परत:

import qualified Vision.Primitive as Im 
import qualified Vision.Image.Type as Im 
import qualified Vision.Image.Class as Im 
import Vision.Image.RGBA.Type (RGBA, RGBAPixel(..)) 

-- Map a Word8 in [0, 255] to a Double in [0, 1]. 
w2f :: Word8 -> Double 
w2f = (/255) . fromIntegral . fromEnum 

-- Map a Double in [0, 1] to a Word8 in [0, 255]. 
f2w :: Double -> Word8 
f2w = toEnum . round . (*255) 

-- Compose two images into one. `bottom` is wrapped to `top`'s size. 
compose :: RGBA -> RGBA -> RGBA 
compose bottom top = 
    let newSize = Im.manifestSize top 
     bottom' = wrap newSize bottom 
    in Im.fromFunction newSize $ \p -> 
     let RGBAPixel rB gB bB aB = bottom' Im.! p 
      RGBAPixel rT gT bT aT = top Im.! p 
      aB' = w2f aB; aT' = w2f aT 
      ovl :: Double -> Double -> Double 
      ovl cB cT = (cT * aT' + cB * aB' * (1.0 - aT'))/(aT' + aB' * (1.0 - aT')) 
      (~*~) :: Word8 -> Word8 -> Word8 
      cB ~*~ cT = f2w $ w2f cB `ovl` w2f cT 
      aO = f2w (aT' + aB' * (1.0 - aT')) 
     in RGBAPixel (rB ~*~ rT) (gB ~*~ gT) (bB ~*~ bT) aO 

यह बस एक नीचे की परत है और एक शीर्ष स्तर है, तो जैसे अल्फा कंपोजिट एक बनावट है, इसे शीर्ष परत के आकार में फिट करने के लिए क्षैतिज और लंबवत (wrap द्वारा) लूप किया जाएगा।


नक्शा प्रस्तुत करना उससे कहीं अधिक लंबा लगता है। गेम के साथ आने वाली डिफ़ॉल्ट दुनिया के लिए मानचित्र को 27 मिनट-O3 पर ले जाता है, भले ही गेम स्वयं कुछ अलग-अलग मिलीसेकंड से कम में प्रत्येक अलग स्क्रीन को स्पष्ट रूप से प्रस्तुत कर सके। (उपरोक्त लिंक किए गए छोटे उदाहरण आउटपुट में 67 सेकंड लगते हैं; बहुत लंबा भी है।)

प्रोफाइलर (आउटपुट here) कहता है कि कार्यक्रम compose में अपने समय का लगभग 77% खर्च करता है।

इसे काटना एक अच्छा पहला कदम लगता है। यह एक बहुत ही सरल ऑपरेशन की तरह लगता है, लेकिन मुझे friday में मूल फ़ंक्शन नहीं मिल रहा है जो मुझे ऐसा करने देता है। माना जाता है कि जीएचसी fromFunction सामानों को ध्वस्त करने में अच्छा होना चाहिए, लेकिन मुझे नहीं पता कि क्या हो रहा है। या पैकेज सिर्फ सुपर धीमी है?

Here’s the full, compileable code.

+0

क्या आप 'रचना' में थोड़ा गहरा खोदने के लिए '-auto-all' प्रोफाइलिंग विकल्प का उपयोग कर सकते हैं और देख सकते हैं कि समय क्या ले रहा है? – crockeea

+0

क्या यह आपको कुछ बताता है? https://bpaste.net/raw/cb2454d6fbc6 – Lynn

+0

[यहां] (https://gist.github.com/lynn/504e0712b5dd8c13f953) कोड – Lynn

उत्तर

1

जैसा कि मैंने मेरी टिप्पणी में कहा गया है, MCE मैं प्रदर्शन ठीक किया जाता है और किसी भी दिलचस्प उत्पादन उपज नहीं करता है:

module Main where 
import qualified Vision.Primitive as Im 
import Vision.Primitive.Shape 
import qualified Vision.Image.Type as Im 
import qualified Vision.Image.Class as Im 
import Vision.Image.RGBA.Type (RGBA, RGBAPixel(..)) 
import Vision.Image.Storage.DevIL (load, save, Autodetect(..), StorageError, StorageImage(..)) 
import Vision.Image (convert) 
import Data.Word 
import System.Environment (getArgs) 

main :: IO() 
main = do 
    [input1,input2,output] <- getArgs 
    io1 <- load Autodetect input1 :: IO (Either StorageError StorageImage) 
    io2 <- load Autodetect input2 :: IO (Either StorageError StorageImage) 
    case (io1,io2) of 
    (Left err,_) -> error $ show err 
    (_,Left err) -> error $ show err 
    (Right i1, Right i2) -> go (convert i1) (convert i2) output 
where 
    go i1 i2 output = 
     do res <- save Autodetect output (compose i1 i2) 
     case res of 
      Nothing -> putStrLn "Done with compose" 
      Just e -> error (show (e :: StorageError)) 

-- Wrap an image to a given size. 
wrap :: Im.Size -> RGBA -> RGBA 
wrap s im = 
    let Z :. h :. w = Im.manifestSize im 
    in Im.fromFunction s $ \(Z :. y :. x) -> im Im.! Im.ix2 (y `mod` h) (x `mod` w) 

-- Map a Word8 in [0, 255] to a Double in [0, 1]. 
w2f :: Word8 -> Double 
w2f = (/255) . fromIntegral . fromEnum 

-- Map a Double in [0, 1] to a Word8 in [0, 255]. 
f2w :: Double -> Word8 
f2w = toEnum . round . (*255) 

-- Compose two images into one. `bottom` is wrapped to `top`'s size. 
compose :: RGBA -> RGBA -> RGBA 
compose bottom top = 
    let newSize = Im.manifestSize top 
     bottom' = wrap newSize bottom 
    in Im.fromFunction newSize $ \p -> 
     let RGBAPixel rB gB bB aB = bottom' Im.! p 
      RGBAPixel rT gT bT aT = top Im.! p 
      aB' = w2f aB; aT' = w2f aT 
      ovl :: Double -> Double -> Double 
      ovl cB cT = (cT * aT' + cB * aB' * (1.0 - aT'))/(aT' + aB' * (1.0 - aT')) 
      (~*~) :: Word8 -> Word8 -> Word8 
      cB ~*~ cT = f2w $ w2f cB `ovl` w2f cT 
      aO = f2w (aT' + aB' * (1.0 - aT')) 
     in RGBAPixel (rB ~*~ rT) (gB ~*~ gT) (bB ~*~ bT) aO 

इस कोड को दो छवियों लोड, आपके लिखें आपरेशन लागू होती है और बचाता है परिणामस्वरूप छवि। यह लगभग तुरंत होता है:

% ghc -O2 so.hs && time ./so /tmp/lambda.jpg /tmp/lambda2.jpg /tmp/output.jpg && o /tmp/output.jpg 
Done with compose 
./so /tmp/lambda.jpg /tmp/lambda2.jpg /tmp/output.jpg 0.05s user 0.00s system 98% cpu 0.050 total 

यदि आपके पास वैकल्पिक एमसीई है तो कृपया इसे पोस्ट करें। आपका पूरा कोड मेरी आंखों के लिए बहुत कम था।

+0

ठीक है, मुझे यकीन है कि दो छवियों को लिखने में लंबा समय नहीं लगता है। समस्या यह है कि उनमें से हजारों को लिखना * यह * लंबा नहीं लेना चाहिए। – Lynn

+0

तो मैं फिर से पूछता हूं - न्यूनतम संकलित उदाहरण प्रदान करने की देखभाल? –

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