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