• OpenCV每日函数 计算摄影模块(1) 图像修复算法 inpaint函数


    一、概述

            该算法使用区域邻域恢复图像中的选定区域。该功能可用于去除扫描照片上的灰尘和划痕,或去除静止图像或视频中不需要的物体。

    二、inpaint函数

    1、函数原型

    void 	cv::inpaint (InputArray src, InputArray inpaintMask, OutputArray dst, double inpaintRadius, int flags)

    2、参数详解

    src输入 8 位、16 位无符号或 32 位浮点 1 通道或 8 位 3 通道图像。
    inpaintMask修复蒙版,8 位 1 通道图像。 非零像素表示需要修复的区域。
    dst输出与 src 大小和类型相同的图像
    inpaintRadius算法考虑的每个修复点的圆形邻域的半径。
    flags可以是 cv::INPAINT_NS 或 cv::INPAINT_TELEA 的修复方法

    三、OpenCV源码

    1、源码路径

    opencv\modules\photo\src\inpaint.cpp

    2、源码代码

    1. static void
    2. icvInpaint( const CvArr* _input_img, const CvArr* _inpaint_mask, CvArr* _output_img,
    3. double inpaintRange, int flags )
    4. {
    5. cv::Ptr<CvMat> mask, band, f, t, out;
    6. cv::Ptr<CvPriorityQueueFloat> Heap, Out;
    7. cv::Ptr<IplConvKernel> el_cross, el_range;
    8. CvMat input_hdr, mask_hdr, output_hdr;
    9. CvMat* input_img, *inpaint_mask, *output_img;
    10. int range=cvRound(inpaintRange);
    11. int erows, ecols;
    12. input_img = cvGetMat( _input_img, &input_hdr );
    13. inpaint_mask = cvGetMat( _inpaint_mask, &mask_hdr );
    14. output_img = cvGetMat( _output_img, &output_hdr );
    15. if( !CV_ARE_SIZES_EQ(input_img,output_img) || !CV_ARE_SIZES_EQ(input_img,inpaint_mask))
    16. CV_Error( CV_StsUnmatchedSizes, "All the input and output images must have the same size" );
    17. if( (CV_MAT_TYPE(input_img->type) != CV_8U &&
    18. CV_MAT_TYPE(input_img->type) != CV_16U &&
    19. CV_MAT_TYPE(input_img->type) != CV_32F &&
    20. CV_MAT_TYPE(input_img->type) != CV_8UC3) ||
    21. !CV_ARE_TYPES_EQ(input_img,output_img) )
    22. CV_Error( CV_StsUnsupportedFormat,
    23. "8-bit, 16-bit unsigned or 32-bit float 1-channel and 8-bit 3-channel input/output images are supported" );
    24. if( CV_MAT_TYPE(inpaint_mask->type) != CV_8UC1 )
    25. CV_Error( CV_StsUnsupportedFormat, "The mask must be 8-bit 1-channel image" );
    26. range = MAX(range,1);
    27. range = MIN(range,100);
    28. ecols = input_img->cols + 2;
    29. erows = input_img->rows + 2;
    30. f.reset(cvCreateMat(erows, ecols, CV_8UC1));
    31. t.reset(cvCreateMat(erows, ecols, CV_32FC1));
    32. band.reset(cvCreateMat(erows, ecols, CV_8UC1));
    33. mask.reset(cvCreateMat(erows, ecols, CV_8UC1));
    34. el_cross.reset(cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_CROSS,NULL));
    35. cvCopy( input_img, output_img );
    36. cvSet(mask,cvScalar(KNOWN,0,0,0));
    37. COPY_MASK_BORDER1_C1(inpaint_mask,mask,uchar);
    38. SET_BORDER1_C1(mask,uchar,0);
    39. cvSet(f,cvScalar(KNOWN,0,0,0));
    40. cvSet(t,cvScalar(1.0e6f,0,0,0));
    41. cvDilate(mask,band,el_cross,1); // image with narrow band
    42. Heap=cv::makePtr<CvPriorityQueueFloat>();
    43. if (!Heap->Init(band))
    44. return;
    45. cvSub(band,mask,band,NULL);
    46. SET_BORDER1_C1(band,uchar,0);
    47. if (!Heap->Add(band))
    48. return;
    49. cvSet(f,cvScalar(BAND,0,0,0),band);
    50. cvSet(f,cvScalar(INSIDE,0,0,0),mask);
    51. cvSet(t,cvScalar(0,0,0,0),band);
    52. if( flags == cv::INPAINT_TELEA )
    53. {
    54. out.reset(cvCreateMat(erows, ecols, CV_8UC1));
    55. el_range.reset(cvCreateStructuringElementEx(2*range+1,2*range+1,
    56. range,range,CV_SHAPE_RECT,NULL));
    57. cvDilate(mask,out,el_range,1);
    58. cvSub(out,mask,out,NULL);
    59. Out=cv::makePtr<CvPriorityQueueFloat>();
    60. if (!Out->Init(out))
    61. return;
    62. if (!Out->Add(band))
    63. return;
    64. cvSub(out,band,out,NULL);
    65. SET_BORDER1_C1(out,uchar,0);
    66. icvCalcFMM(out,t,Out,true);
    67. switch(CV_MAT_DEPTH(output_img->type))
    68. {
    69. case CV_8U:
    70. icvTeleaInpaintFMM<uchar>(mask,t,output_img,range,Heap);
    71. break;
    72. case CV_16U:
    73. icvTeleaInpaintFMM<ushort>(mask,t,output_img,range,Heap);
    74. break;
    75. case CV_32F:
    76. icvTeleaInpaintFMM<float>(mask,t,output_img,range,Heap);
    77. break;
    78. default:
    79. CV_Error( cv::Error::StsBadArg, "Unsupportedformat of the input image" );
    80. }
    81. }
    82. else if (flags == cv::INPAINT_NS) {
    83. switch(CV_MAT_DEPTH(output_img->type))
    84. {
    85. case CV_8U:
    86. icvNSInpaintFMM<uchar>(mask,t,output_img,range,Heap);
    87. break;
    88. case CV_16U:
    89. icvNSInpaintFMM<ushort>(mask,t,output_img,range,Heap);
    90. break;
    91. case CV_32F:
    92. icvNSInpaintFMM<float>(mask,t,output_img,range,Heap);
    93. break;
    94. default:
    95. CV_Error( cv::Error::StsBadArg, "Unsupported format of the input image" );
    96. }
    97. } else {
    98. CV_Error( cv::Error::StsBadArg, "The flags argument must be one of CV_INPAINT_TELEA or CV_INPAINT_NS" );
    99. }
    100. }
    101. void cv::inpaint( InputArray _src, InputArray _mask, OutputArray _dst,
    102. double inpaintRange, int flags )
    103. {
    104. CV_INSTRUMENT_REGION();
    105. Mat src = _src.getMat(), mask = _mask.getMat();
    106. _dst.create( src.size(), src.type() );
    107. Mat dst = _dst.getMat();
    108. CvMat c_src = cvMat(src), c_mask = cvMat(mask), c_dst = cvMat(dst);
    109. icvInpaint( &c_src, &c_mask, &c_dst, inpaintRange, flags );
    110. }

    四、效果图像示例

    待修复的图像
    基于 Navier-Stokes 的方法
    基于Alexandru Telea 的方法

  • 相关阅读:
    高端品牌如何利用软文抓住顾客的心?
    开源进销存系统,10分钟搞定,建议收藏!
    机器学习:争取被遗忘的权利
    Java spring boot 一次调用多个请求
    Elasticsearch学习笔记
    白鳝:聊聊IvorySQL的Oracle兼容技术细节与实现原理
    Ubuntu 安装golang
    DataX从入门实战到精通一文搞定
    python: window环境安装
    11-16 周四 简单代码理解FlashAttention 分块计算softmax
  • 原文地址:https://blog.csdn.net/bashendixie5/article/details/125358624