Advertisement
SkullCoder

ImageLib

Jan 2nd, 2019
449
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
OCaml 11.69 KB | None | 0 0
  1. fun load _ = (); (* for SmlNJ *)
  2.  
  3. (* for MOSML *)
  4. load "Vector";
  5. load "Int";
  6. load "Real";
  7. load "String";
  8. load "Math";
  9. load "Random";
  10.  
  11. type grayimg = int vector vector
  12. type img = (int*int*int) vector vector
  13.  
  14.  
  15.  
  16. (* File Management *)
  17.  
  18. fun toBytes 0 i = nil
  19.   | toBytes n i = (i mod 256) :: toBytes (n-1) (i div 256)
  20.  
  21. fun toByteString n = implode o (map Char.chr) o (toBytes n)
  22. fun apply f = Vector.map (Vector.app f)
  23. fun applyVerbose f = Vector.mapi (fn (y,a) => (print(Int.toString(y)^"\n");Vector.app f a))
  24.  
  25. fun pixelToString (a,b,c) = toByteString 1 c ^ toByteString 1 b ^ toByteString 1 a
  26. fun grayPixelToString a = toByteString 1 a ^ toByteString 1 a ^ toByteString 1 a
  27.  
  28. fun saveBMP filename img =
  29.     let
  30.         val h = Vector.length img
  31.         val w = Vector.length (Vector.sub(img,0))
  32.         val fd = TextIO.openOut filename
  33.     in
  34.         if (w*3) mod 4 <> 0 then raise Domain else
  35.         (
  36.             TextIO.output (fd, "BM");(* BM *)
  37.             TextIO.output (fd, toByteString 4 (w*h*3+54));(* Size *)
  38.             TextIO.output (fd, "0000"); (* 0000 *)
  39.             TextIO.output (fd, toByteString 4 54);(* 54 *)
  40.             TextIO.output (fd, toByteString 4 40);(* 40 *)
  41.             TextIO.output (fd, toByteString 4 w);(* width *)
  42.             TextIO.output (fd, toByteString 4 (~h));(* height *)
  43.             TextIO.output (fd, toByteString 2 1); (* 00 *)
  44.             TextIO.output (fd, toByteString 2 24);(* colordepth *)
  45.             TextIO.output (fd, toByteString 4 0);(* compression *)
  46.             TextIO.output (fd, toByteString 4 0);(* size *)
  47.             TextIO.output (fd, toByteString 4 0);(* dpi x *)
  48.             TextIO.output (fd, toByteString 4 0);(* dpi y *)
  49.             TextIO.output (fd, toByteString 4 0);(* colortable *)
  50.             TextIO.output (fd, toByteString 4 0);(* count *)
  51.             apply (fn x => TextIO.output (fd, pixelToString x)) img; (* image *)
  52.             TextIO.closeOut fd
  53.         )
  54.     end
  55.  
  56. exception InvalidOS
  57. fun savePNG filename img = let val bmpFilename = "tmp.bmp" in (saveBMP bmpFilename img;
  58.     if OS.Process.system(String.concatWith " " ["convert",bmpFilename,filename]) = 0 then
  59.      (OS.Process.system(String.concat["rm ",bmpFilename]);())
  60.     else raise InvalidOS
  61.     ) end
  62.  
  63.  
  64.  
  65. (* usual Helper Procedure *)
  66.  
  67. fun iter n s f =
  68.     if n<1 then s else iter (n-1) (f s) f
  69. fun newton (a:real, x:real, n:int) : real =
  70.     if n<1 then a else newton (0.5*(a+x/a), x, n-1)
  71. fun sqrt (x:real) = newton (x/2.0, x , 5)
  72. fun sign x = if x>0.0 then 1.0 else (if x<0.0 then ~1.0 else 0.0)
  73. fun first (s:int) (p:int->bool) : int =
  74.     if p s then s else first (s+1) p
  75. fun first' s a p f =
  76.     if p (s,a) then (s,a) else first' (s+1) (f(s,a)) p f
  77.  
  78.  
  79.  
  80. (* usual Helper Math *)
  81.  
  82. fun abs x = if x<0.0 then ~x else x
  83. val rnd = Real.floor
  84.  
  85. fun toReal (x,y) = (Real.fromInt x, Real.fromInt y)
  86. fun fromReal (x,y) = (rnd x, rnd y)
  87.  
  88.  
  89.  
  90. (* Random *)
  91.  
  92. val rand=Random.rand(1,0)
  93. fun randomReal () = Random.randReal(rand)
  94.  
  95.  
  96.  
  97. (* Image Manipulation *)
  98.  
  99. fun createImg w h f = Vector.tabulate(h,fn y => Vector.tabulate(w, fn x => f(x,y)))
  100.  
  101. fun getPixel img x y = Vector.sub(Vector.sub(img,y),x)
  102.  
  103. fun setPixel img f x y =
  104.     let
  105.         val row = Vector.sub(img,y)
  106.     in
  107.         Vector.update(img,y,Vector.update(row,x,f (Vector.sub(row,x))))
  108.     end
  109.  
  110. fun setPixel2 img f (x,y) =
  111.     let
  112.         val y = Int.min(Vector.length img-1,Int.max(0,y))
  113.         val row = Vector.sub(img,y)
  114.         val x = Int.min(Vector.length row-1,Int.max(0,x))
  115.     in
  116.         Vector.update(img,y,Vector.update(row,x,f (Vector.sub(row,x))))
  117.     end
  118.  
  119. fun imgMap f = Vector.mapi (fn (y,v) => Vector.mapi (
  120.         fn (x,a) => f(x,y,a)) v)
  121.  
  122. fun imageMap f = Vector.map (fn (v) => Vector.map (
  123.         fn (a) => f a) v)
  124.  
  125. fun stretch (xs,ys) img = imgMap (fn (x,y,a) => getPixel img (rnd(Real.fromInt(x)*xs)) (rnd(Real.fromInt(y)*ys))) img
  126.  
  127. fun crop (w,h) img = createImg w h (fn (x,y) => getPixel img x y)
  128.  
  129. fun zipWith f img img2 = imgMap (fn (x,y,a) => f(a,getPixel img2 x y)) img
  130.  
  131.  
  132.  
  133. (* ImageConversion *)
  134.  
  135. val toGrayImage = Vector.map (Vector.map (fn (a,b,c) => (a+b+c) div 3))
  136. val toColorImage = Vector.map (Vector.map (fn g:int => (g,g,g)))
  137. fun toColoredImage (rm,gm,bm) = Vector.map (Vector.map (fn g:int => (g*rm,g*gm,g*bm)))
  138.  
  139.  
  140.  
  141. (* Image Math *)
  142.  
  143. val findMax = Vector.foldl (fn (v,a) => Real.max(a,Vector.foldl Real.max Real.negInf v)) Real.negInf
  144. fun normalize img = case findMax img of max => imgMap (fn (_,_,a) => rnd(255.0*a/max)) img
  145. fun findMaxInt x = Vector.foldl (fn (v,a) => Int.max(a,Vector.foldl Int.max (Vector.sub(v,0)) v)) (Vector.sub(Vector.sub(x,0),0)) x
  146. val findMin = Vector.foldl (fn (v,a) => Real.min(a,Vector.foldl Real.min Real.posInf v)) Real.posInf
  147. fun normalize2 img = let
  148.         val max = findMax img
  149.         val min = findMin img
  150.     in
  151.         imgMap (fn (_,_,a) => rnd(255.0*(a-min)/(max-min))) img
  152.     end
  153.  
  154. val toRealImage = imgMap (Real.fromInt o #3)
  155.  
  156.  
  157.  
  158. (* Color Functions *)
  159.  
  160. fun hsvToRgb (h,s,v) =
  161.     let
  162.         val h'=Real.rem(h,360.0)/60.0
  163.         val c=s*v
  164.         val x=c*(1.0-abs(Real.rem(h', 2.0) -1.0))
  165.         val m=v-c
  166.     in
  167.         case (case rnd(h') of
  168.               0 => (c,x,0.0)
  169.             | 1 => (x,c,0.0)
  170.             | 2 => (0.0,c,x)
  171.             | 3 => (x,0.0,c)
  172.             | 4 => (x,0.0,c)
  173.             | _ => (c,0.0,x)) of
  174.         (r,g,b) => (rnd(255.0*(r+m)),
  175.             rnd(255.0*(g+m)),
  176.             rnd(255.0*(b+m)))
  177.     end
  178.  
  179. fun toColorHSVImage s v = Vector.map (Vector.map (fn h => hsvToRgb(h,s,v)))
  180. fun toColorHSVImage2 s v = Vector.map (Vector.map (fn h => if h < 0.01 then (0,0,0) else (hsvToRgb(h,s,v))))
  181.  
  182. fun lerp (a,b) p = a*p+b*(1.0-p)
  183. fun lerpInt a b p = rnd(lerp(Real.fromInt a,Real.fromInt b) p)
  184. fun lerpColor ((r1,g1,b1),(r2,g2,b2),p) = (lerpInt r1 r2 p,lerpInt g1 g2 p,lerpInt b1 b2 p)
  185.  
  186. fun colorGradient v =
  187.             let
  188.                 val len = Vector.length v
  189.             in
  190.                 imgMap (fn (_,_,a) => let
  191.                     val a=Int.min(a,255)
  192.                     val p = Real.rem(Real.fromInt(len-1)*Real.fromInt(a)/256.0,1.0)
  193.                     val ind = (len-1)*a div 256
  194.                 in
  195.                     lerpColor(Vector.sub(v,ind),Vector.sub(v,ind+1),1.0-p)
  196.                 end)
  197.             end
  198.  
  199. val greenGradient = #[(0,0,0),(255,255,255),(0,100,0),(0,255,0),(0,255,100),(255,255,255)]
  200. val blueGradient = #[(0,0,0),(0,100,100),(0,100,255),(0,0,255),(200,200,255)]
  201. val flameGradient = #[(0,0,0),(255,0,0),(255,255,0)]
  202. val rgbGradient = #[(0,0,0),(255,0,0),(0,255,0),(0,0,255)]
  203. val landGradient = #[(255,255,255),(0,255,0),(255,255,0),(0,0,255),(0,0,0)]
  204. val seaGradient = #[(0,0,100),(0,80,200),(0,150,200),(150,200,200)]
  205.  
  206.  
  207.  
  208. (* TextOutput *)
  209.  
  210. fun printVec pf = Vector.map (fn v => (Vector.map (fn g => (print o pf) g) v;print "\n"))
  211. val printGrayImg = printVec ((fn a => a^"\t ") o Int.toString)
  212. val printImg = printVec (fn (a,b,c) => Int.toString a ^ Int.toString b ^ Int.toString c)
  213. fun toStringVec f = (String.concatWith "\n") o (Vector.foldr (fn (x, l) => ((Vector.foldr (fn (x,a) => x^a) "") o (Vector.map f)) x::l) nil)
  214. val printGrayImg = printVec ((fn a => a^"\t ") o Int.toString)
  215. val toStringGrayImg = toStringVec ((fn a => a^"\t ") o Int.toString)
  216. val printImg = printVec (fn (a,b,c) => Int.toString a ^ Int.toString b ^ Int.toString c)
  217.  
  218.  
  219.  
  220. (* Complex Functions *)
  221.  
  222. fun angle (r,i) = Math.atan2(i,r)
  223. val arg=angle
  224. fun radius (r,i) = Math.sqrt(r*r+i*i)
  225. fun fromPolar (ang,rad) = (rad*Math.cos(ang),rad*Math.sin(ang))
  226. fun toPolar (c as (r,i)) = (angle c,radius c)
  227.  
  228. fun restrict (a,b) (c as (r,i)) = fromPolar(Real.min(b,Real.max(a,angle c)),radius c)
  229. fun toComplex (w,h) (x,y) = let val w2=Real.fromInt(w)/2.0 val h2=Real.fromInt(h)/2.0 in (x/w2-1.0,y/h2-1.0) end
  230. fun fromComplex (w,h) (x,y) = let val w2=Real.fromInt(w)/2.0 val h2=Real.fromInt(h)/2.0 in (x*w2+w2,y*h2+h2) end
  231.  
  232. fun complexToHsv (r,i) = let
  233.         val r=Real.max(Real.min(2.0,r),~2.0)
  234.         val i=Real.max(Real.min(2.0,i),~2.0)
  235.         val rad = Real.max(Real.min(0.0,2.0/Math.sqrt(r*r+i*i)),1.0)
  236.         val phi = Math.atan2(r,i)
  237.     in
  238.         (phi*180.0/Math.pi+180.0,rad,rad)
  239.     end
  240.  
  241. fun modifyAngleReal (bounds as (w,h)) f pos =
  242.     let
  243.         val c = toComplex bounds pos
  244.         val ang = angle c
  245.         val rad = radius c
  246.     in
  247.         ((fromComplex bounds) o fromPolar) (f ang,rad)
  248.     end
  249.  
  250. fun modifyAngle (bounds as (w,h)) f = fromReal o (modifyAngleReal bounds f) o (toReal)
  251.  
  252.  
  253.  
  254. (* Advance Pixeldraw *)
  255.  
  256. fun drawTimes img _ 0 _ _ = img
  257.   | drawTimes img f n cf pos = drawTimes (setPixel2 img f pos) f (n-1) cf (cf pos)
  258.  
  259. fun rotatePixel bounds n img f pos =
  260.     let
  261.         val c = toComplex bounds (toReal pos)
  262.         val ang = angle c
  263.         val rad = radius c
  264.     in
  265.         drawTimes img f n (modifyAngle bounds (fn ang => ang+2.0*Math.pi/Real.fromInt(n))) pos
  266.     end
  267.  
  268. fun setMirrorPixel bounds draw img f (p as (x,y)) =
  269.     let
  270.         val (x2,y2) = modifyAngle bounds op~ p
  271.         val img = draw img f (x,y)
  272.         val img = draw img f (x2,y2) (* no reference => ugly *)
  273.     in
  274.         img
  275.     end
  276.  
  277.  
  278.  
  279. (* for Newton (Expression+Derivation) *)
  280.  
  281. exception Unbound of string
  282. val empty = fn x => raise Unbound x
  283. fun update env id v var =
  284.   if var = id then v else env var
  285. datatype exp = C of real*real | V of string | A of exp * exp | M of exp * exp | D of exp * exp | F of string * exp
  286. fun S (a,b) = A(a,M(C(~1.0,0.0),b))
  287. fun P (a,0) = C(1.0,0.0)
  288.   | P (a,1) = a
  289.   | P (a,n) = M(a,P(a,n-1))
  290. fun I(x) = C(x,0.0)
  291. fun diff x (C _)        = C (0.0,0.0)
  292.   | diff x (V v)        = if x = v then C (1.0,0.0) else C (0.0,0.0)
  293.   | diff x (A (a,b))    = A(diff x a, diff x b)
  294.   | diff x (M (a,b))    = A(M(diff x a, b),M(a,diff x b))
  295.   | diff x (D (a,b))    = D(S(M(diff x a, b),M(a,diff x b)),M(b,b))
  296.   | diff x (F (s,a))    = case diff x a of e =>
  297.                             M(e,case s of
  298.                                   "abs" => D(a,F("abs",a))
  299.                                 | "exp" => F("exp",a)
  300.                                 | "ln" => D(C(1.0,0.0),a)
  301.                                 | "cos" => M(C(~1.0,0.0),F("sin",a))
  302.                                 | "sin" => F("cos",a)
  303.                              )
  304.  
  305. fun eval f (C c)        = c
  306.   | eval f (V v)        = f v
  307.   | eval f (A (a,b))    = (case (eval f a, eval f b) of
  308.                             ((r1,i1),(r2,i2)) => (r1+r2,i1+i2))
  309.   | eval f (M (a,b))    = (case (eval f a, eval f b) of
  310.                             ((r1,i1),(r2,i2)) => (r1*r2-i1*i2,r1*i2+r2*i1))
  311.   | eval f (D (a,b))    = let
  312.                             val (fx,fy)=eval f a
  313.                             val (fx',fy')=eval f b
  314.                             val rez = 1.0/(fx'*fx'+fy'*fy')
  315.                           in
  316.                             (rez*(fx*fx'+fy*fy'),
  317.                                     rez*(fy*fx'-fx*fy'))
  318.                           end
  319.   | eval f (F(s,a))     = (case eval f a of (r,i) => case s of
  320.                               "abs" => (Math.sqrt(r*r+i*i),0.0)
  321.                             | "exp" => (Math.exp(r)*Math.cos(i),Math.exp(r)*Math.sin(i))
  322.                             | "ln" => (Math.ln(Math.sqrt(r*r+i*i)), arg(r,i))
  323.                             | "sin" => (Math.sin(r)*Math.cosh(i),Math.cos(r)*Math.sinh(i))
  324.                             | "cos" => (Math.cos(r)*Math.cosh(i),~ (Math.sin r)*Math.sinh(i))
  325.                           )
  326.  
  327.  
  328.  
  329. (* Herausforderungen: *)
  330. (*
  331. Programmieren Sie folgende Fraktale:
  332. Hopalong
  333. Mandelbrot
  334. Burning Ship
  335. Newton Fractal
  336. Flame Fractal
  337. Perlin Noise (+ landscape, clouds, fire, wood, marble)
  338. DLA with mirror axis and 6-fold rotation
  339. IFS Fractals (koch, sierpinski, far)n
  340.  
  341. none of these is longer than 20 lines of code
  342. *)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement