raphaelj / friday Goto Github PK
View Code? Open in Web Editor NEWFast image IO and transformations.
Home Page: https://hackage.haskell.org/package/friday
License: GNU Lesser General Public License v3.0
Fast image IO and transformations.
Home Page: https://hackage.haskell.org/package/friday
License: GNU Lesser General Public License v3.0
In cases where artifacts are critical to avoid bicubic interpolation would be nice to have.
Would you mind adding this package to Stackage? The instructions can be found here.
I'm fairly new to haskell (~1 year) and the only bigger lib I've used for some time now is Diagrams.
Now I was looking into basic image processing and wanted to do stuff like image noise reduction by calculating the average of a number of images.
The functions fromFunction
and map
are fairly basic, so I tried a few hacks like:
map2 :: (I.Image src1, I.Image src2, I.FromFunction res)
=> Size
-> (I.ImagePixel src1 -> I.ImagePixel src2 -> I.FromFunctionPixel res)
-> src1
-> src2
-> res
map2 s f img1 img2 =
I.fromFunction s $ \pix ->
f (img1 `I.index` pix) (img2 `I.index` pix)
foldImg :: (I.Image i, I.FromFunction i)
=> Size
-> (I.ImagePixel i -> I.ImagePixel i -> I.FromFunctionPixel i)
-> [i]
-> i
foldImg s f = foldl1 (map2 s f)
Maybe I missed something, but I think this library could benefit from a more powerful interface.
SCW feature extraction has proven useful to me in a few situations.
That would give a very attractive all-in-Haskell solution for the basic image processing needs of most web applications.
No need to install IMagick or similar, or a C library -- just cabal install
all the way :)
I went ahead and added base >= 4.8
constraints:
Configuring component lib from friday-0.2.3.1
Preprocessing library friday-0.2.3.1...
[ 1 of 28] Compiling Vision.Primitive.Shape ( src/Vision/Primitive/Shape.hs, /tmp/matrix-worker/1482012292/dist-newstyle/build/x86_64-linux/ghc-7.8.4/friday-0.2.3.1/build/Vision/Primitive/Shape.o )
src/Vision/Primitive/Shape.hs:87:40:
Could not deduce (Functor m) arising from a use of ‘fmap’
from the context (Control.Monad.Primitive.PrimMonad m)
bound by the type signature for
basicUnsafeNew :: Control.Monad.Primitive.PrimMonad m =>
Int -> m (VU.MVector (Control.Monad.Primitive.PrimState m) Z)
at src/Vision/Primitive/Shape.hs:87:3-16
Possible fix:
add (Functor m) to the context of
the type signature for
basicUnsafeNew :: Control.Monad.Primitive.PrimMonad m =>
Int -> m (VU.MVector (Control.Monad.Primitive.PrimState m) Z)
In the expression: MV_Z `fmap` basicUnsafeNew i
In an equation for ‘basicUnsafeNew’:
basicUnsafeNew i = MV_Z `fmap` basicUnsafeNew i
In the instance declaration for ‘MVector VU.MVector Z’
src/Vision/Primitive/Shape.hs:94:38:
Could not deduce (Functor m) arising from a use of ‘fmap’
from the context (Control.Monad.Primitive.PrimMonad m)
bound by the type signature for
basicUnsafeFreeze :: Control.Monad.Primitive.PrimMonad m =>
VG.Mutable VU.Vector (Control.Monad.Primitive.PrimState m) Z
-> m (VU.Vector Z)
at src/Vision/Primitive/Shape.hs:94:3-19
Possible fix:
add (Functor m) to the context of
the type signature for
basicUnsafeFreeze :: Control.Monad.Primitive.PrimMonad m =>
VG.Mutable VU.Vector (Control.Monad.Primitive.PrimState m) Z
-> m (VU.Vector Z)
In the expression: V_Z `fmap` VG.basicUnsafeFreeze v
In an equation for ‘basicUnsafeFreeze’:
basicUnsafeFreeze (MV_Z v) = V_Z `fmap` VG.basicUnsafeFreeze v
In the instance declaration for ‘VG.Vector VU.Vector Z’
src/Vision/Primitive/Shape.hs:95:39:
Could not deduce (Functor m) arising from a use of ‘fmap’
from the context (Control.Monad.Primitive.PrimMonad m)
bound by the type signature for
basicUnsafeThaw :: Control.Monad.Primitive.PrimMonad m =>
VU.Vector Z
-> m (VG.Mutable
VU.Vector (Control.Monad.Primitive.PrimState m) Z)
at src/Vision/Primitive/Shape.hs:95:3-17
Possible fix:
add (Functor m) to the context of
the type signature for
basicUnsafeThaw :: Control.Monad.Primitive.PrimMonad m =>
VU.Vector Z
-> m (VG.Mutable VU.Vector (Control.Monad.Primitive.PrimState m) Z)
In the expression: MV_Z `fmap` VG.basicUnsafeThaw v
In an equation for ‘basicUnsafeThaw’:
basicUnsafeThaw (V_Z v) = MV_Z `fmap` VG.basicUnsafeThaw v
In the instance declaration for ‘VG.Vector VU.Vector Z’
src/Vision/Primitive/Shape.hs:108:49:
Could not deduce (Functor m) arising from a use of ‘fmap’
from the context (Unbox t, Unbox h)
bound by the instance declaration
at src/Vision/Primitive/Shape.hs:104:10-58
or from (Control.Monad.Primitive.PrimMonad m)
bound by the type signature for
basicUnsafeRead :: Control.Monad.Primitive.PrimMonad m =>
VU.MVector (Control.Monad.Primitive.PrimState m) (t :. h)
-> Int -> m (t :. h)
at src/Vision/Primitive/Shape.hs:108:3-17
Possible fix:
add (Functor m) to the context of
the type signature for
basicUnsafeRead :: Control.Monad.Primitive.PrimMonad m =>
VU.MVector (Control.Monad.Primitive.PrimState m) (t :. h)
-> Int -> m (t :. h)
or the instance declaration
In the expression: pairToPoint `fmap` basicUnsafeRead v i
In an equation for ‘basicUnsafeRead’:
basicUnsafeRead (MV_Dim v) i
= pairToPoint `fmap` basicUnsafeRead v i
In the instance declaration for ‘MVector VU.MVector (t :. h)’
src/Vision/Primitive/Shape.hs:109:44:
Could not deduce (Functor m) arising from a use of ‘fmap’
from the context (Unbox t, Unbox h)
bound by the instance declaration
at src/Vision/Primitive/Shape.hs:104:10-58
or from (Control.Monad.Primitive.PrimMonad m)
bound by the type signature for
basicUnsafeNew :: Control.Monad.Primitive.PrimMonad m =>
Int
-> m (VU.MVector (Control.Monad.Primitive.PrimState m) (t :. h))
at src/Vision/Primitive/Shape.hs:109:3-16
Possible fix:
add (Functor m) to the context of
the type signature for
basicUnsafeNew :: Control.Monad.Primitive.PrimMonad m =>
Int
-> m (VU.MVector (Control.Monad.Primitive.PrimState m) (t :. h))
or the instance declaration
In the expression: MV_Dim `fmap` basicUnsafeNew i
In an equation for ‘basicUnsafeNew’:
basicUnsafeNew i = MV_Dim `fmap` basicUnsafeNew i
In the instance declaration for ‘MVector VU.MVector (t :. h)’
src/Vision/Primitive/Shape.hs:116:42:
Could not deduce (Functor m) arising from a use of ‘fmap’
from the context (MVector (VG.Mutable VU.Vector) (t :. h),
Unbox t,
Unbox h)
bound by the instance declaration
at src/Vision/Primitive/Shape.hs:113:10-59
or from (Control.Monad.Primitive.PrimMonad m)
bound by the type signature for
basicUnsafeFreeze :: Control.Monad.Primitive.PrimMonad m =>
VG.Mutable
VU.Vector (Control.Monad.Primitive.PrimState m) (t :. h)
-> m (VU.Vector (t :. h))
at src/Vision/Primitive/Shape.hs:116:3-19
Possible fix:
add (Functor m) to the context of
the type signature for
basicUnsafeFreeze :: Control.Monad.Primitive.PrimMonad m =>
VG.Mutable VU.Vector (Control.Monad.Primitive.PrimState m) (t :. h)
-> m (VU.Vector (t :. h))
or the instance declaration
In the expression: V_Dim `fmap` VG.basicUnsafeFreeze v
In an equation for ‘basicUnsafeFreeze’:
basicUnsafeFreeze (MV_Dim v) = V_Dim `fmap` VG.basicUnsafeFreeze v
In the instance declaration for ‘VG.Vector VU.Vector (t :. h)’
src/Vision/Primitive/Shape.hs:117:43:
Could not deduce (Functor m) arising from a use of ‘fmap’
from the context (MVector (VG.Mutable VU.Vector) (t :. h),
Unbox t,
Unbox h)
bound by the instance declaration
at src/Vision/Primitive/Shape.hs:113:10-59
or from (Control.Monad.Primitive.PrimMonad m)
bound by the type signature for
basicUnsafeThaw :: Control.Monad.Primitive.PrimMonad m =>
VU.Vector (t :. h)
-> m (VG.Mutable
VU.Vector
(Control.Monad.Primitive.PrimState m)
(t :. h))
at src/Vision/Primitive/Shape.hs:117:3-17
Possible fix:
add (Functor m) to the context of
the type signature for
basicUnsafeThaw :: Control.Monad.Primitive.PrimMonad m =>
VU.Vector (t :. h)
-> m (VG.Mutable
VU.Vector (Control.Monad.Primitive.PrimState m) (t :. h))
or the instance declaration
In the expression: MV_Dim `fmap` VG.basicUnsafeThaw v
In an equation for ‘basicUnsafeThaw’:
basicUnsafeThaw (V_Dim v) = MV_Dim `fmap` VG.basicUnsafeThaw v
In the instance declaration for ‘VG.Vector VU.Vector (t :. h)’
src/Vision/Primitive/Shape.hs:119:48:
Could not deduce (Functor m) arising from a use of ‘fmap’
from the context (MVector (VG.Mutable VU.Vector) (t :. h),
Unbox t,
Unbox h)
bound by the instance declaration
at src/Vision/Primitive/Shape.hs:113:10-59
or from (Monad m)
bound by the type signature for
basicUnsafeIndexM :: Monad m =>
VU.Vector (t :. h) -> Int -> m (t :. h)
at src/Vision/Primitive/Shape.hs:119:3-19
Possible fix:
add (Functor m) to the context of
the type signature for
basicUnsafeIndexM :: Monad m =>
VU.Vector (t :. h) -> Int -> m (t :. h)
or the instance declaration
In the expression: pairToPoint `fmap` VG.basicUnsafeIndexM v i
In an equation for ‘basicUnsafeIndexM’:
basicUnsafeIndexM (V_Dim v) i
= pairToPoint `fmap` VG.basicUnsafeIndexM v i
In the instance declaration for ‘VG.Vector VU.Vector (t :. h)
From the documentation it seems that Friday only supports 8bit per channel pixels. Is there a specific reason for this limitation?
The dependency between friday and DevIL will be removed in friday 0.2.
I/O functions will be provided by two separate packages, friday-devil and friday-juicypixels. Both will use a different I/O backend.
Add Stroke Width Transformation (SWT, googleable).
Add MSER - see http://www.cs.ubc.ca/~perfo/papers/forssen_cvpr07.pdf for a color method and for a grey scale see "Linear time maximally stable extremal regions" (no publicly available PDF afaict).
Hi, sorry if this is a simple question (I'm new to Haskell), but
I'm using Friday in an application for some simple
image operations (source).
Did I do something wrong to cause the following warning message when compiling? Full build info is available at https://travis-ci.org/bamos/augment/builds/62451721
match_co: needs more cases
friday-0.2.1.2:Vision.Image.Type.TFCo:R:ImagePixelManifest{tc r3AS}[0]
(Sym
(friday-0.2.1.2:Vision.Image.Type.TFCo:R:FromFunctionPixelManifest{tc r3B9}[0]
<friday-0.2.1.2:Vision.Image.RGB.Type.RGBPixel{tc ray}>_N))
cat /root/ocr/learn/learn/.stack-work/logs/friday-0.2.2.0.log
Configuring friday-0.2.2.0...
setup-Simple-Cabal-1.24.0.0-ghc-8.0.1: Encountered missing dependencies:
transformers >=0.3 && <0.5 && ==0.5.2.0
Hi,
thansk for sharing this very helpful library, samples and additional documentation. I'm new to Haskell and even new to this library (since after some research I think this is the more suitable for the thing I'm trying to do).
What I'm trying to do is translating this F# snippet for Random Art: http://fssnip.net/si.
To implement the function draw
at line 122, I must be able to:
Can I have some indications for accomplish this task and put me on right direction, if possible.
Thanks, Giacomo.
P.S.: finished the porting, I obviously share my work.
Hello! Just tried to use your library, but found one bad thing.
When I am writing something like
image :: Maybe Vision.Image.Storage.ImageType -> IO (Either StorageError StorageImage)
image = load "img.png"
Compiler is arguing that type constructor or class
Vision.Image.Storage.ImageType`` is not in scope. Please, export ImageType constructor from Storage.hsc.
BTW, it will be great to write something like
image :: IO (Either StorageError StorageImage)
image = load "img.png" PNG
Best wishes!
Some operations are more efficient with pre-multiplied RGBA. The conversion from RGBA to RGB assumes normal RGBA. I'm not sure what else does, but I bet a lot of code could be shared with a newtype.
The threshholding schemes as limited. Otsu threshholding is rather popular and hugely useful.
Contours are obviously a common mechanism to filter out unwanted artifacts based on facts such as size and dimensions. It would be nice if Friday included contours.
[1] Topological Structural Analysis of Digitized Binary Images by Border Following
cabal file says containers >= 0.4 && < 0.6
, but containers-0.6.0.1
works. See NixOS/nixpkgs#53432.
Sorry if this is a really banal question, but how can I draw simple shapes like rectangles and ovals using friday?
I have some problems with using masked images. I try to create a masked image from a normal one by using a fromFunction
and although the function itself compiles correctly, the application of the function yields a type error during compilation. I set up an equivalent example to illustrate the problem as my original function is a bit complex.
{-# LANGUAGE ScopedTypeVariables, TypeFamilies #-}
import Vision.Image
import Vision.Image.Storage.DevIL (Autodetect (..), load)
import Vision.Primitive
maskImage :: (Image i1, FromFunction i,
FromFunctionPixel i ~ Maybe (ImagePixel i1))
=> i1 -> i
maskImage img = fromFunction (shape img) maskPixel
where maskPixel p = Just $ img `index` p
main = do
io <- load Autodetect "../test.jpg"
case io of
Right (rgb :: RGB) -> do
let i' = maskImage rgb
print "Processed image"
The snippet yields the compilation error:
Main.hs:27:22:
Couldn't match type ‘FromFunctionPixel i0’ with ‘Maybe RGBPixel’
The type variable ‘i0’ is ambiguous
Expected type: Maybe (ImagePixel RGB)
Actual type: FromFunctionPixel i0
Relevant bindings include i' :: i0 (bound at Main.hs:27:17)
In the expression: maskImage rgb
In an equation for ‘i'’: i' = maskImage rgb
In the expression:
do { let i' = maskImage rgb;
print "Processed image" }
I also tried to create to unmask the image afterwards but this didn't work either. So how would one create a masked image with fromFunction
and destruct it later again? Or why doesn't my code compile correctly?
Background: I try to implement an image registration algorithm. One step of the algorithm is to interpolate the moved image at the points of the orgiinal image. As usually not all pixels of the original and the moved image overlap, a masked image was my data structure of choice to represent the result of this processing step.
Right now the functions blur
and gaussianBlur
in Vision.Image.Filter
impose the constraint Integral (ImagePixel src)
on the source image. However, this seems like an unnecessary constraint, which prevents one from, for example, blurring RGB or RGBA images. As I understand it, only addition and multiplication (by a scalar) operations are required for the pixels in order to do the convolution. One could sensibly define these operations for RGB and RGBA pixels. Maybe one could find or define a weaker typeclass to use as a constraint. Another option would be to have an intermediate function which would allow applying a filter component-wise.
During stackage build - skip tests during stackage build for now...
Images:
Conversions identities:
RGB to/from RGBA: [OK, passed 100 tests]
RGB to/from HSV: [OK, passed 100 tests]
Nearest-neighbor resize:
Grey: [OK, passed 100 tests]
RGBA: [OK, passed 100 tests]
RGB: [OK, passed 100 tests]
Horizontal flip is symetric:
Grey: [OK, passed 100 tests]
RGBA: [OK, passed 100 tests]
RGB: [OK, passed 100 tests]
Vertical flip is symetric:
Grey: [OK, passed 100 tests]
RGBA: [OK, passed 100 tests]
RGB: [OK, passed 100 tests]
Storable can roundtrip:
HSVPixel: [OK, passed 100 tests]
RGBPixel: [OK, passed 100 tests]
RGBAPixel: [OK, passed 100 tests]
Histograms:
Sum of bins equals the number of pixels: [OK, passed 100 tests]
The reduction of a 2D histogram gives the linear one.: [OK, passed 100 tests]
Resizing an histogram equals computing the smallest one.: [OK, passed 100 tests]
Cumulative histogram last bin equals original's sum: [OK, passed 100 tests]
Sum of an normalized histogram equals its size: [Failed]
*** Failed! Falsified (after 56 tests and 1 shrink):
0.5
Histogram {shape = Z :. 256, vector = [2588874,3760359,720623,88493,4765925,5214786,5380910,4626141,7918821,7446416,3783668,612062,4038479,7289132,1352859,3938527,5584479,5991528,3790679,1200055,7266956,6545644,8350728,6068,5911822,80365,5815394,8125574,1552477,8335872,1895585,2522358,8060338,1630125,8048094,7093748,7597141,7055715,7801283,5166461,3218385,1981296,5122197,5018516,3416502,5994008,4118715,3241077,518360,1226086,6173995,6581931,46094,7641231,5976849,3941604,7141244,3355327,425080,3985695,3981092,3873933,5876040,7122121,1830567,4239503,2460593,550065,5182582,5078395,3343104,8065700,1464768,8359395,7670869,8037245,5099700,1688109,1547349,7559159,3163754,4926297,7557779,2010891,286426,6590163,6801928,5160241,3242684,6813917,209062,2272301,4675019,6401681,3307865,1083211,2977412,1556369,5435021,1100831,2097022,2774904,6543436,775072,2815747,8313874,2255342,7961863,1752217,719501,5029710,972296,7493596,4910195,6976062,2933023,5634015,6137366,3574115,115922,7106588,3627508,383144,612447,2000036,8039585,1080023,2244073,2028864,1801145,1387871,6200798,4511775,3552288,8221410,6203173,6348402,345730,180126,703001,3561976,5401644,7454871,5123947,98963,2149606,4542793,5665716,3171722,4873149,2723720,2111702,3397665,534161,936519,1951229,4938908,835757,2239384,1509722,8384313,7575338,7262226,7188603,6687242,5462495,4964740,2498214,7811518,5866802,325808,1731506,6396768,7648192,7317367,4119641,5177891,4527696,8280161,4758006,506218,502291,4842982,3916590,2181837,6795571,2760904,3965138,3826875,1245163,4394544,8171111,6559579,3994998,3581740,3324137,5249736,3135469,7686012,3746885,5540664,626998,1227559,6233003,6200155,6514254,7908587,3388038,6394697,4497512,1935612,1930081,5635603,3937621,627211,8177324,6301896,1151766,7362785,5810577,3976349,1822969,945906,3436015,7360081,2905572,7804879,4769035,8328918,7274822,7925791,8002429,7719314,2394158,5364619,3419256,469723,3866018,3586478,166900,485407,7298211,2013272,2007539,5932427,1893309,7353049,5867370,5398137,672492,95457,4466659,1751082,644808,1630605,7451234]}
(used seed 1704976077533009389)
Comparing the same histogram returns a perfect correlation: [OK, passed 100 tests]
Comparing the same histogram returns a 0 chi-square value: [OK, passed 100 tests]
The intersection of an histogram with itself is the sum of its values.: [OK, passed 100 tests]
Comparing the same histogram returns a 0 EMD value: [OK, passed 100 tests]
Primitives:
Storable can roundtrip:
DIM0: [OK, passed 100 tests]
DIM1: [OK, passed 100 tests]
DIM2: [OK, passed 100 tests]
DIM3: [OK, passed 100 tests]
DIM4: [OK, passed 100 tests]
DIM5: [OK, passed 100 tests]
DIM6: [OK, passed 100 tests]
DIM7: [OK, passed 100 tests]
DIM8: [OK, passed 100 tests]
DIM9: [OK, passed 100 tests]
Properties Total
Passed 32 32
Failed 1 1
Total 33 33
Labeling the graph and providing units would make for a much stronger and informative statement. Keep up the good work!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.