1、首先先了解下什么是卷积呢?

2、卷积操作:卷积核与原图对应位置相乘再求和;然后将所求和放在被卷积操作的图中心位置。

上图表示一个 8×8 的原图,每个方格代表一个像素点;其中一个包含 X 的方格是一个 5×5 的卷积核,核半径等于 5/2 = 2;

进行卷积操作后,生成图像为上图中包含 Y 的方格,可以看出是一个 4×4 的生成图;

通过比较观察可以发现,生成图比原图尺寸要小,为了保证生成图与原图保持尺寸大小一样,需要对原图进行边界补充,方法有如下四种:
(1)补零填充;
(2)镜像填充;
(3)块填充;
(4)边界复制填充。

由上图可知,生成图边界与原图边界差2个像素点,这是因为,卷积核半径为2,所以,为了保证图像处理前后尺寸一致,可将原图填充为 12×12 大小。

3、可参考下面程序了解卷积操作:

  • 方法一
//边缘锐化
Mat Kernel_test_3_3 = (Mat_<double>(3,3) << 0,-1,0,-1,5,-1,0,-1,0);
//均值平滑模板(平滑)
Mat Kernel_junzhi=(Mat_<double>(3,3) <<1.0/9,1.0/9,1.0/9,1.0/9,1.0/9,1.0/9,1.0/9,1.0/9,1.0/9);
Mat Kernel_junzhi_new=(Mat_<double>(5,5))<<0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04);//拉普拉斯4邻域模板(锐化)
Mat Kernel_laPuLaSi=(Mat_<double>(3,3)<<0,1,0,1,-4,1,0,1,0);
//sobel算子模板(边缘检测)
Mat Kernel_sobel=(Mat_<double>(3,3)<<-1,0,1,-2,0,2,-1,0,1);void Convlution(Mat  InputImage,Mat  OutputImage,Mat kernel)
{//计算卷积核的半径int sub_x = kernel.cols/2;int sub_y = kernel.rows/2;//遍历图片,除边界以外每个像素for (int image_y=0;image_y<InputImage.rows-2*sub_y;image_y++){for(int image_x=0;image_x<InputImage.cols-2*sub_x;image_x++){int pix_value = 0;//用来累加每个位置的乘积for (int kernel_y = 0;kernel_y<kernel.rows;kernel_y++)//对每一个点根据卷积模板进行卷积{for(int kernel_x = 0;kernel_x<kernel.cols;kernel_x++){double  weihgt = kernel.at<double>(kernel_y,kernel_x);int value =  (int)InputImage.at<uchar>(image_y+kernel_y,image_x+kernel_x); pix_value +=weihgt*value;}}OutputImage.at<uchar>(image_y+sub_y,image_x+sub_x) = (uchar)pix_value;//OutputImage.at<uchar>(image_y+sub_y,image_x+sub_x) = saturate_cast<uchar>((int)pix_value);if ((int)pix_value!=(int)saturate_cast<uchar>((int)pix_value)){//cout<<"没有防溢出"<<(int)pix_value<<endl;//cout<<"防溢出"<<(int)saturate_cast<uchar>((int)pix_value)<<endl;//cout<<"没有防溢出写入了什么?"<<(int)OutputImage.at<uchar>(image_y+sub_y,image_x+sub_x)<<endl;//cout<<endl;}}}
}int main()
{Mat srcImage = imread("1.jpg",0);//创建一个图形矩阵namedWindow("srcImage", WINDOW_AUTOSIZE);imshow("原图", srcImage);//filter2D卷积Mat dstImage_oprncv(srcImage.rows,srcImage.cols,CV_8UC1,Scalar(0));filter2D(srcImage,dstImage_oprncv,srcImage.depth(),Kernel_test_3_3);imshow("filter2D卷积图",dstImage_oprncv);imwrite("0.jpg",dstImage_oprncv);//自定义卷积1Mat dstImage_mycov(srcImage.rows,srcImage.cols,CV_8UC1,Scalar(0));Convlution(srcImage,dstImage_mycov,Kernel_test_3_3);imshow("卷积图1",dstImage_mycov);imwrite("1.jpg",dstImage_mycov);//均值平滑Mat dstImage_junzhi(srcImage.rows,srcImage.cols,CV_8UC1,Scalar(0));Convlution(srcImage,dstImage_junzhi,Kernel_junzhi);imshow("平滑图",dstImage_junzhi);imwrite("2.jpg",dstImage_junzhi);//拉普拉斯锐化Mat dstImage_lapulasi(srcImage.rows,srcImage.cols,CV_8UC1,Scalar(0));Convlution(srcImage,dstImage_lapulasi,Kernel_laPuLaSi);imshow("锐化图",dstImage_lapulasi);imwrite("3.jpg",dstImage_lapulasi);//sobel边缘检测Mat dstImage_sobel(srcImage.rows,srcImage.cols,CV_8UC1,Scalar(0));Convlution(srcImage,dstImage_sobel,Kernel_sobel);imshow("边缘检测图",dstImage_sobel);imwrite("4.jpg",dstImage_sobel);waitKey(0);return 0;}
  • 方法二
/convolution卷积
//inputeImage图片矩阵 mytemplate模板矩阵
Mat convolution(Mat inputImage, Mat myTemplate)
{int inputImageWidth = inputImage.size().width;//图片矩阵的宽度int inputImageHeigh = inputImage.size().height;//图片矩阵的高度int myTemplateWidth = myTemplate.size().width;//模板矩阵的宽度int myTemplateHeigh = myTemplate.size().height;//模板矩阵的高度Mat result(inputImageHeigh, inputImageWidth,CV_8UC1);//返回结果float temp;//卷积所用临时变量//两层for循环遍历除边界以外每一个像素for (int i = 1; i<inputImageHeigh - 1; i++){for (int j = 1; j<inputImageWidth - 1; j++){//对每一个点进行卷积temp = 0;//累加每一个位置的乘积for (int m = -1; m<myTemplateHeigh - 1; m++)for (int n = -1; n<myTemplateWidth - 1; n++)temp += myTemplate.at<float>((m + 1), (n + 1)) * inputImage.at<uchar>((i + m), (j + n));temp = (temp >= 0) ? temp : 0;//如果结果小于0置0temp = (temp <= 255) ? temp : 255;//如果结果大于255置255result.at<uchar>(i, j) = temp;//为结果矩阵对应位置赋值}}//边界不进行修改for (int i = 0; i < inputImageWidth; i++)//复制第一行和最后一行{result.at<uchar>(0, i) = inputImage.at<uchar>(0, i);result.at<uchar>((inputImageHeigh - 1), i) = inputImage.at<uchar>((inputImageHeigh - 1), i);}for (int i = 0; i < inputImageHeigh; i++)//复制第一列和最后一列{result.at<uchar>(i, 0) = inputImage.at<uchar>(i, 0);result.at<uchar>(i, (inputImageWidth - 1)) = inputImage.at<uchar>(i, (inputImageWidth - 1));}return result;
}Mat matAddAndSqrt(Mat mat1,Mat mat2) //两个矩阵平方求和再开方
{int temp1 = 0;int temp2 = 0;for (int i = 0; i < mat1.size().height; i++)for (int j = 0; j < mat1.size().width; j++){temp1 = mat1.at<uchar>(i, j);temp2 = mat2.at<uchar>(i, j);temp1 = sqrt(temp1*temp1 + temp2*temp2);temp1 = (temp1 <= 255) ? temp1 : 255;mat1.at<uchar>(i, j) = temp1;}return mat1;
}int main()
{Mat image = imread("D:\\7.jpg", 0);Mat newImage1(image.size().height, image.size().width, CV_8UC1, Scalar(0));Mat newImage2(image.size().height, image.size().width, CV_8UC1, Scalar(0));Mat newImage3(image.size().height, image.size().width, CV_8UC1, Scalar(0));Mat newImage4(image.size().height, image.size().width, CV_8UC1, Scalar(0));//均值平滑模板Mat mat1 = (Mat_<float>(3, 3) << 1.0/9, 1.0/9, 1.0/9, 1.0/9, 1.0/9, 1.0/9, 1.0/9, 1.0/9, 1.0/9);newImage1 = convolution(image, mat1);//拉普拉斯4邻域锐化模板Mat mat2 = (Mat_<float>(3, 3) << 0, -1, 0, -1, 4, -1, 0, -1, 0);newImage2 = convolution(image, mat2);newImage2 = image + newImage2;//锐化图像=原图像+加重的边缘//sobel算子边缘检测模板Mat mat3 = (Mat_<float>(3, 3) << -1, 0, 1, -2, 0, 2, -1, 0, 1);//横向边缘检测newImage3 = convolution(image, mat3);Mat mat4 = (Mat_<float>(3, 3) << -1, -2, -1, 0, 0, 0, 1, 2, 1);//纵向边缘检测newImage4 = convolution(image, mat4);//newImage3 = abs(newImage3) + abs(newImage4);//为了提高效率,使用绝对值相加为近似值newImage3 = matAddAndSqrt(newImage3, newImage4);//综合横向与纵向namedWindow("原图");//添加" , CV_WINDOW_NORMAL "可自由拖动鼠标调整窗口大小imshow("原图", image);namedWindow("均值平滑");imshow("均值平滑", newImage1);namedWindow("拉普拉斯4邻域锐化");imshow("拉普拉斯4邻域锐化", newImage2);namedWindow("sobel算子边缘检测");imshow("sobel算子边缘检测", newImage3);waitKey(0);return 0;
}

附:上述为个人理解,可能存在考虑不全面的情况,如果哪里有问题,还望大家留言指出~

如何对图像进行卷积操作相关推荐

  1. 理解图像中卷积操作的含义

    原文地址:https://blog.csdn.net/chaipp0607/article/details/72236892?locationNum=9&fps=1 上文用生动的例子来解释卷积 ...

  2. 卷积 对图像进行卷积操作 卷积神经网络

    目录 卷积 对图像进行卷积操作 卷积神经网络 卷积(Filtering) 池化(下采样)(Pooling) 修正线性单元(Rectified Linear Units)(ReLus激活函数) 全连接层 ...

  3. Java中 实现通过文件夹选择任一图像,从而进行图像卷积操作

    ** Java中 实现通过文件夹选择任一图像,从而进行图像卷积操作 ** 之前的那篇关于图像卷积的博客(Java中实现图像的卷积效果),只是讲了给定一张图片,从而实现图片的卷积操作:而现在,需要去实现 ...

  4. 【OpenCV 4】图像卷积操作(Blur)

    一.编程环境: OpenCV  4.1.0 IDE Visual Studio 2017 Enterprise (15.9.13) 操作系统 Windows 10 x64 中文专业版 (1903) 二 ...

  5. 【深度学习入门】——亲手实现图像卷积操作

    深度学习中有一个很重要的概念就是卷积神经网络 CNN,卷积神经网络中又有卷积层.池化层的概念.尤其是卷积层,理解难度比较大,虽然书中或者是视频中都有详细介绍过它的基础概念,但对于求知欲望很强烈的我,我 ...

  6. 理解图像卷积操作的意义

    数字信号处理中卷积 卷积一词最开始出现在信号与线性系统中,信号与线性系统中讨论的就是信号经过一个线性系统以后发生的变化.由于现实情况中常常是一个信号前一时刻的输出影响着这一时刻的输出,所在一般利用系统 ...

  7. 卷积及理解图像卷积操作的意义

    转载:http://blog.csdn.net/chaipp0607/article/details/72236892 https://www.zhihu.com/question/22298352 ...

  8. 【深度学习入门-1】透彻理解卷积的三层含义:从“卷积”、到“图像卷积操作”、再到“卷积神经网络”的含义(学习笔记)

    一.写在前面 笔者在进行卷积神经网络入门的时候花了很多功夫,理解的也不够透彻,基础不牢,地动山摇.在查阅了很多资料后,发现了大佬up"王木头学科学"讲的卷积神经网络的理解,茅塞顿开 ...

  9. Lesson 16.3 卷积操作

    3 卷积操作 这里有两个长度为9的列表,我们让对应位置的元素相乘,之后再相加: a∗9+b∗8+7∗c+6∗d+5∗e+f∗4+g∗3+h∗2+i∗1a * 9+b * 8+7 * c+6 * d+5 ...

最新文章

  1. 报错解决: error: ‘writev’ was not declared in this scope
  2. sqlserver 遇到以零作除数错误的处理 不报错的解决方法
  3. Nginx基于TCP的四层负载均衡介绍
  4. mybatis.xml中sql编写规范
  5. 3.type关键字.rs
  6. vue获取DOM元素并设置属性
  7. .Net 调用wordCOM组件转PDF
  8. 【Flink】Flink常量UDF-TableFunction优化
  9. python俗称_python为什么叫爬虫?
  10. 十个最佳方法保护Windows文件服务器
  11. Java中TreeMap集合讲解
  12. 一个能拖动,能调整大小,能更新bind值的vue指令-vuedragx
  13. 创建ASP.NET MVC5 应用程序
  14. 施乐打印机驱动程序安装(CP315/318DW)
  15. 如何在“文件资源”左侧栏处删除坚果云图标
  16. PC大作[微软模拟飞行10]
  17. AppThinning之AppSlicing
  18. 魔百和CM201-1 线机教程 救砖(大部分情况能用)
  19. MATLAB矩阵变换
  20. 日志分析---携来百侣曾游,忆往昔峥嵘岁月稠

热门文章

  1. kd树实现搜索的过程
  2. js计算两个日期时间的差值
  3. 软连接和硬连接(Linux创建软连接一定要用绝对路径)
  4. 2022年初级审计师考试综合试题及答案
  5. js给对象添加变量属性 js 更改对象中的属性名 数组对象中每个对象添加一个字段-map用法和forEarch用法
  6. 计算机中华五岳说课稿,中国五岳 地理课前三分钟演讲.ppt
  7. 译文推荐 | Apache BookKeeper 洞察系列(二)— 安全关闭 Ledger
  8. MacBook 电池管家—— AlDente Pro 使用体验
  9. Linux从入门到放弃 docker
  10. NXP bootloader