实际比较filter2D和imfilter之间的关系
​     
            卷积运算是图像处理和增强中经常遇到的一种算法。由于很多优秀的开源算法都是采用matlab编写的,在我改写为c语言的时候就必然会遇到改写卷积算法的问题。在matlab中,卷积可以由imfilter来实现,在opencv中则是由filter2D来实现。它们之间的具体转化过程是什么?我通过一系列实验来研究。
          一、实验准备
          为了方便观察,仍然是采用分开来研究的方法。1)是输入数字作为卷积内容,直接观察结果;2)是采用小块图片作为卷积内容,仍然是比较结果;3)是采用真实的图片和真实的卷积核作为输入,对比最后处理图片的效果。
          那么,首先需要了解的就是在matlab中和opencv中如何将矩阵的内容进行比对?
          在matlab中可以直接打印到矩阵变量中去,而在opencv中可以这样直接打印到屏幕上面。然后将两者在matlab中做减法,直观地比较最后的结果。
          二、过程
          1)是输入数字作为卷积内容
        int _tmain(int argc, _TCHAR* argv[])
{
    //filter2d的卷积方法
    printf(    "filter2d的卷积方法\n");
    Mat srcMat(,,CV_32F);
    Mat dstMat(,,CV_32F);
    Mat srcH(,,CV_32F);
    srcH.at<float>(,) = -;
    srcH.at<float>(,) = -;
    srcH.at<float>(,) = ;
    srcH.at<float>(,) = ;
    srcH.at<float>(,) = ;
    srcH.at<float>(,) = ;
    srcH.at<float>(,) = ;
    srcH.at<float>(,) = ;
    srcH.at<float>(,) = ;
    printf(    "卷积核\n");
    for (int i=;i<srcH.rows;i++){
        for (int j=;j<srcH.cols;j++){
            printf("%f ",srcH.at<float>(i,j) );
        }
            printf("\n");
    }
    printf(    "输入\n");
    for (int i = ; i < ; i++){
        for (int j = ; j < ; j++)
          srcMat.at<float>(i,j) = i+;
    }
    for (int i = ; i < ; i++){
        for (int j = ; j < ; j++){
            printf("%.1f ",srcMat.at<float>(i,j));
        }
        printf("\n");
    }
    printf(    "输出\n");
    filter2D(srcMat,dstMat,srcMat.depth(),srcH);
    printf("\n"); printf("\n");
    for (int i = ; i < ; i++){
        for (int j = ; j < ; j++){
            printf("%.1f ",dstMat.at<float>(i,j));
        }
        printf("\n");
    }
    waitKey();
    return ;
}
 
            而在matlab中也有相关输入
          >> clear
>> H = [-2.000000 -1.000000 4.000000
3.000000 3.000000 3.000000
3.000000 2.000000 1.000000]
 
H =
 
    -2    -1     4
     3     3     3
     3     2     1
 
>> I=[1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0
4.0 4.0 4.0 4.0 4.0 4.0 4.0 4.0 4.0 4.0
5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0
6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
7.0 7.0 7.0 7.0 7.0 7.0 7.0 7.0 7.0 7.0
8.0 8.0 8.0 8.0 8.0 8.0 8.0 8.0 8.0 8.0
9.0 9.0 9.0 9.0 9.0 9.0 9.0 9.0 9.0 9.0
10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0]
 
I =
 
     1     1     1     1     1     1     1     1     1     1
     2     2     2     2     2     2     2     2     2     2
     3     3     3     3     3     3     3     3     3     3
     4     4     4     4     4     4     4     4     4     4
     5     5     5     5     5     5     5     5     5     5
     6     6     6     6     6     6     6     6     6     6
     7     7     7     7     7     7     7     7     7     7
     8     8     8     8     8     8     8     8     8     8
     9     9     9     9     9     9     9     9     9     9
    10    10    10    10    10    10    10    10    10    10
 
>> rst = imfilter(I,H)
 
rst =
 
    12    21    21    21    21    21    21    21    21    16
    24    37    37    37    37    37    37    37    37    24
    36    53    53    53    53    53    53    53    53    32
    48    69    69    69    69    69    69    69    69    40
    60    85    85    85    85    85    85    85    85    48
    72   101   101   101   101   101   101   101   101    56
    84   117   117   117   117   117   117   117   117    64
    96   133   133   133   133   133   133   133   133    72
   108   149   149   149   149   149   149   149   149    80
    87    99    99    99    99    99    99    99    99    33
 
 
 
则计算两者之差
rst3 =
 
   -11    -2    -2    -2    -2    -2    -2    -2    -2    -7
   -13     0     0     0     0     0     0     0     0   -13
   -17     0     0     0     0     0     0     0     0   -21
   -21     0     0     0     0     0     0     0     0   -29
   -25     0     0     0     0     0     0     0     0   -37
   -29     0     0     0     0     0     0     0     0   -45
   -33     0     0     0     0     0     0     0     0   -53
   -37     0     0     0     0     0     0     0     0   -61
   -41     0     0     0     0     0     0     0     0   -69
   -66   -54   -54   -54   -54   -54   -54   -54   -54  -120
结论是在边界会有所不同,这个应该是不同算法对于边界的处理不同而已。那么主体成分是完全一样的。
 
 
            2)是采用小块图片作为卷积内容
         那么准备了小块的灰度图片作为卷积内容
             //读取图片的处理的方法
    Mat gray = imread("test.jpg",);
    imwrite("gray.jpg",gray);
    gray.convertTo(gray,CV_32F);
    Mat dst;
    filter2D(gray,dst,gray.depth(),srcH);
    for (int i = ; i < gray.rows; i++){
        for (int j = ; j < gray.cols; j++){
            printf("%f ",dst.at<float>(i,j));
        }
        printf("\n");
    }         
          
             同样matlab
             I = im2double(imread('gray.jpg'))
             H =
              -2    -1     4
               3     3     3
               3     2     1
>> rst = imfilter(I,H)
              
            对比相关结果,这里可以发现,在matlab中图像是归一化存储的。
           
           在输入之前归一化,这样就会得到比较好的结果。
           结果比较像
 
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace std;
using namespace cv;
int _tmain(int argc, _TCHAR* argv[])
{
    ////filter2d的卷积方法
    printf(    "filter2d的卷积方法\n");
    //Mat srcMat(10,10,CV_32F);
    //Mat dstMat(10,10,CV_32F);
    Mat srcH(,,CV_32F);
    srcH.at<float>(,) = -;
    srcH.at<float>(,) = -;
    srcH.at<float>(,) = ;
    srcH.at<float>(,) = ;
    srcH.at<float>(,) = ;
    srcH.at<float>(,) = ;
    srcH.at<float>(,) = ;
    srcH.at<float>(,) = ;
    srcH.at<float>(,) = ;
    printf(    "卷积核\n");
    for (int i=;i<srcH.rows;i++){
        for (int j=;j<srcH.cols;j++){
            printf("%f ",srcH.at<float>(i,j) );
        }
        printf("\n");
    }
    //读取图片的处理的方法
    Mat gray = imread("test.jpg",);
    imwrite("gray.jpg",gray);
    gray.convertTo(gray,CV_32F);
    gray = gray/; //归一化处理
    fstream ftxt;
    ftxt.open("src.txt",ios::out); //写入的方式,同时是append模式的就不会覆盖掉前面的东西了。 
    for (int i = ; i < gray.rows; i++){
        for (int j = ; j < gray.cols; j++){
            ftxt<<gray.at<float>(i,j)<<" ";
        }
        ftxt<<endl;
    }
    ftxt.close();
    Mat dst;
    filter2D(gray,dst,gray.depth(),srcH);
    
    ftxt.open("rst.txt",ios::out); //写入的方式,同时是append模式的就不会覆盖掉前面的东西了。 
    for (int i = ; i < gray.rows; i++){
        for (int j = ; j < gray.cols; j++){
             ftxt<<dst.at<float>(i,j)<<" ";
        }
         ftxt<<endl;
    }
    ftxt.close();
    imshow("dst",dst);
    waitKey();
    return ;
}
 
 
        结果令人满意
       
           3)是采用真实的图片和真实的卷积核作为输入
          结论除了在图片的边界有差异外,在其他的地方,这个差异在小数点后4位,应该说是非常相似的,可以用于实际生成。
          三、小结和反思
          最后的结论是可以正常使用,但是在输入之前,需要将图片归一化处理。那么,通过这个实验,除了获得面上的这个知识之外,更多的应该是一种实验的方法。很多时候,无论是做改写还是其他的事情之前,将相关可能发生的情况设计好;力图获得稳定准确的结果。这些对于最终获得设计之中的结论是非常重要和有价值的。
          感谢阅读到此,希望能够有所帮助。
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace std;
using namespace cv; int _tmain(int argc, _TCHAR* argv[])
{
////filter2d的卷积方法
printf( "filter2d的卷积方法\n");
//Mat srcMat(10,10,CV_32F);
//Mat dstMat(10,10,CV_32F);
Mat srcH(3,3,CV_32F);
srcH.at<float>(0,0) = -2;
srcH.at<float>(0,1) = -1;
srcH.at<float>(0,2) = 4;
srcH.at<float>(1,0) = 3;
srcH.at<float>(1,1) = 3;
srcH.at<float>(1,2) = 3;
srcH.at<float>(2,0) = 3;
srcH.at<float>(2,1) = 2;
srcH.at<float>(2,2) = 1;
printf( "卷积核\n");
for (int i=0;i<srcH.rows;i++){
for (int j=0;j<srcH.cols;j++){
printf("%f ",srcH.at<float>(i,j) );
}
printf("\n");
}
//printf( "输入\n");
//for (int i = 0; i < 10; i++){
// for (int j = 0; j < 10; j++)
// srcMat.at<float>(i,j) = i+1;
//}
//for (int i = 0; i < 10; i++){
// for (int j = 0; j < 10; j++){
// printf("%.1f ",srcMat.at<float>(i,j));
// }
// printf("\n");
//}
//printf( "输出\n");
//filter2D(srcMat,dstMat,srcMat.depth(),srcH);
//printf("\n"); printf("\n");
//for (int i = 0; i < 10; i++){
// for (int j = 0; j < 10; j++){
// printf("%.1f ",dstMat.at<float>(i,j));
// }
// printf("\n");
//}
//读取图片的处理的方法
Mat gray = imread("test.jpg",0);
imwrite("gray.jpg",gray);
gray.convertTo(gray,CV_32F);
gray = gray/255; //归一化处理
fstream ftxt;
ftxt.open("src.txt",ios::out); //写入的方式,同时是append模式的就不会覆盖掉前面的东西了。
for (int i = 0; i < gray.rows; i++){
for (int j = 0; j < gray.cols; j++){
ftxt<<gray.at<float>(i,j)<<" ";
//printf("%.1f ",dst.at<float>(i,j));
}
ftxt<<endl;
//printf("\n");
}
ftxt.close();
Mat dst;
filter2D(gray,dst,gray.depth(),srcH); ftxt.open("rst.txt",ios::out); //写入的方式,同时是append模式的就不会覆盖掉前面的东西了。
for (int i = 0; i < gray.rows; i++){
for (int j = 0; j < gray.cols; j++){
ftxt<<dst.at<float>(i,j)<<" ";
//printf("%.1f ",dst.at<float>(i,j));
}
ftxt<<endl;
//printf("\n");
}
ftxt.close();
imshow("dst",dst); waitKey();
return 0;
}

p.s 转一篇有用博文,时间久了原始链接已经丢失,抱歉

Overview:
imfill是matlab的一个函数,在http://www.mathworks.cn/cn/help/images/ref/imfill.html 中有详细的讲解。这个函数有好几种不同的签名。在这里我的侧重点是imfill(m, 'holes'),以及如何用openCV来实现imfill一样的功能。本文有三部分组成。
 
1. 使用Matlab 的imfill 进行填充图像
在Matlab中简单的几行代码就能实现:
1
2
3
4
5
6
7
8
 
clc;
clear;
BW = im2bw( imread('imfilltest.tif'));
imshow(BW);
holes = imfill(BW, 'holes');

BW(~holes) = 1; 
figure,imshow(holes);

左图为填充前的图像,右图是填充后的图像:
2. 用opencv来实现imfill(bw, 'holes')
opencv 在这里不像matlab那么好用了,matlab调用下。
 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 
#include 
#include 
#include

using namespace std;
using namespace cv;

void my_imfillholes(Mat &src)
{
   // detect external contours
   //
   vector > contours;
   vector hierarchy;
   findContours(src, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
   //
   // fill external contours
   //
   if( !contours.empty() && !hierarchy.empty() )
   {
      for (int idx=0;idx < contours.size();idx++)
      {
         drawContours(src,contours,idx,Scalar::all(255),CV_FILLED,8);
      }
   }
}

void test_my_imfillholes()
{
   Mat m = imread(filltestName,IMREAD_GRAYSCALE);
   //threshold, (i,j)>100 -->255
   Mat th_m;
   threshold(m, th_m, 100, 255, THRESH_BINARY);
   my_imfillholes(th_m);
   namedWindow(WinName, CV_WINDOW_AUTOSIZE);
   imshow(WinName, th_m);
   waitKey(0); 
}

void main()
{
   test_my_imfillholes();
   system("pause");
}

3. imfill 和opencv实现的imfill 对矩阵进行操作的对比
我仍有点不放心,觉得尽管2幅图看起来差不多,但是是不是完全一样呢,然后我觉得用个矩阵试一下。
m = [1, 1, 1, 0, 0, 0, 0, 0;
         1, 0, 1, 0, 1, 1, 0, 0;
         1, 0, 1, 0, 1, 1, 0, 0;
         1, 1, 1, 0, 1, 0, 1, 0;
         1, 0, 1, 0, 1, 0, 1, 0;
         1, 1, 1, 0, 1, 0, 1, 0;
         1, 0, 1, 0, 0, 1, 1, 0;
         1, 1, 1, 0, 0, 0, 0, 0];
without_holes = imfill(m, 'holes')
 
得到结果:
without_holes =
     1     1     1     0     0     0     0     0
     1     1     1     0     1     1     0     0
     1     1     1     0     1     1     0     0
     1     1     1     0     1     1     1     0
     1     1     1     0     1     1     1     0
     1     1     1     0     1     1     1     0
     1     1     1     0     0     1     1     0
     1     1     1     0     0     0     0     0
然后用第2部分所说的opencv的方法也试一下,结果发现是这样的:
without_holes =
     0     0     0     0     0     0     0     0
     0     1     1     0     1     1     0     0
     0     1     1     0     1     1     0     0
     0     1     1     0     1     1     1     0
     0     1     1     0     1     1     1     0
     0     1     1     0     1     1     1     0
     0     1     1     0     0     1     1     0
     0     0     0     0     0     0     0     0
是不一样的。这个问题折腾了我一个晚上,终于,我在
中的 findContours找到了这样的一个note:
Note:
Source image is modified by this function. Also, the function does not take into account 1-pixel border of the image (it’s filled with 0’s and used for neighbor analysis in the algorithm), therefore the contours touching the image border will be clipped.
它的意思是,findCountours 是不会包含1-pixel的边界的。所以这就是为啥opencv计算的结果中边界的1都消失的原因。我想,既然边界不被包含,那么我给它上下左右加一个1-pixel的框,这样边界点就变成了内部点,就能成功的用findCountours了。于是乎:我写了下面的code:
C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 
#include 
#include 
#include

using namespace std;
using namespace cv;

void my_imfillholes_v2()
{
   //step 1: make a border
   Mat m(8, 8, CV_8UC1, data);
   Mat m_with_border;
   copyMakeBorder(m, m_with_border, 1, 1, 1, 1, BORDER_CONSTANT, Scalar());
   cout<<m_with_border<<endl;

//setp 2: find the contour fill holes
   vector > contours;
   vector hierarchy;
   findContours(m_with_border, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
   //
   // fill external contours
   // 
   if( !contours.empty() && !hierarchy.empty() )
   {
      for (int idx=0;idx < contours.size();idx++)
      {
         drawContours(m_with_border,contours,idx,Scalar::all(1),CV_FILLED,8);
      }
   }
   //cout<<m_with_border<<endl;
   //step 3: remove the border
   m_with_border = m_with_border.rowRange(Range(1, m_with_border.rows-1));
   //cout<<m_with_border<<endl;
   m_with_border = m_with_border.colRange(Range(1, m_with_border.cols-1));
   cout<<m_with_border<<endl;
}

void main()
{
   my_imfillholes_v2();
   system("pause");
}

 
先加一个全0的1-pixel的框,然后在findCountours填充,最后把框给去了。这样结果就完全和matlab中的imfill一致了。
result =
     1     1     1     0     0     0     0     0
     1     1     1     0     1     1     0     0
     1     1     1     0     1     1     0     0
     1     1     1     0     1     1     1     0
     1     1     1     0     1     1     1     0
     1     1     1     0     1     1     1     0
     1     1     1     0     0     1     1     0
     1     1     1     0     0     0     0     0

实际比较filter2D和imfilter之间的关系的更多相关文章

  1. .NET Core与.NET Framework、Mono之间的关系

    随着微软的.NET开源的推进,现在在.NET的实现上有了三个.NET Framework,Mono和.NET Core.经常被问起Mono的稳定性怎么样,后续Mono的前景如何,要回答这个问题就需要搞 ...

  2. .NET Core 和 .NET Framework 之间的关系

    引用一段描述:Understanding the relationship between .NET Core and the .NET Framework. .NET Core and the .N ...

  3. 实体之间的关系【Entity Relationships】(EF基础系列篇9)

    Here, you will learn how entity framework manages the relationships between entities. Entity framewo ...

  4. php CGI、Fastcgi、PHP-FPM的详细介绍与之间的关系

    以下PHP CGI.Fastcgi.PHP-FPM的一些信息归纳和汇总----->详细介绍与之间的关系 一:CGI是干嘛的?CGI是为了保证web server传递过来的数据是标准格式的 web ...

  5. [转] valuestack,stackContext,ActionContext.之间的关系

    三者之间的关系如下图所示: ActionContext  一次Action调用都会创建一个ActionContext  调用:ActionContext context = ActionContext ...

  6. angular源码阅读,依赖注入的原理:injector,provider,module之间的关系。

    最开始使用angular的时候,总是觉得它的依赖注入方式非常神奇. 如果你跳槽的时候对新公司说,我曾经使用过angular,那他们肯定会问你angular的依赖注入原理是什么? 这篇博客其实是angu ...

  7. JavaScript和Java之间的关系

    今天来简单而又详细地说说JavaScript和Java的关系. 开门见山总结性一句话,它们之间的关系 = 雷锋和雷峰塔之间的关系,换句话说:它们之间没什么关系. 但往往有不少初学者甚至中级者认为它们之 ...

  8. PHP类和对象之间的关系

    类是对象的描述: 类和对象之间的关系类似于建房子的图纸和房子: 创建类--new对象--用对象: 一.对象的两个特性: --对象的行为(功能):可以对对象施加操作,例如,电视机的开.关.转换频道: - ...

  9. 关于计算机的ID和用户ID之间的关系

    关于计算机的ID和用户ID之间的关系 计算机安装完系统后就会生成计算机ID,然后系统会以计算机ID为前缀附加数字创建Administrator(500)和Guest(501)用户ID,其他用户的ID将 ...

随机推荐

  1. ABP入门系列(8)——Json格式化

    ABP入门系列目录--学习Abp框架之实操演练 讲完了分页功能,这一节我们先不急着实现新的功能.来简要介绍下Abp中Json的用法.为什么要在这一节讲呢?当然是做铺垫啊,后面的系列文章会经常和Json ...

  2. Java 异步 IO

         新的异步功能的关键点,它们是Channel 类的一些子集,Channel 在处理IO操作的时候需要被切换成一个后台进程.一些需要访问较大,耗时的操作,或是其它的类似实例,可以考虑应用此功能. ...

  3. Python学习--16 正则表达式

    正则表达式是一种描述性的语言,用来匹配字符串.凡是符合规则的字符串,我们认为就是匹配了. 正则表达式并非Python独有的,它与语言无关.很多语言都支持正则表达式. 我们经常用正则表达式来匹配电子邮件 ...

  4. Android实现屏蔽微信拉黑和删除联系人功能

    实现效果: 让微信永远弹不出那个删除的对话框不就相当于屏蔽掉该功能了吗?哈哈效果如图: 实现原理: 同样是利用AccessibilityService辅助服务,关于这个服务类还不了解的同学可以先看下我 ...

  5. OVS VxLAN Flow 分析 - 每天5分钟玩转 OpenStack(149)

    OVS 的数据流向都是由 Flow 规则控制的,今天我们就来分析 VxLAN 的 Flow 规则.提个醒:这可能是本教程最烧脑的一节,let's rock it ! 下面分析控制节点上的 flow r ...

  6. java的位运算符

    1.与运算&,同为1为1,否则为0: 例如:10001(二进制)&10000(二进制)=10000(二进制) 2.或运算|,只要有1就是1: 例如:10001(二进制)&100 ...

  7. 【.Net Framework 体积大?】不安装.net framework 也能运行!?开篇叙述-1

    [声明:请尊重作者micro-chen的原创,抓文章,请添加来源和作者署名.作者保留追责权利.......] 写在前言 看着日渐没落的.net ,心里多少有了点悲凉.国内的越来越多的新兴公司 都是JA ...

  8. 最简单的排序算法之一冒泡排序----js实现

    1. 算法步骤 比较相邻的元素.如果第一个比第二个大,就交换他们两个. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.这步做完后,最后的元素会是最大的数. 针对所有的元素重复以上的步骤, ...

  9. VMware workstation安装报Microsoft Runtime DLL和Intel VT-x错误

    在安装VMware workstation时,弹出提示框,提示"安装程序无法继续.Microsoft Runtime DLL安装程序未能完成安装." 网上找到两种说法,但我的win ...

  10. Yarn init 命令在 Git Bash 中打开时的错误

    最近一直在学习一些新的知识,ES5.ES6.Vue等,当然,作为程序,英文的阅读和听写能力也是要去学习的. 最近慕课网上的qbaty大神出了两套视频,分别是webpack和yarn,本着不断学习的精神 ...