【图像修复】浅析:图像修复中的TV模型

  • Post author:
  • Post category:其他


转自: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源码实现:




  1. img=double(imread(‘lena.jpg’));


  2. mask=imread(‘mask.jpg’);

  3. a1=find(mask>127);

  4. b1=find(mask<=127);

  5. mask(a1)=0;

  6. mask(b1)=255;

  7. [m n]=size(img);

  8. for i=1:m

  9. for j=1:n

  10. if mask(i,j)==0

  11. img(i,j)=0;

  12. end

  13. end

  14. end

  15. imshow(img,[]);     %合成的需要修复的图像


  16. lambda=0.2;

  17. a=0.5;%避免分母为0

  18. imgn=img;

  19. for l=1:1500         %迭代次数

  20. for i=2:m-1

  21. for j=2:n-1

  22. if mask(i,j)==0     %如果当前像素是被污染的像素,则进行处理

  23. Un=sqrt((img(i,j)-img(i-1,j))^2+((img(i-1,j-1)-img(i-1,j+1))/2)^2);

  24. Ue=sqrt((img(i,j)-img(i,j+1))^2+((img(i-1,j+1)-img(i+1,j+1))/2)^2);

  25. Uw=sqrt((img(i,j)-img(i,j-1))^2+((img(i-1,j-1)-img(i+1,j-1))/2)^2);

  26. Us=sqrt((img(i,j)-img(i+1,j))^2+((img(i+1,j-1)-img(i+1,j+1))/2)^2);


  27. Wn=1/sqrt(Un^2+a^2);

  28. We=1/sqrt(Ue^2+a^2);

  29. Ww=1/sqrt(Uw^2+a^2);

  30. Ws=1/sqrt(Us^2+a^2);


  31. Hon=Wn/((Wn+We+Ww+Ws)+lambda);

  32. Hoe=We/((Wn+We+Ww+Ws)+lambda);

  33. How=Ww/((Wn+We+Ww+Ws)+lambda);

  34. Hos=Ws/((Wn+We+Ww+Ws)+lambda);


  35. Hoo=lambda/((Wn+We+Ww+Ws)+lambda);

  36. 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);

  37. imgn(i,j)= value;

  38. end

  39. end

  40. end

  41. img=imgn;

  42. end

  43. figure;

  44. imshow(img)


opencv源码实现:




  1. #include <iostream>





  2. #include <stdlib.h>





  3. #include <cv.h>





  4. #include <math.h>





  5. #include <opencv2/highgui/highgui.hpp>





  6. #include <opencv2/core/core.hpp>





  7. #include <opencv2/imgproc/imgproc.hpp>






  8. using




    namespace


    cv;




  9. int


    main(


    void


    )


  10. {


  11. //读取原始图像及掩模图像




  12. IplImage *src_uint8 = cvLoadImage(

    “src.jpg”


    , CV_LOAD_IMAGE_GRAYSCALE);


  13. IplImage *mask = cvLoadImage(

    “mask.jpg”


    , CV_LOAD_IMAGE_GRAYSCALE);



  14. //合成需要修复的图像





  15. int


    M = mask->height;



  16. int


    N = mask->width;



  17. int


    i, j;


  18. CvMat *src = cvCreateMat(M, N, CV_32FC1);

    //存放浮点图像




  19. cvConvert(src_uint8, src);


  20. for


    (i = 0; i < M; i++)


  21. {


  22. for


    (j = 0; j < N; j++)


  23. {


  24. if


    ((mask->imageData + i * mask->widthStep)[j] < 0)


    //理解此处判别条件,根据情况自行更改




  25. {

  26. ((

    float


    *)(


    void


    *)(src->data.ptr + (


    size_t


    )src->step*i))[j] = 0.0;


  27. }


  28. if


    (((


    float


    *)(


    void


    *)(src->data.ptr + (


    size_t


    )src->step*i))[j] < 0)


  29. {

  30. ((

    float


    *)(


    void


    *)(src->data.ptr + (


    size_t


    )src->step*i))[j] += 256.0;


  31. }

  32. }

  33. }

  34. cvConvert(src, src_uint8);

  35. cvShowImage(

    “需要修复的图像”


    , src_uint8);


  36. cvWaitKey(0);



  37. double


    t = getTickCount();


    //当前滴答数





  38. float


    lambda = 0.2;



  39. float


    delta = 0.5;



  40. float


    UO, UN, UW, US, UE, UNE, UNW, USW, USE;



  41. float


    Un, Ue, Uw, Us;



  42. float


    Wn, We, Ww, Ws;



  43. float


    Hon, Hoe, How, Hos;



  44. float


    Hoo;



  45. int


    iteration = 500;



  46. while


    (iteration)


  47. {


  48. for


    (i = 1; i < M – 1; i++)


  49. {


  50. for


    (j = 1; j < N – 1; j++)


  51. {


  52. if


    (((


    char


    *)(mask->imageData + i * mask->widthStep))[j] < 0)


    //坏损区




  53. {

  54. UO = ((

    float


    *)(


    void


    *)(src->data.ptr + (


    size_t


    )src->step*i))[j];


  55. UN = ((

    float


    *)(


    void


    *)(src->data.ptr + (


    size_t


    )src->step*(i-1)))[j];


  56. US = ((

    float


    *)(


    void


    *)(src->data.ptr + (


    size_t


    )src->step*(i+1)))[j];


  57. UE = ((

    float


    *)(


    void


    *)(src->data.ptr + (


    size_t


    )src->step*i))[j+1];


  58. UW = ((

    float


    *)(


    void


    *)(src->data.ptr + (


    size_t


    )src->step*i))[j-1];



  59. UNE = ((

    float


    *)(


    void


    *)(src->data.ptr + (


    size_t


    )src->step*(i-1)))[j+1];


  60. UNW = ((

    float


    *)(


    void


    *)(src->data.ptr + (


    size_t


    )src->step*(i-1)))[j-1];


  61. USE = ((

    float


    *)(


    void


    *)(src->data.ptr + (


    size_t


    )src->step*(i+1)))[j+1];


  62. USW = ((

    float


    *)(


    void


    *)(src->data.ptr + (


    size_t


    )src->step*(i+1)))[j-1];



  63. Un = sqrt((UO – UN) * (UO – UN) + ((UNW – UNE) / 2.0) * ((UNW – UNE) / 2.0));

  64. Ue = sqrt((UO – UE) * (UO – UE) + ((UNE – USE) / 2.0) * ((UNE – USE) / 2.0));

  65. Uw = sqrt((UO – UW) * (UO – UW) + ((UNW – USW) / 2.0) * ((UNW – USW) / 2.0));

  66. Us = sqrt((UO – US) * (UO – US) + ((USW – USE) / 2.0) * ((USW – USE) / 2.0));


  67. Wn = 1.0/sqrt(Un * Un + delta * delta);

  68. We = 1.0/sqrt(Ue * Ue + delta * delta);

  69. Ww = 1.0/sqrt(Uw * Uw + delta * delta);

  70. Ws = 1.0/sqrt(Us * Us + delta * delta);


  71. Hon = Wn/(Wn+We+Ww+Ws+lambda);

  72. Hoe = We/(Wn+We+Ww+Ws+lambda);

  73. How = Ww/(Wn+We+Ww+Ws+lambda);

  74. Hos = Ws/(Wn+We+Ww+Ws+lambda);


  75. Hoo = lambda/(Wn+We+Ww+Ws+lambda);

  76. ((

    float


    *)(


    void


    *)(src->data.ptr + (


    size_t


    )src->step*i))[j]=(Hon*UN+Hoe*UE+How*UW+Hos*US+Hoo*UO);


  77. }

  78. }

  79. }

  80. iteration–;

  81. }

  82. cvConvert(src, src_uint8);

  83. t = ((

    double


    )getTickCount() – t)/getTickFrequency();


  84. printf(

    “算法用时:%f秒\n”


    , t);


  85. cvShowImage(

    “修复结果”


    , src_uint8);


  86. cvWaitKey(0);

  87. }


由于迭代次数和浮点数的运算,使得算法时间较长,效果如下,仔细观察可以看出仍有细节处修复效果不是很理想。在TV模型之后,又出现了许多改进的TV模型,在速度和效果上都比理想,此处不深入探讨。






本文所需的实验材料都已打包上传,点击此处下载:

http://download.csdn.net/detail/hujingshuang/8500553




如有疑问请加群:数字图像处理群:389011389





特别注意:




1、本博客例程仅做学习交流用,切勿用于商业用途。


2、欢迎交流,转载请注明出处:

http://blog.csdn.net/hujingshuang/article/details/44257179

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hujingshuang/article/details/44257179