基于OpenCV的自定义滤波函数实现

实现一个卷积操作的函数,这里的卷积代指图像卷积,原理如下

 

1 图像边界扩充

对输⼊的图像根据kernel(卷积核)的size进⾏padding操作,这里笔者选用填0,

2 初始化dst

初始化dst的size和存储元素类型( CV_8UC3 or CV_8UC1 )

3 遍历padding后的图像

此外:

对于多通道的图像,你可以先通过 cv::split() 将其拆分为单通道图像,并对各个单通道图像分别进⾏ 运算,再将结果通过 cv::merge() 合并作为输出。

下面贴上完整代码

#include <opencv2/opencv.hpp>
#include <iostream>


using namespace cv;
using namespace std;

void filter(const cv::Mat &src, cv::Mat &dst, const cv::Mat &kernel)
{
	Mat newsrc = cv::Mat::zeros(src.rows, src.cols, CV_8UC1);
	//图像边界扩充(按kernel像素计算)
	int row_k = (kernel.rows - 1) / 2;
	int col_k = (kernel.cols - 1) / 2;
	cv::copyMakeBorder(src, newsrc, row_k, row_k, col_k, col_k, BORDER_CONSTANT, 0); //以边缘为轴,对称扩展原图边界
	dst = cv::Mat::zeros(src.rows, src.cols, CV_8UC1);

	
	/*/遍历图像,常规法
	for (int i = 0; i < src.rows; i++)
	{
		for (int j = 0; j < src.cols; j++)
		{
			double cnvSum = 0.0;                           //卷积和convolution sum
			for (int m = 0; m < row_k * 2 + 1; m++)
			{
				for (int n = 0; n < col_k * 2 + 1; n++)
				{
					double srcValue = newsrc.at<uchar>(i + m, j + n) * kernel.at<uchar>(m,n);
					cnvSum += srcValue;
				}
			}
			dst.at<uchar>(i, j) = cnvSum;
		}
	}
	*/

	//遍历图像(矩阵法)
	for (int i = 0; i < src.rows; i++)
	{
		for (int j = 0; j < src.cols; j++)
		{
			Rect rect(j, i, kernel.cols, kernel.rows);    //截取矩阵大小
			Mat aa = newsrc(rect);
			aa.convertTo(aa, CV_32FC1);
			//cout << "kernel =" << kernel << endl;
			//cout << "aa =" << aa << endl;
			double sum = kernel.dot(aa);                  //向量点积
			//cout << "sum =" << sum << endl;
 			dst.at<uchar>(i, j) = sum;
		}
	}
	
}

int main()
{
	
	//imread()函数载入原始图像
	Mat srcImg = imread("tt1.jpg",1);
	
	Mat dst1 = cv::Mat::zeros(Size(srcImg.rows, srcImg.cols),CV_8UC3);	  //dst1均值滤波
	Mat dst2 = cv::Mat::zeros(Size(srcImg.rows, srcImg.cols), CV_8UC3);   //dst2我的滤波

	//均值滤波
	cv::blur(srcImg, dst1, cv::Size(3, 3));

	
	//我的滤波
	//滤波算子
	//cv::Mat mykernel= (cv::Mat_<float>(3, 3) << 0,-1,0,-1,5,-1,0,-1,0);   //若是浮点数,直接输入
	cv::Mat mykernel = cv::Mat::ones(5, 5, CV_32FC1) / (5 * 5);
		
	
	// vector创建三通道Mat,opencv是BGR,
	vector<cv::Mat> channels;
	//三通道分离函数
	cv::split(srcImg, channels);

	//蓝色通道单独通道滤波计算
	Mat imgBlue = channels.at(0);
	filter(imgBlue, channels.at(0), mykernel);
	//cv::imshow("blueblur", channels.at(0));
	cv::waitKey(0);

	//绿色通道单独通道滤波计算
	Mat imgGreen = channels.at(1);
	filter(imgGreen, channels.at(1), mykernel);
	//cv::imshow("Greenblur", channels.at(1));
	//cv::waitKey(0);


	//红色通道单独通道滤波计算
	Mat imgRed = channels.at(2);
	filter(imgRed, channels.at(2), mykernel);
	//cv::imshow("Redblur", channels.at(2));
	//cv::waitKey(0);

	//三通道合并函数
	cv::merge(channels, dst2);

	cv::imshow("raw", srcImg);     //原图
    cv::imshow("blur",dst1);       //OpenCV均值滤波
	cv::imshow("myblur", dst2);    //自定义滤波函数
	cv::waitKey(0);
	destroyAllWindows();

    return 0;
}

 此函数未使用任何OpenCV已有的滤波函数

注意:输入卷积核时若为小数请写1./9.而不要写1/9

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值