Dplab
实验背景
本实验介绍了一种快速的横向或者纵向缩放图片的算法,采用了动态规划的思想,即通过找寻一张图中像素相近的一条条“缝”,然后去这条缝上的全部像素,这样的话删除多条缝即可达到缩放的目的。
实验代码
fun generateGradients ({width, height, data}:image):gradient seq seq =
let
fun square x = Math.pow (x,2.0)
fun delta (p:pixel,q:pixel) = square (#r q - #r p) + square (#g q - #g p) + square (#b q - #b p)
fun findPixel (i,j) = nth (nth data i) j
val $$ = findPixel
fun sigGre (i,j) = Math.sqrt (delta ($$ (i,j), $$ (i,j+1)) + delta ($$ (i,j), $$ (i+1,j)))
fun mapping (i:int,h:pixel seq) =
if i = (height-1) then map (fn _ => 0.0) h
else mapIdx (fn (j,x) => if j = width - 1 then 1000000.0 else sigGre (i,j)) h
val res = mapIdx (fn (i,h) => mapping (i,h)) data
in
res
end
fun findSeam (G:gradient seq seq) : int seq = let val height = length G val width = length (nth G 0) fun findGradient T (i,j) = nth (nth T i) j val $$ = findGradient fun findMin (x,y,z) = Real.min (x,Real.min(y,z)) fun sigSeam j x T = if j = 0 then x + Real.min (nth T j,nth T (j+1)) else if j = width - 1 then x + Real.min (nth T (j-1),nth T j) else x + findMin (nth T (j-1),nth T j,nth T (j+1)) fun findSeam' (G:gradient seq seq) (T:(int*real seq) list) (i:int) : (int*real seq) list= if i = 0 then T else let val PT = findSeam' G T (i-1) val tmp = (i,mapIdx (fn (j,x)=> sigSeam j x (#2 (List.nth (PT,0)))) (nth G i)) val T' = tmp::PT in T' end val seamT = inject (fromList (findSeam' G [(0,nth G 0)] (height - 1))) G fun Min S = reduce (fn ((i,x),(j,y)) => if x<y then (i,x) else (j,y)) (0,1000000.0) (mapIdx (fn (i,x) => (i,x)) S) fun generateSeam S G T i (idx,seam) = if i < 0 then S else if i = height-1 then generateSeam ((i,#1 (Min (nth T i)))::S) G T (i - 1) (Min (nth T i)) else let fun Compare ((i,x,u),(j,y,v),(k,z,w)) = if Real.== (findMin (x,y,z),x) then (i,x,u) else if Real.== (findMin (x,y,z),y) then (j,y,v) else (k,z,w) val pV = $$ G (i+1,idx) (*val _ = print (Real.toString ($$ T (i,idx+1)) ^ " ") val _ = print (Int.toString idx ^ " " ^ Int.toString i ^ " " ^ Int.toString width ^ " " ^Int.toString height ^ " ")*) val pS = if idx = 0 then ((i,$$ T (i,idx),idx),(i,$$ T (i,idx + 1),idx + 1),(0,10000000000.0,0)) else if idx = width - 1 then ((i,$$ T (i,idx),idx),(i,$$ T (i,idx - 1),idx - 1),(0,100000000000.0,0)) else ((i,$$ T (i,idx - 1),idx - 1),(i,$$ T (i,idx),idx),(i,$$ T (i,idx + 1),idx + 1)) val V = Compare pS (*val _ = print (Int.toString (length V) ^ "\n")*) val V' = case V of (i,_,x) => (i,x) in generateSeam (V'::S) G T (i-1) (#3 V,#2 V) end val injection = fromList (generateSeam ([]) G seamT (height-1) (0,0.0)) in inject injection (tabulate (fn _ => 0) height) end