转自:https://blog.csdn.net/hujingshuang/article/details/44257179,感谢原创作者!
前言
:
图像修复是一项非常有意义的研究工作,比如我们生活中的照片被污染,再比如名贵字画、国家文物壁画等珍贵物品被破坏,这些都需要图像修复工作来完成。
简介
:
整体变分(Total Variation)的方法最早是用来对受到噪声污染的图像进行降噪的,在这方面的应用最早是由L.Rudin和S.Osher等人在1992年提出的,2002年Chan等人把TV模型推广到图像修补中,并提出了基于TV模型的图像修补方法,同时说明了TV修补模型的缺点,进一步提出了CDD修补模型(curvature driven diffusions),此修补模型改正了TV修补模型的缺陷,对图像的修补具有很好的效果。
一、
TV模型介绍
如图所示:D区域是被污染区(待修复),E是D的邻域
下面直接给出TV模型的数学公式:
①
其中:u是图像中的像素点,λ为设定的参数
在该模型基础上,考虑到噪声的影响,边界E区域产生的噪声不能超过一定的范围;根据最佳猜测和贝叶斯理论,要求图像u在满足约束条件下使它的能量泛函最小,因此约束条件记做:公式②。根据拉格朗日乘数法,将①②方程转化成为一个求极值的方程,对其求导数并令其等于0,可得到如下方程:
其中:div代表散度(关于图像中的散度解释,可见此处:
在图像处理中,散度 div 具体的作用是什么?
)
由于图像是离散的数值,故可看做如下构成。其中:O为污染点,邻域B=(N,S,W,E),半像素邻域B’ =(n,s,w,e)。
因此,离散化后可得到表达式:
化简得到最终的表达式:
其中:λe(O)为中心O处的λ参数,与上λe一致;uo为O点修复后的像素,另一个为O点修复前的原始像素。将上式迭代,知道达到较好的修复效果。
到此,TV模型的理论推导已完成。接下来就是要编程实现其功能。
matlab源码实现:
-
img=double(imread(‘lena.jpg’));
-
mask=imread(‘mask.jpg’);
-
a1=find(mask>127);
-
b1=find(mask<=127);
-
mask(a1)=0;
-
mask(b1)=255;
-
[m n]=size(img);
-
for i=1:m
-
for j=1:n
-
if mask(i,j)==0
-
img(i,j)=0;
-
end
-
end
-
end
-
imshow(img,[]); %合成的需要修复的图像
-
-
lambda=0.2;
-
a=0.5;%避免分母为0
-
imgn=img;
-
for l=1:1500 %迭代次数
-
for i=2:m-1
-
for j=2:n-1
-
if mask(i,j)==0 %如果当前像素是被污染的像素,则进行处理
-
Un=sqrt((img(i,j)-img(i-1,j))^2+((img(i-1,j-1)-img(i-1,j+1))/2)^2);
-
Ue=sqrt((img(i,j)-img(i,j+1))^2+((img(i-1,j+1)-img(i+1,j+1))/2)^2);
-
Uw=sqrt((img(i,j)-img(i,j-1))^2+((img(i-1,j-1)-img(i+1,j-1))/2)^2);
-
Us=sqrt((img(i,j)-img(i+1,j))^2+((img(i+1,j-1)-img(i+1,j+1))/2)^2);
-
-
Wn=1/sqrt(Un^2+a^2);
-
We=1/sqrt(Ue^2+a^2);
-
Ww=1/sqrt(Uw^2+a^2);
-
Ws=1/sqrt(Us^2+a^2);
-
-
Hon=Wn/((Wn+We+Ww+Ws)+lambda);
-
Hoe=We/((Wn+We+Ww+Ws)+lambda);
-
How=Ww/((Wn+We+Ww+Ws)+lambda);
-
Hos=Ws/((Wn+We+Ww+Ws)+lambda);
-
-
Hoo=lambda/((Wn+We+Ww+Ws)+lambda);
-
value = Hon*img(i-1,j)+Hoe*img(i,j+1)+How*img(i,j-1)+Hos*img(i+1,j)+Hoo*img(i,j);
-
imgn(i,j)= value;
-
end
-
end
-
end
-
img=imgn;
-
end
-
figure;
-
imshow(img)
opencv源码实现:
-
#include <iostream>
-
#include <stdlib.h>
-
#include <cv.h>
-
#include <math.h>
-
#include <opencv2/highgui/highgui.hpp>
-
#include <opencv2/core/core.hpp>
-
#include <opencv2/imgproc/imgproc.hpp>
-
-
using
namespace
cv;
-
-
int
main(
void
)
-
{
-
//读取原始图像及掩模图像
-
IplImage *src_uint8 = cvLoadImage(
“src.jpg”
, CV_LOAD_IMAGE_GRAYSCALE);
-
IplImage *mask = cvLoadImage(
“mask.jpg”
, CV_LOAD_IMAGE_GRAYSCALE);
-
//合成需要修复的图像
-
int
M = mask->height;
-
int
N = mask->width;
-
int
i, j;
-
CvMat *src = cvCreateMat(M, N, CV_32FC1);
//存放浮点图像
-
cvConvert(src_uint8, src);
-
for
(i = 0; i < M; i++)
-
{
-
for
(j = 0; j < N; j++)
-
{
-
if
((mask->imageData + i * mask->widthStep)[j] < 0)
//理解此处判别条件,根据情况自行更改
-
{
-
((
float
*)(
void
*)(src->data.ptr + (
size_t
)src->step*i))[j] = 0.0;
-
}
-
if
(((
float
*)(
void
*)(src->data.ptr + (
size_t
)src->step*i))[j] < 0)
-
{
-
((
float
*)(
void
*)(src->data.ptr + (
size_t
)src->step*i))[j] += 256.0;
-
}
-
}
-
}
-
cvConvert(src, src_uint8);
-
cvShowImage(
“需要修复的图像”
, src_uint8);
-
cvWaitKey(0);
-
-
double
t = getTickCount();
//当前滴答数
-
float
lambda = 0.2;
-
float
delta = 0.5;
-
float
UO, UN, UW, US, UE, UNE, UNW, USW, USE;
-
float
Un, Ue, Uw, Us;
-
float
Wn, We, Ww, Ws;
-
float
Hon, Hoe, How, Hos;
-
float
Hoo;
-
int
iteration = 500;
-
while
(iteration)
-
{
-
for
(i = 1; i < M – 1; i++)
-
{
-
for
(j = 1; j < N – 1; j++)
-
{
-
if
(((
char
*)(mask->imageData + i * mask->widthStep))[j] < 0)
//坏损区
-
{
-
UO = ((
float
*)(
void
*)(src->data.ptr + (
size_t
)src->step*i))[j];
-
UN = ((
float
*)(
void
*)(src->data.ptr + (
size_t
)src->step*(i-1)))[j];
-
US = ((
float
*)(
void
*)(src->data.ptr + (
size_t
)src->step*(i+1)))[j];
-
UE = ((
float
*)(
void
*)(src->data.ptr + (
size_t
)src->step*i))[j+1];
-
UW = ((
float
*)(
void
*)(src->data.ptr + (
size_t
)src->step*i))[j-1];
-
-
UNE = ((
float
*)(
void
*)(src->data.ptr + (
size_t
)src->step*(i-1)))[j+1];
-
UNW = ((
float
*)(
void
*)(src->data.ptr + (
size_t
)src->step*(i-1)))[j-1];
-
USE = ((
float
*)(
void
*)(src->data.ptr + (
size_t
)src->step*(i+1)))[j+1];
-
USW = ((
float
*)(
void
*)(src->data.ptr + (
size_t
)src->step*(i+1)))[j-1];
-
-
Un = sqrt((UO – UN) * (UO – UN) + ((UNW – UNE) / 2.0) * ((UNW – UNE) / 2.0));
-
Ue = sqrt((UO – UE) * (UO – UE) + ((UNE – USE) / 2.0) * ((UNE – USE) / 2.0));
-
Uw = sqrt((UO – UW) * (UO – UW) + ((UNW – USW) / 2.0) * ((UNW – USW) / 2.0));
-
Us = sqrt((UO – US) * (UO – US) + ((USW – USE) / 2.0) * ((USW – USE) / 2.0));
-
-
Wn = 1.0/sqrt(Un * Un + delta * delta);
-
We = 1.0/sqrt(Ue * Ue + delta * delta);
-
Ww = 1.0/sqrt(Uw * Uw + delta * delta);
-
Ws = 1.0/sqrt(Us * Us + delta * delta);
-
-
Hon = Wn/(Wn+We+Ww+Ws+lambda);
-
Hoe = We/(Wn+We+Ww+Ws+lambda);
-
How = Ww/(Wn+We+Ww+Ws+lambda);
-
Hos = Ws/(Wn+We+Ww+Ws+lambda);
-
-
Hoo = lambda/(Wn+We+Ww+Ws+lambda);
-
((
float
*)(
void
*)(src->data.ptr + (
size_t
)src->step*i))[j]=(Hon*UN+Hoe*UE+How*UW+Hos*US+Hoo*UO);
-
}
-
}
-
}
-
iteration–;
-
}
-
cvConvert(src, src_uint8);
-
t = ((
double
)getTickCount() – t)/getTickFrequency();
-
printf(
“算法用时:%f秒\n”
, t);
-
cvShowImage(
“修复结果”
, src_uint8);
-
cvWaitKey(0);
-
}
由于迭代次数和浮点数的运算,使得算法时间较长,效果如下,仔细观察可以看出仍有细节处修复效果不是很理想。在TV模型之后,又出现了许多改进的TV模型,在速度和效果上都比理想,此处不深入探讨。
本文所需的实验材料都已打包上传,点击此处下载:
http://download.csdn.net/detail/hujingshuang/8500553
如有疑问请加群:数字图像处理群:389011389
特别注意:
1、本博客例程仅做学习交流用,切勿用于商业用途。
2、欢迎交流,转载请注明出处:
http://blog.csdn.net/hujingshuang/article/details/44257179