基于Iterated conditional models和Graph-cut的黑白图像去噪(Haskell语言实现)
事情起因
同组的队友说他已经把图像转成内容为(01)*的文本文件,要我用除Java以外的语言接收这个文本文件进行去噪,就想用Haskell试试。
问题描述
对于一个二色(用{-1,+1}表示)加噪图像进行去噪处理。
理论基础
基于Graph-cut得出下列能量计算式。
xi为去噪图像的像素点,yi为加噪图像的加噪点。我们的目标是让上式所得的能量最低。
基于Iterated conditional models,对于每个i,我们将xi = yi,然后扫描所有xi,将xi置为-1和+1两种情况,将能量更低的情况作为新的去噪图像继续扫描。
函数构思
函数 | 功能 |
stringToInt :: String -> [Int] | 将(01)*串变成{+1,-1}的数组 |
intToString :: [Int] -> String | 将{+1,-1}串变成(01)*的数组 |
deNoise :: ([Int], [Int]) -> [Int] -> [Int] | 去噪总函数 |
selectLowerEnergy :: ([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)
n为图像的边长,可见这段代码的效率还有待提高
源代码
1 import System.IO 2 import Data.List 3 4 5 main = do 6 noiseString <- readFile "noise.txt" 7 let numList = stringToInt noiseString 8 newNumList = deNoise ([], numList) numList 9 newNoiseString = intToString newNumList 10 writeFile "deNoise.txt" newNoiseString 11 12 13 --去噪函数,利用元组输入xs便于迭代更新xs 14 deNoise :: ([Int], [Int]) -> [Int] -> [Int] 15 deNoise (xs, []) ys = xs 16 deNoise (xs1, x:xs2) ys = deNoise (selectLowerEnergy (xs1, [x], xs2) ys) ys 17 18 19 --选择低能量xs 20 selectLowerEnergy :: ([Int], [Int], [Int]) -> [Int] -> ([Int], [Int]) 21 selectLowerEnergy (xs1, _, xs2) ys 22 | e1 < e2 = (xs1++[1], xs2) 23 | otherwise = (xs1++[-1], xs2) 24 where e1 = evaluateEnergy s1 ys (1, 1, 2) 25 e2 = evaluateEnergy s2 ys (1, 1, 2) 26 s1 = xs1 ++ [1] ++ xs2 27 s2 = xs1 ++ [-1] ++ xs2 28 29 30 --默认输入64x64的图像 31 --e2的计算输要将数组转成二维数组,然后对相邻行进行求积求和 32 --翻转之后再求积求和,相加之后就可以得出e2 33 evaluateEnergy :: [Int] -> [Int] -> (Int, Int, Int) -> Int 34 evaluateEnergy xs ys (h, beta, eta) = h * e1 - beta * e2 - eta * e3 35 where e1 = sum xs 36 matrix = toMatrix 64 xs 37 e2 = (sumOfMatrixRow matrix) + (sumOfMatrixRow $ transpose matrix) 38 e3 = sum $ zipWith (*) xs ys 39 40 41 --dim为维数,正确的说是每一行的长度 42 --不需要确定行数。 43 toMatrix :: Int -> [Int] -> [[Int]] 44 toMatrix _ [] = [] 45 toMatrix dim xs = y:(toMatrix dim ys) 46 where (y,ys) = splitAt dim xs 47 48 49 sumOfMatrixRow :: [[Int]] -> Int 50 sumOfMatrixRow (xs:[]) = 0 51 sumOfMatrixRow (xs:ys:xss) = sumOfMatrixRow (ys:xss) + (sum $ zipWith (*) xs ys) 52 53 54 stringToInt :: String -> [Int] 55 stringToInt = map checkString 56 where checkString '0' = -1 57 checkString '1' = 1 58 checkString _ = 0 59 60 61 intToString :: [Int] -> String 62 intToString = map checkInt 63 where checkInt 1 = '1' 64 checkInt (-1) = '0' 65 checkInt _ = '2' 66