事情起因
同组的队友说他已经把图像转成内容为(01)*的文本文件,要我用除Java以外的语言接收这个文本文件进行去噪,就想用Haskell试试。
问题描述
对于一个二色(用{-1,+1}表示)加噪图像进行去噪处理。
理论基础
基于Graph-cu
t得出下列能量计算式。
xi为去噪图像的像素点,yi为加噪图像的加噪点。我们的目标是让上式所得的能量最低。
基于Iterated conditional models,对于每个i,我们将xi = yi,然后扫描所有xi,将xi置为-1和+1两种情况,将能量更低的情况作为新的去噪图像继续扫描。
函数构思
函数列表:
将(01)*串变成{+1,-1}的数组:stringToInt :: String -> [Int]
同理需要:intToString :: [Int] -> String
去噪总函数:deNoise :: ([Int], [Int]) -> [Int] -> [Int]
选择低能量:selectLowerEnergy :: ([Int], [Int], [Int]) -> [Int] -> ([Int], [Int])
计算能量:evaluateEnergy :: [Int] -> [Int] -> (Int, Int, Int) -> Int
计算能量:evaluateEnergy :: [Int] -> [Int] -> (Int, Int, Int) -> Int
效率
由于每次计算能量都要重算整个图像,计算能量的时间复杂度为O(n*n) + O(n*n*logn
) + O(n*n)
扫描整个图像的时间复杂度为O(n*n)
故总的时间复杂度为O(n^4 * logn)
可见这段代码的效率还有待提高
源代码
import System.IO
import Data.List
main = do
noiseString <- readFile "noise.txt"
let numList = stringToInt noiseString
newNumList = deNoise ([], numList) numList
newNoiseString = intToString newNumList
writeFile "deNoise.txt" newNoiseString
--去噪函数,利用元组输入xs便于迭代更新xs
deNoise :: ([Int], [Int]) -> [Int] -> [Int]
deNoise (xs, []) ys = xs
deNoise (xs1, x:xs2) ys = deNoise (selectLowerEnergy (xs1, [x], xs2) ys) ys
--选择低能量xs
selectLowerEnergy :: ([Int], [Int], [Int]) -> [Int] -> ([Int], [Int])
selectLowerEnergy (xs1, _, xs2) ys
| e1 < e2 = (xs1++[1], xs2)
| otherwise = (xs1++[-1], xs2)
where e1 = evaluateEnergy s1 ys (1, 1, 2)
e2 = evaluateEnergy s2 ys (1, 1, 2)
s1 = xs1 ++ [1] ++ xs2
s2 = xs1 ++ [-1] ++ xs2
--默认输入64x64的图像
--e2的计算输要将数组转成二维数组,然后对相邻行进行求积求和
--翻转之后再求积求和,相加之后就可以得出e2
evaluateEnergy :: [Int] -> [Int] -> (Int, Int, Int) -> Int
evaluateEnergy xs ys (h, beta, eta) = h * e1 - beta * e2 - eta * e3
where e1 = sum xs
matrix = toMatrix 64 xs
e2 = (sumOfMatrixRow matrix) + (sumOfMatrixRow $ transpose matrix)
e3 = sum $ zipWith (*) xs ys
--dim为维数,正确的说是每一行的长度
--不需要确定行数。
toMatrix :: Int -> [Int] -> [[Int]]
toMatrix _ [] = []
toMatrix dim xs = y:(toMatrix dim ys)
where (y,ys) = splitAt dim xs
sumOfMatrixRow :: [[Int]] -> Int
sumOfMatrixRow (xs:[]) = 0
sumOfMatrixRow (xs:ys:xss) = sumOfMatrixRow (ys:xss) + (sum $ zipWith (*) xs ys)
stringToInt :: String -> [Int]
stringToInt = map checkString
where checkString '0' = -1
checkString '1' = 1
checkString _ = 0
intToString :: [Int] -> String
intToString = map checkInt
where checkInt 1 = '1'
checkInt (-1) = '0'
checkInt _ = '2'
计算能量:evaluateEnergy :: [Int] -> [Int] -> (Int, Int, Int) -> Int