From 7848525ee7a74b4aa18021d05f3505591cad5868 Mon Sep 17 00:00:00 2001 From: Nishant Shukla Date: Tue, 24 Jun 2014 19:53:01 -0400 Subject: [PATCH] Added Chapter 10 --- Ch10/Code01_tw/Code1001.cabal | 25 +++ Ch10/Code01_tw/Common.hs | 62 ++++++ Ch10/Code01_tw/Main.hs | 65 ++++++ Ch10/Code01_tw/Makefile | 5 + Ch10/Code02_irc/Code1002.cabal | 25 +++ Ch10/Code02_irc/Main.hs | 28 +++ Ch10/Code02_irc/Makefile | 5 + Ch10/Code03_irc2/Code1003.cabal | 25 +++ Ch10/Code03_irc2/Main.hs | 30 +++ Ch10/Code03_irc2/Makefile | 5 + Ch10/Code04_poll/Code1004.cabal | 25 +++ Ch10/Code04_poll/Main.hs | 28 +++ Ch10/Code04_poll/Makefile | 5 + Ch10/Code05_file/Code1005.cabal | 25 +++ Ch10/Code05_file/Main.hs | 29 +++ Ch10/Code05_file/Makefile | 5 + Ch10/Code06_socket/Code1006.cabal | 25 +++ Ch10/Code06_socket/Main.hs | 32 +++ Ch10/Code06_socket/Makefile | 5 + Ch10/Code06_socket/client.hs | 25 +++ Ch10/Code07_cam/Code1007.cabal | 25 +++ Ch10/Code07_cam/Main.hs | 39 ++++ Ch10/Code07_cam/Makefile | 5 + Ch10/Code08_cam/Code1008.cabal | 25 +++ Ch10/Code08_cam/Main.hs | 26 +++ Ch10/Code08_cam/Makefile | 5 + Ch10/Code08_cam/lena.jpg | Bin 0 -> 37868 bytes Ch10/LICENSE | 339 ++++++++++++++++++++++++++++++ Ch10/README.md | 11 +- 29 files changed, 953 insertions(+), 1 deletion(-) create mode 100644 Ch10/Code01_tw/Code1001.cabal create mode 100644 Ch10/Code01_tw/Common.hs create mode 100644 Ch10/Code01_tw/Main.hs create mode 100644 Ch10/Code01_tw/Makefile create mode 100644 Ch10/Code02_irc/Code1002.cabal create mode 100644 Ch10/Code02_irc/Main.hs create mode 100644 Ch10/Code02_irc/Makefile create mode 100644 Ch10/Code03_irc2/Code1003.cabal create mode 100644 Ch10/Code03_irc2/Main.hs create mode 100644 Ch10/Code03_irc2/Makefile create mode 100644 Ch10/Code04_poll/Code1004.cabal create mode 100644 Ch10/Code04_poll/Main.hs create mode 100644 Ch10/Code04_poll/Makefile create mode 100644 Ch10/Code05_file/Code1005.cabal create mode 100644 Ch10/Code05_file/Main.hs create mode 100644 Ch10/Code05_file/Makefile create mode 100644 Ch10/Code06_socket/Code1006.cabal create mode 100644 Ch10/Code06_socket/Main.hs create mode 100644 Ch10/Code06_socket/Makefile create mode 100644 Ch10/Code06_socket/client.hs create mode 100644 Ch10/Code07_cam/Code1007.cabal create mode 100644 Ch10/Code07_cam/Main.hs create mode 100644 Ch10/Code07_cam/Makefile create mode 100644 Ch10/Code08_cam/Code1008.cabal create mode 100644 Ch10/Code08_cam/Main.hs create mode 100644 Ch10/Code08_cam/Makefile create mode 100644 Ch10/Code08_cam/lena.jpg create mode 100644 Ch10/LICENSE diff --git a/Ch10/Code01_tw/Code1001.cabal b/Ch10/Code01_tw/Code1001.cabal new file mode 100644 index 0000000..c4c87c5 --- /dev/null +++ b/Ch10/Code01_tw/Code1001.cabal @@ -0,0 +1,25 @@ +-- Initial Code1001.cabal generated by cabal init. For further +-- documentation, see http://haskell.org/cabal/users-guide/ + +name: Code1001 +version: 0.1.0.0 +synopsis: Twitter sentiment analysis. +-- description: +homepage: haskelldata.com +license: GPL-2 +license-file: ../LICENSE +author: Nishant Shukla +maintainer: nick722@gmail.com +-- copyright: +category: Network +build-type: Simple +-- extra-source-files: +cabal-version: >=1.10 + +executable Code1001 + main-is: Main.hs + -- other-modules: + other-extensions: OverloadedStrings, ConstraintKinds, FlexibleContexts + build-depends: base >=4.6 && <4.7, yocto, twitter-conduit >=0.0 && <0.1, authenticate-oauth >=1.4 && <1.5, network >=2.5 && <2.6, http-conduit >=2.0 && <2.1, containers >=0.5 && <0.6, bytestring >=0.10 && <0.11, case-insensitive >=1.2 && <1.3, transformers >=0.3 && <0.4, transformers-base >=0.4 && <0.5, resourcet >=0.4 && <0.5, monad-logger >=0.3 && <0.4, lens >=4.1 && <4.2, conduit >=1.0 && <1.1, text >=0.11 && <0.12, HTTP >=4000.2 && <4000.3, twitter-types >=0.2 && <0.3 + -- hs-source-dirs: + default-language: Haskell2010 \ No newline at end of file diff --git a/Ch10/Code01_tw/Common.hs b/Ch10/Code01_tw/Common.hs new file mode 100644 index 0000000..098e9f0 --- /dev/null +++ b/Ch10/Code01_tw/Common.hs @@ -0,0 +1,62 @@ +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ConstraintKinds #-} +{-# LANGUAGE FlexibleContexts #-} + +module Common where + +import Web.Twitter.Conduit + +import Web.Authenticate.OAuth as OA +import qualified Network.URI as URI +import Network.HTTP.Conduit +import qualified Data.Map as M +import qualified Data.ByteString.Char8 as S8 +import qualified Data.CaseInsensitive as CI +import Control.Applicative +import Control.Monad.IO.Class +import Control.Monad.Base +import Control.Monad.Trans.Resource +import System.Environment +import Control.Monad.Logger +import Control.Lens + +getOAuthTokens :: IO (OAuth, Credential) +getOAuthTokens = do + consumerKey <- getEnv' "OAUTH_CONSUMER_KEY" + consumerSecret <- getEnv' "OAUTH_CONSUMER_SECRET" + accessToken <- getEnv' "OAUTH_ACCESS_TOKEN" + accessSecret <- getEnv' "OAUTH_ACCESS_SECRET" + let oauth = twitterOAuth + { oauthConsumerKey = consumerKey + , oauthConsumerSecret = consumerSecret + } + cred = Credential + [ ("oauth_token", accessToken) + , ("oauth_token_secret", accessSecret) + ] + return (oauth, cred) + where + getEnv' = (S8.pack <$>) . getEnv + +getProxyEnv :: IO (Maybe Proxy) +getProxyEnv = do + env <- M.fromList . over (mapped . _1) CI.mk <$> getEnvironment + let u = M.lookup "https_proxy" env <|> + M.lookup "http_proxy" env <|> + M.lookup "proxy" env >>= URI.parseURI >>= URI.uriAuthority + return $ Proxy <$> (S8.pack . URI.uriRegName <$> u) <*> (parsePort . URI.uriPort <$> u) + where + parsePort :: String -> Int + parsePort [] = 8080 + parsePort (':':xs) = read xs + parsePort xs = error $ "port number parse failed " ++ xs + +runTwitterFromEnv :: (MonadIO m, MonadBaseControl IO m) => TW (ResourceT m) a -> m a +runTwitterFromEnv task = do + pr <- liftBase getProxyEnv + (oa, cred) <- liftBase getOAuthTokens + let env = (setCredential oa cred def) { twProxy = pr } + runTW env task + +runTwitterFromEnv' :: (MonadIO m, MonadBaseControl IO m) => TW (ResourceT (NoLoggingT m)) a -> m a +runTwitterFromEnv' = runNoLoggingT . runTwitterFromEnv \ No newline at end of file diff --git a/Ch10/Code01_tw/Main.hs b/Ch10/Code01_tw/Main.hs new file mode 100644 index 0000000..9e2909a --- /dev/null +++ b/Ch10/Code01_tw/Main.hs @@ -0,0 +1,65 @@ +{-# LANGUAGE OverloadedStrings #-} + +import qualified Data.Conduit as C +import qualified Data.Conduit.List as CL +import qualified Data.Text.IO as T +import qualified Data.Text as T + +import Control.Monad.IO.Class (liftIO) +import Network.HTTP (getResponseBody, getRequest, simpleHTTP, urlEncode) +import Text.JSON.Yocto +import Web.Twitter.Conduit (stream, statusesFilterByTrack) +import Common +import Control.Lens ((^!), act) +import Data.Map ((!)) +import Data.List (isInfixOf, or) +import Web.Twitter.Types (userScreenName, statusUser, statusText, StreamingAPI(..)) + +-- Streaming Twitter for real-time sentiment analysis +main :: IO () +main = do + let query = "x-men" + T.putStrLn $ T.concat [ "Streaming Tweets that match \"" + , query, "\"..."] + analyze query + +analyze :: T.Text -> IO () +analyze query = runTwitterFromEnv' $ do + src <- stream $ statusesFilterByTrack query + src C.$$+- CL.mapM_ (^! act (liftIO . process)) + +process :: StreamingAPI -> IO () +process (SStatus s) = do + let theUser = userScreenName $ statusUser s + let theTweet = statusText s + T.putStrLn $ T.concat [theUser, ": ", theTweet] + val <- sentiment $ T.unpack theTweet + let record = (T.unpack theUser) ++ "," ++ (show.fromRational) val ++ "\n" + appendFile "output.csv" record + print val +process s = return () + +clean :: String -> String +clean str = unwords $ filter + (\w -> not (or + [ isInfixOf "@" w + , isInfixOf "#" w + , isInfixOf "http://" w ])) + (words str) + +sentiment :: String -> IO Rational +sentiment str = do + let baseURL = "http://www.sentiment140.com/api/classify?text=" + resp <- simpleHTTP $ getRequest $ baseURL ++ (urlEncode.clean) str + body <- getResponseBody resp + let p = polarity (decode body) / 4.0 + return p + +polarity :: Value -> Rational +polarity (Object m) = polarity' $ m ! "results" + where polarity' (Object m) = fromNumber $ m ! "polarity" + fromNumber (Number n) = n +polarity _ = -1 + + + diff --git a/Ch10/Code01_tw/Makefile b/Ch10/Code01_tw/Makefile new file mode 100644 index 0000000..9899df1 --- /dev/null +++ b/Ch10/Code01_tw/Makefile @@ -0,0 +1,5 @@ +default: + cabal install --bindir=./ + +clean: + rm -rf dist Setup.hs Code1001 *~ diff --git a/Ch10/Code02_irc/Code1002.cabal b/Ch10/Code02_irc/Code1002.cabal new file mode 100644 index 0000000..66b8298 --- /dev/null +++ b/Ch10/Code02_irc/Code1002.cabal @@ -0,0 +1,25 @@ +-- Initial Code1002.cabal generated by cabal init. For further +-- documentation, see http://haskell.org/cabal/users-guide/ + +name: Code1002 +version: 0.1.0.0 +synopsis: IRC example. +-- description: +homepage: haskelldata.com +license: GPL-2 +license-file: ../LICENSE +author: Nishant Shukla +maintainer: nick722@gmail.com +-- copyright: +category: Network +build-type: Simple +-- extra-source-files: +cabal-version: >=1.10 + +executable Code1002 + main-is: Main.hs + -- other-modules: + -- other-extensions: + build-depends: base >=4.6 && <4.7, network >=2.5 && <2.6 + -- hs-source-dirs: + default-language: Haskell2010 \ No newline at end of file diff --git a/Ch10/Code02_irc/Main.hs b/Ch10/Code02_irc/Main.hs new file mode 100644 index 0000000..c5b7776 --- /dev/null +++ b/Ch10/Code02_irc/Main.hs @@ -0,0 +1,28 @@ +import Network +import System.IO +import Text.Printf +import Control.Monad (forever) + +server = "irc.freenode.org" +port = 6667 +chan = "#haskelldata" +nick = "awesome-haskell-bot" + +-- Reading IRC chat room messages +main = do + h <- connectTo server (PortNumber (fromIntegral port)) + hSetBuffering h NoBuffering + write h "NICK" nick + write h "USER" (nick++" 0 * :tutorial bot") + write h "JOIN" chan + listen h + +write :: Handle -> String -> String -> IO () +write h s t = do + hPrintf h "%s %s\r\n" s t + printf "> %s %s\n" s t + +listen :: Handle -> IO () +listen h = forever $ do + s <- hGetLine h + putStrLn s diff --git a/Ch10/Code02_irc/Makefile b/Ch10/Code02_irc/Makefile new file mode 100644 index 0000000..0224ebd --- /dev/null +++ b/Ch10/Code02_irc/Makefile @@ -0,0 +1,5 @@ +default: + cabal install --bindir=./ + +clean: + rm -rf dist Setup.hs Code1002 *~ diff --git a/Ch10/Code03_irc2/Code1003.cabal b/Ch10/Code03_irc2/Code1003.cabal new file mode 100644 index 0000000..4adeb21 --- /dev/null +++ b/Ch10/Code03_irc2/Code1003.cabal @@ -0,0 +1,25 @@ +-- Initial Code1003.cabal generated by cabal init. For further +-- documentation, see http://haskell.org/cabal/users-guide/ + +name: Code1003 +version: 0.1.0.0 +synopsis: Using an IRC library. +-- description: +homepage: haskelldata.com +license: GPL-2 +license-file: ../LICENSE +author: Nishant Shukla +maintainer: nick722@gmail.com +-- copyright: +category: Network +build-type: Simple +-- extra-source-files: +cabal-version: >=1.10 + +executable Code1003 + main-is: Main.hs + -- other-modules: + other-extensions: OverloadedStrings + build-depends: base >=4.6 && <4.7, simpleirc >=0.3 && <0.4, bytestring >=0.10 && <0.11 + -- hs-source-dirs: + default-language: Haskell2010 \ No newline at end of file diff --git a/Ch10/Code03_irc2/Main.hs b/Ch10/Code03_irc2/Main.hs new file mode 100644 index 0000000..12f20c2 --- /dev/null +++ b/Ch10/Code03_irc2/Main.hs @@ -0,0 +1,30 @@ +{-# LANGUAGE OverloadedStrings #-} + +import Network.SimpleIRC +import Data.Maybe +import qualified Data.ByteString.Char8 as B + +-- Responding to IRC messages +onMessage :: EventFunc +onMessage s m = do + case msg of + "host?" -> sendMsg s chan $ botMsg + otherwise -> return () + where chan = fromJust $ mChan m + msg = mMsg m + host = case mHost m of + Just h -> h + Nothing -> "unknown" + nick = case mNick m of + Just n -> n + Nothing -> "unknown user" + botMsg = B.concat ["Hi ", nick, ", your host is ", host] + +events = [(Privmsg onMessage)] + +freenode = (mkDefaultConfig "irc.freenode.net" "awesome-bot") + { cChannels = ["#haskelldata"] -- Channels to join on connect + , cEvents = events -- Events to bind + } + +main = connect freenode False True diff --git a/Ch10/Code03_irc2/Makefile b/Ch10/Code03_irc2/Makefile new file mode 100644 index 0000000..8b87ebf --- /dev/null +++ b/Ch10/Code03_irc2/Makefile @@ -0,0 +1,5 @@ +default: + cabal install --bindir=./ + +clean: + rm -rf dist Setup.hs Code1003 *~ diff --git a/Ch10/Code04_poll/Code1004.cabal b/Ch10/Code04_poll/Code1004.cabal new file mode 100644 index 0000000..35bd331 --- /dev/null +++ b/Ch10/Code04_poll/Code1004.cabal @@ -0,0 +1,25 @@ +-- Initial Code1004.cabal generated by cabal init. For further +-- documentation, see http://haskell.org/cabal/users-guide/ + +name: Code1004 +version: 0.1.0.0 +synopsis: Polling a webserver. +-- description: +homepage: haskelldata.com +license: GPL-2 +license-file: ../LICENSE +author: Nishant Shukla +maintainer: nick722@gmail.com +-- copyright: +category: Network +build-type: Simple +-- extra-source-files: +cabal-version: >=1.10 + +executable Code1004 + main-is: Main.hs + -- other-modules: + -- other-extensions: + build-depends: base >=4.6 && <4.7, HTTP >=4000.2 && <4000.3, text >=0.11 && <0.12 + -- hs-source-dirs: + default-language: Haskell2010 \ No newline at end of file diff --git a/Ch10/Code04_poll/Main.hs b/Ch10/Code04_poll/Main.hs new file mode 100644 index 0000000..3f39810 --- /dev/null +++ b/Ch10/Code04_poll/Main.hs @@ -0,0 +1,28 @@ +import Network.HTTP +import Control.Concurrent (threadDelay) +import qualified Data.Text as T + +url = "http://www.reddit.com/r/pics/new.json" + +latest :: IO String +latest = simpleHTTP (getRequest url) >>= getResponseBody + +-- Polling a web server +doWork str = length $ T.breakOnAll + (T.pack "imgur.com/") (T.pack str) + +poll :: IO a +poll = do + body <- latest + print $ doWork body + threadDelay (10 * 10^6) + poll + +main :: IO a +main = do + putStrLn $ "Polling " ++ url ++ " ..." + poll + + + + diff --git a/Ch10/Code04_poll/Makefile b/Ch10/Code04_poll/Makefile new file mode 100644 index 0000000..66ec658 --- /dev/null +++ b/Ch10/Code04_poll/Makefile @@ -0,0 +1,5 @@ +default: + cabal install --bindir=./ + +clean: + rm -rf dist Setup.hs Code1004 *~ diff --git a/Ch10/Code05_file/Code1005.cabal b/Ch10/Code05_file/Code1005.cabal new file mode 100644 index 0000000..3ac82be --- /dev/null +++ b/Ch10/Code05_file/Code1005.cabal @@ -0,0 +1,25 @@ +-- Initial Code1005.cabal generated by cabal init. For further +-- documentation, see http://haskell.org/cabal/users-guide/ + +name: Code1005 +version: 0.1.0.0 +synopsis: Detecting file-system modifications. +-- description: +homepage: haskelldata.com +license: GPL-2 +license-file: ../LICENSE +author: Nishant Shukla +maintainer: nick722@gmail.com +-- copyright: +category: System +build-type: Simple +-- extra-source-files: +cabal-version: >=1.10 + +executable Code1005 + main-is: Main.hs + -- other-modules: + other-extensions: OverloadedStrings + build-depends: base >=4.6 && <4.7, system-filepath >=0.4 && <0.5, fsnotify >=0.1 && <0.2, system-fileio >=0.3 && <0.4 + -- hs-source-dirs: + default-language: Haskell2010 \ No newline at end of file diff --git a/Ch10/Code05_file/Main.hs b/Ch10/Code05_file/Main.hs new file mode 100644 index 0000000..79f6333 --- /dev/null +++ b/Ch10/Code05_file/Main.hs @@ -0,0 +1,29 @@ +{-# LANGUAGE OverloadedStrings #-} +import Filesystem.Path.CurrentOS + +import System.FSNotify +import Filesystem +import Filesystem.Path (filename) + +-- Detecting real-time file changes +main :: IO () +main = do + -- let wd = "." + wd <- getWorkingDirectory + print wd + man <- startManager + watchTree man wd (const True) doWork + putStrLn "press return to stop" + getLine + putStrLn "watching stopped, press return to exit" + stopManager man + getLine + return () + +doWork :: Event -> IO () +doWork (Added filepath time) = + putStrLn $ (show $ filename filepath) ++ " added" +doWork (Modified filepath time) = + putStrLn $ (show $ filename filepath) ++ " modified" +doWork (Removed filepath time) = + putStrLn $ (show $ filename filepath) ++ " removed" diff --git a/Ch10/Code05_file/Makefile b/Ch10/Code05_file/Makefile new file mode 100644 index 0000000..2e81a58 --- /dev/null +++ b/Ch10/Code05_file/Makefile @@ -0,0 +1,5 @@ +default: + cabal install --bindir=./ + +clean: + rm -rf dist Setup.hs Code1005 *~ diff --git a/Ch10/Code06_socket/Code1006.cabal b/Ch10/Code06_socket/Code1006.cabal new file mode 100644 index 0000000..ce42994 --- /dev/null +++ b/Ch10/Code06_socket/Code1006.cabal @@ -0,0 +1,25 @@ +-- Initial Code1006.cabal generated by cabal init. For further +-- documentation, see http://haskell.org/cabal/users-guide/ + +name: Code1006 +version: 0.1.0.0 +synopsis: Socket programming. +-- description: +homepage: haskelldata.com +license: GPL-2 +license-file: ../LICENSE +author: Nishant Shukla +maintainer: nick722@gmail.com +-- copyright: +category: System +build-type: Simple +-- extra-source-files: +cabal-version: >=1.10 + +executable Code1006 + main-is: Main.hs + -- other-modules: + -- other-extensions: + build-depends: base >=4.6 && <4.7, network >=2.5 && <2.6 + -- hs-source-dirs: + default-language: Haskell2010 \ No newline at end of file diff --git a/Ch10/Code06_socket/Main.hs b/Ch10/Code06_socket/Main.hs new file mode 100644 index 0000000..3c4d5cc --- /dev/null +++ b/Ch10/Code06_socket/Main.hs @@ -0,0 +1,32 @@ +import Network (listenOn, withSocketsDo, accept, PortID(..), Socket) +import System.Environment (getArgs) +import System.IO (hSetBuffering, hGetLine, hPutStrLn, BufferMode(..), Handle) +import Control.Concurrent (forkIO) + +-- Communicating in real-time with sockets +main :: IO () +main = withSocketsDo $ do + let port = PortNumber 9001 + socket <- listenOn port + putStrLn "Listening..." + sockHandler socket + +sockHandler :: Socket -> IO () +sockHandler socket = do + (h, _, _) <- accept socket + putStrLn "Connected!" + hSetBuffering h LineBuffering + forkIO $ process h + forkIO $ respond h + sockHandler socket + +respond h = withSocketsDo $ do + txt <- getLine + hPutStrLn h txt + respond h + +process :: Handle -> IO () +process h = do + line <- hGetLine h + print line + process h diff --git a/Ch10/Code06_socket/Makefile b/Ch10/Code06_socket/Makefile new file mode 100644 index 0000000..3d14859 --- /dev/null +++ b/Ch10/Code06_socket/Makefile @@ -0,0 +1,5 @@ +default: + cabal install --bindir=./ + +clean: + rm -rf dist Setup.hs Code1006 *~ diff --git a/Ch10/Code06_socket/client.hs b/Ch10/Code06_socket/client.hs new file mode 100644 index 0000000..a0a043a --- /dev/null +++ b/Ch10/Code06_socket/client.hs @@ -0,0 +1,25 @@ +import Network (connectTo, withSocketsDo, PortID(..)) +import System.Environment (getArgs) +import System.IO (hSetBuffering, hPutStrLn, hGetLine, BufferMode(..)) +import Control.Concurrent (forkIO) + +main = withSocketsDo $ do + let port = PortNumber 9001 + h <- connectTo "localhost" port + putStrLn "Connected!" + hSetBuffering h LineBuffering + forkIO $ respond h + forkIO $ process h + loop + +loop = loop + +respond h = do + txt <- getLine + hPutStrLn h txt + respond h + +process h = do + line <- hGetLine h + print line + process h diff --git a/Ch10/Code07_cam/Code1007.cabal b/Ch10/Code07_cam/Code1007.cabal new file mode 100644 index 0000000..8f34aec --- /dev/null +++ b/Ch10/Code07_cam/Code1007.cabal @@ -0,0 +1,25 @@ +-- Initial Code1007.cabal generated by cabal init. For further +-- documentation, see http://haskell.org/cabal/users-guide/ + +name: Code1007 +version: 0.1.0.0 +synopsis: Facial detection. +-- description: +homepage: haskelldata.com +license: GPL-2 +license-file: ../LICENSE +author: Nishant Shukla +maintainer: nick722@gmail.com +-- copyright: +category: Graphics +build-type: Simple +-- extra-source-files: +cabal-version: >=1.10 + +executable Code1007 + main-is: Main.hs + -- other-modules: + -- other-extensions: + build-depends: base >=4.6 && <4.7, cv-combinators >=0.1 && <0.2, HOpenCV >=0.1 && <0.2, allocated-processor >=0.0 && <0.1 + -- hs-source-dirs: + default-language: Haskell2010 \ No newline at end of file diff --git a/Ch10/Code07_cam/Main.hs b/Ch10/Code07_cam/Main.hs new file mode 100644 index 0000000..6c1c5e2 --- /dev/null +++ b/Ch10/Code07_cam/Main.hs @@ -0,0 +1,39 @@ +--sudo apt-get install libopencv-dev libsdl1.2-dev ftgl-dev +--cabal install cv-combinators + +import AI.CV.ImageProcessors + +import qualified AI.CV.OpenCV.CV as CV +import qualified Control.Processor as Processor +import Control.Processor((--<)) +import AI.CV.OpenCV.Types (PImage) +import AI.CV.OpenCV.CxCore(CvRect(..), CvSize(..)) + +import Prelude hiding (id) +import Control.Arrow ((&&&), (***)) +import Control.Category ((>>>), id) + +captureDev :: ImageSource +--captureDev = videoFile "./video.mpeg" +captureDev = camera 0 + +resizer :: ImageProcessor +resizer = resize 320 240 CV.CV_INTER_LINEAR + +edges :: ImageProcessor +edges = canny 30 190 3 + +faceDetect :: Processor.IOProcessor PImage [CvRect] +faceDetect = haarDetect "/usr/share/opencv/haarcascades/haarcascade_frontalface_alt.xml" 1.1 3 CV.cvHaarFlagNone (CvSize 20 20) + +eyeDetect :: Processor.IOProcessor PImage [CvRect] +eyeDetect = haarDetect "/usr/share/opencv/haarcascades/haarcascade_eye.xml" 1.1 3 CV.cvHaarFlagNone (CvSize 20 20) + +faceRects = (id &&& faceDetect) >>> drawRects +eyeRects = (id &&& eyeDetect) >>> drawRects + +start = captureDev >>> resizer --< (faceRects *** eyeRects) >>> (window 0 *** window 1) + +-- Detecting faces and eyes through a camera stream +main :: IO () +main = runTillKeyPressed start diff --git a/Ch10/Code07_cam/Makefile b/Ch10/Code07_cam/Makefile new file mode 100644 index 0000000..63937c2 --- /dev/null +++ b/Ch10/Code07_cam/Makefile @@ -0,0 +1,5 @@ +default: + cabal install --bindir=./ + +clean: + rm -rf dist Setup.hs Code1007 *~ diff --git a/Ch10/Code08_cam/Code1008.cabal b/Ch10/Code08_cam/Code1008.cabal new file mode 100644 index 0000000..a692f7b --- /dev/null +++ b/Ch10/Code08_cam/Code1008.cabal @@ -0,0 +1,25 @@ +-- Initial Code1008.cabal generated by cabal init. For further +-- documentation, see http://haskell.org/cabal/users-guide/ + +name: Code1008 +version: 0.1.0.0 +synopsis: Template matching. +-- description: +homepage: haskelldata.com +license: GPL-2 +license-file: ../LICENSE +author: Nishant Shukla +maintainer: nick722@gmail.com +-- copyright: +category: Graphics +build-type: Simple +-- extra-source-files: +cabal-version: >=1.10 + +executable Code1008 + main-is: Main.hs + -- other-modules: + -- other-extensions: + build-depends: base >=4.6 && <4.7, CV >=0.3 && <0.4 + -- hs-source-dirs: + default-language: Haskell2010 \ No newline at end of file diff --git a/Ch10/Code08_cam/Main.hs b/Ch10/Code08_cam/Main.hs new file mode 100644 index 0000000..7daf295 --- /dev/null +++ b/Ch10/Code08_cam/Main.hs @@ -0,0 +1,26 @@ +{-#LANGUAGE ScopedTypeVariables#-} +module Main where +import CV.Image (loadImage, rgbToGray, getSize) +import CV.Video (captureFromCam, streamFromVideo) +import Utils.Stream (runStream_, takeWhileS, sideEffect) +import CV.HighGUI (showImage, waitKey) +import CV.TemplateMatching (simpleTemplateMatch, MatchType(..)) +import CV.ImageOp ((<#)) +import CV.Drawing (circleOp, ShapeStyle(..)) + +-- Streaming camera frames for template matching +main = do + Just t <- loadImage "lena.jpg" + Just c <- captureFromCam 0 + runStream_ . sideEffect (process t) . + takeWhileS (\_ -> True) $ streamFromVideo c + +process t img = do + let gray = rgbToGray img + let ((mx, my), _) = simpleTemplateMatch CCOEFF_NORMED gray t + let circleSize = (fst (getSize t)) `div` 2 + let circleCenter = (mx + circleSize, my + circleSize) + showImage "test" (img <# circleOp (0,0,0) + circleCenter circleSize (Stroked 3)) + waitKey 100 + return () diff --git a/Ch10/Code08_cam/Makefile b/Ch10/Code08_cam/Makefile new file mode 100644 index 0000000..db3a982 --- /dev/null +++ b/Ch10/Code08_cam/Makefile @@ -0,0 +1,5 @@ +default: + cabal install --bindir=./ + +clean: + rm -rf dist Setup.hs Code1008 *~ diff --git a/Ch10/Code08_cam/lena.jpg b/Ch10/Code08_cam/lena.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5beb3f835bf6addad18748fed314885b3896ca8c GIT binary patch literal 37868 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 eI`&`M#OSg*zCm~J6*dw8v1gS7k- + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/Ch10/README.md b/Ch10/README.md index 3389e4f..2de6a49 100644 --- a/Ch10/README.md +++ b/Ch10/README.md @@ -6,8 +6,17 @@ Refer to the book for step-by-step explanations.

-# How to use +# Recipes: +* **Code01**: Streaming Twitter for real-time sentiment analysis +* **Code02**: Reading IRC chat room messages +* **Code03**: Responding to IRC messages +* **Code04**: Polling a web server for the latest updates +* **Code05**: Detecting real-time file directory changes +* **Code06**: Communicating in real time through sockets +* **Code07**: Detecting faces and eyes through a camera stream +* **Code08**: Streaming camera frames for template matching +# How to use ### Setting up the environment Install the [Haskell Platform](http://www.haskell.org/platform/).