视觉图像:卷积运算及代码实现

2025-11-20 11:59:46

1、OpenCV卷积函数filter2D():

形式:

CV_EXPORTS_W void filter2D( InputArray src,

OutputArray dst,

int ddepth,

                                  InputArray kernel,

Point anchor=Point(-1,-1),

                                  double delta=0,

int borderType=BORDER_DEFAULT );

功能:利用内核实现对图像的卷积运算;

参数:

InputArray src: 输入图像;

OutputArray dst: 输出图像,和输入图像具有相同的尺寸和通道数量;

int ddepth: 目标图像深度;

原图像和目标图像支持的图像深度如下:

src.depth() = CV_8U, ddepth = -1/CV_16S/CV_32F/CV_64F

    src.depth() = CV_16U/CV_16S, ddepth = -1/CV_32F/CV_64F

    src.depth() = CV_32F, ddepth = -1/CV_32F/CV_64F

    src.depth() = CV_64F, ddepth = -1/CV_64F

当ddepth输入值为-1时,目标图像和原图像深度保持一致;

InputArray kernel: 卷积核,一个单通道浮点型矩阵。如果想在图像不同的通道使用不同的kernel,可以先使用split()函数将图像通道事先分开。

Point anchor: 内核的基准点(anchor),其默认值为(-1,-1)说明位于kernel的中心位置。基准点即kernel中与进行处理的像素点重合的点。

double delta:在储存目标图像前可选的添加到像素的值,默认值为0

int borderType:像素向外逼近的方法,默认值是BORDER_DEFAULT,即对全部边界进行计算。

2、filter2D()示例:

#include <opencv2\opencv.hpp>

using namespace std; 

using namespace cv; 

int main( int argc, char** argv ) 

{

    Mat raw_img = imread("raw.jpg",1);

    if (!raw_img.data)

    {

        return -1;

    }

    imshow("before",raw_img);

    Mat mask_img = (Mat_<char>(3,3) << 0,-1,0,-1,5,-1,0,-1,0);

    Mat dst_img(raw_img.rows,raw_img.cols,CV_32FC3);

    Point anchor = Point(-1,-1);

   

    filter2D(raw_img,dst_img,-1,mask_img,anchor,0,BORDER_DEFAULT);

    imshow("before",raw_img);

    imshow("after",dst_img);

   

    waitKey( 0 );     

    return 0;    

视觉图像:卷积运算及代码实现

视觉图像:卷积运算及代码实现

3、常见卷积模板:

模板:矩阵方块,其数学含义是一种卷积运算;

卷积运算:是加权求和的过程;所有乘积之和作为区域中心像素的新值;

卷积示例:

3*3的像素区域R与卷积核G的卷积运算(中心像素)

R5=R1G1+R2G2+R3G3+R4G4+R5G5+R6G6+R7G7+R8G8+R9G9;

常见模板如下:

滤波是图像处理的基本操作,滤波去除图像中的噪声,提取感兴趣的特征,允许图像重采样。

图像中的频域和空域:空间域指用图像的灰度值来描述一幅图像;而频域指用图像灰度值的变化来描述一幅图像。而低通滤波器和高通滤波器的概念就是在频域中产生的。

低通滤波器:指去除图像中的高频成分,使边缘平滑;

而高通滤波器:指去除图像中的低频成分,使边缘提取与增强;

视觉图像:卷积运算及代码实现

视觉图像:卷积运算及代码实现

视觉图像:卷积运算及代码实现

4、卷积边界问题:

当处理图像边界像素时,卷积核与图像使用区域不能匹配,卷积核的中心与边界像素点对应,卷积将出现问题。

处理方法:

A.忽略边界像素,即处理后的图像将丢掉这些像素;

B.保留原边界像素,即copy边界像素到处理后的图像;

视觉图像:卷积运算及代码实现

5、自定义卷积运算:

#include <opencv2\opencv.hpp>

using namespace std;

using namespace cv;

//kernel(-1,-2,1;4,-2,-1;4,-2,2);

void Sharpen(Mat& myImage, Mat& Result)

{

       int nChannels = myImage.channels();

       Result.create(myImage.size(), myImage.type());

       for (int j = 1; j < myImage.rows - 1; ++j) //hang

       {

              unsigned char *previous = myImageNaNr<unsigned char>(j-1);//上一行数据的指针

              unsigned char *current = myImageNaNr<unsigned char>(j);//当前行数据的指针

              unsigned char *next = myImageNaNr<unsigned char>(j+1);//下一行数据的指针

              unsigned char *output = ResultNaNr<unsigned char>(j);  //输出图像当前列数据的指针

              for (int i = 1; i < myImage.cols - 1; ++i)//lie

              {

                     output[i] += saturate_cast<uchar>(

                                      -1*previous[i-1]-2*previous[i]+1*previous[i+1]

                                   +4*current[i-1]-2*current[i]-1*current[i+1]

                                            +4*next[i-1]-2*next[i]+2*next[i+1]) ;

              }

       }

       // 将边界设为0

       Result.row(0).setTo(Scalar(0));

       Result.row(Result.rows - 1).setTo(Scalar(0));

       Result.col(0).setTo(Scalar(0));

       Result.col(Result.cols - 1).setTo(Scalar(0));

}

int main(){

       Mat img = imread("raw.jpg",0);

       Mat src;

       Sharpen(img, src);

       imshow("img", img);

       imshow("src",src);

       waitKey(0);

       return 0;

}

6、示例:

#include <opencv2\opencv.hpp>

using namespace std;

using namespace cv;

Mat Gaussian_kernal(int kernel_size,float sigma);

Mat z_Sharpen(Mat raw_img,Mat kernel_img);

int main( int argc, char** argv )

{

    Mat raw_img = imread("raw.jpg",0);

    imshow("before",raw_img);

    int kernel_size =3;

    float sigma = 1.4;

    Mat kernel_img = Gaussian_kernal(kernel_size,sigma);

    cout<<kernel_img<<endl;

    //float myArray[3][3] =

    //{

    //  -1, -2, 1,

    //   4, -2, -1,

    //   4, -2, 2

    //};

    //Mat kernel_img = Mat(3, 3, CV_32FC1, myArray);//创建矩阵

    Mat dst_img = z_Sharpen(raw_img,kernel_img);

    imshow("after",dst_img);

    waitKey( 0 );    

    return 0;   

}

Mat z_Sharpen(Mat raw_img,Mat kernel_img)

{

    int m_width = raw_img.cols;//kuan

    int m_height = raw_img.rows;//gao

    int kernel_size = kernel_img.cols;

    int k_size = (kernel_size-1)/2;

    Mat dst_img(m_height,m_width,CV_8UC1);

    for (int j=k_size;j<m_width-k_size;j++)//lie

    {

        for (int i=k_size;i<m_height-k_size;i++)//hang

        {

            unsigned char *current = dst_imgNaNr<unsigned char>(i);//dang qian hang

                       

            int m_J = -k_size;//lie

            for (int m=0;m<kernel_size;m++)

            {

                float *k_data = kernel_imgNaNr<float>(m);

                int m_I = -k_size;//hang

                for (int n=0;n<kernel_size;n++)

                {

                    unsigned char *p_data = raw_imgNaNr<unsigned char>(i+m_I);

                    current[j] += saturate_cast<unsigned char>(p_data[j+m_J]*k_data[n]);

                    m_I++;

                }

                m_J++;

            }

        }

    }

    //将边界设为0

    for (int i=0;i<k_size;i++)

    {

        dst_img.row(i).setTo(Scalar(0));

        dst_img.col(i).setTo(Scalar(0));

    }

    for(int i=m_height-k_size;i<m_height;i++)

    {

        dst_img.row(i).setTo(Scalar(0));

    }

    for(int i=m_width-k_size;i<m_width;i++)

    {

        dst_img.col(i).setTo(Scalar(0));

    }


    return dst_img;

}

Mat Gaussian_kernal(int kernel_size,float sigma)

{

    const double PI = 3.14159265358979323846;

    int m = kernel_size / 2;

    Mat mask_temp(kernel_size,kernel_size,CV_32FC1);

    float s_2 = 2*sigma*sigma;

    for (int i=0;i<kernel_size;i++)

    {

        for (int j=0;j<kernel_size;j++)

        {

            int x=i-m;

            int y=j-m;

            mask_tempNaNr<float>(i)[j] = exp(-(x*x+y*y)/2*s_2) /(PI*s_2);

        }

    }

    return mask_temp;

}

视觉图像:卷积运算及代码实现

声明:本网站引用、摘录或转载内容仅供网站访问者交流或参考,不代表本站立场,如存在版权或非法内容,请联系站长删除,联系邮箱:site.kefu@qq.com。
猜你喜欢