基于OpenCV的中值滤波代码仿真
程序员文章站
2024-03-25 22:54:52
...
中值滤波主要是用来除去椒盐噪声的,基本操作如下:
1. 抠出区域
2. 排序
3. 中值
还是老规矩,此代码仅仅是用来学习,暂时不用管它速度。
这一份代码主要做了以下工作:
1. 自定义了一份新的中值滤波函数
2. 调用OpenCV的中值滤波函数
3. 比较两个函数的处理结果,如果所对应的元素值小于一定范围,则表示两个元素值是一样的,显示黑色,反之,则显示白色
备注:因为在实际代码中处理会有精度损失,所以只能通过两个值小于一定阈值来判定两个元素是否一样;另外,边界没有处理,opencv的边界处理时用copyMakeBorder来做。
为了给技术小白提供方便,提供了完整的代码,项目文件和测试图片。点此下载。
下面附上代码:
/**
中值滤波步骤:
1. 抠出区域
2. 排序
3. 中值
本程序做了以下操作:
1. 调用自己设计中值滤波代码
2. 调用opencv中值滤波代码
3. 比较两个函数的结果。
若比较的结果图某部分是白色,说明此部分是不一样。如果是黑色区域,表示的是数据一样
程序运行信息:
开发环境: VS2015 + OpenCV 3.4.1 + Windows 10
硬件环境: CPU i7-8750H; RAM 8G; Gpu: GTX1050Ti
*/
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include "opencv2/opencv.hpp"
/** @brief 将unsigned char的单通道Mat转换成float的vector类型
@param img: 单通道unsigned char类型
@param dst: 元素为float的vector类型
*/
static void MatConvertToVector(const cv::Mat& img, std::vector<float>& dst)
{
CV_Assert(img.type() == CV_8UC1);
cv::Mat tmp;
img.convertTo(tmp, CV_8U);
dst = (std::vector<float>)(tmp.reshape(1, 1));
}
/** @brief 将图片转换成vector数组, 并将其排序获得中位数的值
@param src 单通道图像矩阵
@return 中值
*/
static float CalcMedianValue(const cv::Mat& src)
{
CV_Assert(src.type() == CV_8UC1);
std::vector<float> values;
MatConvertToVector(src, values);
std::sort(values.begin(), values.end());
int index = values.size() / 2;
return values[index];
}
/** @brief 比较两个矩阵是否一致, 不一致则在结果矩阵中显示255
@param src0 矩阵0
@param src1 矩阵1
@param dst 比较结果
@param eps 两个矩阵对应元素值得差异, 大于此值则显示255,反之显示0
*/
static void CompareTwoMatrix(const cv::Mat& src0, const cv::Mat& src1, cv::Mat& dst, float eps)
{
if ((src0.rows != src1.rows) || (src0.cols != src1.cols)) return;
dst = cv::Mat::zeros(src0.rows, src0.cols, CV_8UC1);
cv::Mat s0;
cv::Mat s1;
src0.convertTo(s0, CV_32F);
src1.convertTo(s1, CV_32F);
for (int y = 0; y < src0.rows; ++y)
{
for (int x = 0; x < src0.cols; ++x)
{
float v0 = s0.at<float>(y, x);
float v1 = s1.at<float>(y, x);
// 当差异非常大了, 才显示255
if (std::abs(v0 - v1) >= eps)
{
dst.at<uchar>(y, x) = 255;
}
}
}
}
/** @brief 仿写中值模糊算法
本仿写算法不处理边界情况
@param src 单通道灰度图
@param dst 处理后的矩阵, CV_32FC1类型
@param sz kernel的长和宽, 必须为奇数. cv的源码是sz.width = sz.height。本代码不要求一定相等
*/
static void MedianBlur(const cv::Mat& src, cv::Mat& dst, cv::Size sz)
{
CV_Assert(src.type() == CV_8UC1);
CV_Assert((sz.width % 2 == 1) && (sz.height % 2 == 1));
const int xn = sz.width / 2;
const int yn = sz.height / 2;
dst = cv::Mat::zeros(src.rows, src.cols, CV_32FC1);
for (int y = yn; y < src.rows - yn; ++y)
{
for (int x = xn; x < src.cols - xn; ++x)
{
cv::Rect rect = cv::Rect(x - xn, y - yn, sz.width, sz.height);
cv::Mat roi = src(rect);
float val = CalcMedianValue(roi);
dst.at<float>(y, x) = val;
}
}
}
void test_median_blur()
{
std::cout << "Demoe" << std::endl;
std::string path = "../Resources/QQ图片20180614112723.jpg";
cv::Mat img = cv::imread(path, cv::ImreadModes::IMREAD_GRAYSCALE);
cv::imshow("原图", img);
cv::Mat dst;
MedianBlur(img, dst, cv::Size(5, 5));
//cv
cv::Mat cvDst;
cv::medianBlur(img, cvDst, 5);
cv::Mat cmpResult;
CompareTwoMatrix(dst, cvDst, cmpResult, 0.5/*eps*/);
cv::imshow("cv处理函数", cvDst);
dst.convertTo(dst, CV_8U);
cv::imshow("手动撸函数", dst);
cv::imshow("比较结果", cmpResult);
}
效果图镇楼:
上一篇: 品优购电商系统 2 - 品牌管理
下一篇: 并发,锁相关 博客分类: 总结-2014