要求

  1. 均值滤波
    具体内容:利用 OpenCV 对灰度图像像素进行操作,分别利用算术均值滤波器. 几何均值滤波器. 谐波和逆谐波均值滤波器进行图像去噪。模板大小为5*5。(注:请分别为图像添加高斯噪声. 胡椒噪声. 盐噪声和椒盐噪声,并观察滤波效果)
  2. 中值滤波
    具体内容:利用 OpenCV 对灰度图像像素进行操作,分别利用 5*5 和 9*9尺寸的模板对图像进行中值滤波。(注:请分别为图像添加胡椒噪声. 盐噪声和椒盐噪声,并观察滤波效果)
  3. 自适应均值滤波。
    具体内容:利用 OpenCV 对灰度图像像素进行操作,设计自适应局部降低噪声滤波器去噪算法。模板大小 7*7 (对比该算法的效果和均值滤波器的效果)
  4. 自适应中值滤波
    具体内容:利用 OpenCV 对灰度图像像素进行操作,设计自适应中值滤波算法对椒盐图像进行去噪。模板大小 7*7(对比中值滤波器的效果)
  5. 彩色图像均值滤波
    具体内容:利用 OpenCV 对彩色图像 RGB 三个通道的像素进行操作,利用算术均值滤波器和几何均值滤波器进行彩色图像去噪。模板大小为 5*5。

过程

calcHist

使用的是


void cv::calcHist   (   const Mat *     images,
int     nimages,
const int *     channels,
InputArray  mask,
OutputArray     hist,
int     dims,
const int *     histSize,
const float **  ranges,
bool    uniform = true,
bool    accumulate = false
)

channels

当参数channels为1时,效果和np.histogram差不多。当channels为2时,效果和np.histogram2d差不多。

注意:当channels>1时,函数不是分别计算各个channel的一维直方图

ranges

range是个二维float数组。其中的各项(一维数组)指定了直方图各个维度的bin边界(取值范围)。当直方图中bin的边界是均匀分割得到的时候(unifor = true),对于每个维度i,只需要指定该维度的第一个bin(索引0)的下边界(包含在内)L0L_0L0​和该维度的最后一个bin(索引为histSize[i]-1)的上边界UhistSize[i]−1U_{\texttt{histSize}[i]-1}UhistSize[i]−1​(排除在外)。在这种情况下,ranges的各项(一维数组)只需要包含2个元素(float)就行了。在另外的情况下(uniform=false),ranges[i]包含histSize[i]+1个元素L0,U0=L1,U1=L2,...,UhistSize[i]−2=LhistSize[i]−1,UhistSize[i]−1L_0, U_0=L_1, U_1=L_2, ..., U_{\texttt{histSize[i]}-2}=L_{\texttt{histSize[i]}-1}, U_{\texttt{histSize[i]}-1}L0​,U0​=L1​,U1​=L2​,...,UhistSize[i]−2​=LhistSize[i]−1​,UhistSize[i]−1​。图片中没有被包含在L0L_0L0​和UhistSize[i]−1U_{\texttt{histSize[i]}-1}UhistSize[i]−1​之间的,不会被统计进直方图中。

STL和Mat

vector是深复制。

高效的使用STL 当对象很大时,建立指针的容器而不是对象的容器

带你深入理解STL之迭代器和Traits技法

cppMat中对应的是

template<typename _Tp>
class cv::DataType< _Tp >
Template "trait" class for OpenCV primitive data types.

static local var

使用静态局部变量实现带状态的函数

nth_element

STL中用来寻找在全排序中位列第n个元素,实际上并不需要全排序,局部排序即可。应该是借鉴快排的思路了。

ROI

locateROI的函数用来寻找ROI(如果ROI是从Mat中截取出来的)在原Mat中的位置。

adjustROI的函数用来调整ROI的边界。

结构设计

我不是太清楚这些设计的正确命名

调用处理框架

特定函数,首先实现其特定的小函数,然后将特定小函数作为回调函数传递给并调用公共的处理函数(类似于处理框架)。主体是特定函数

函数表驱动

将特定函数部分实现后放进函数表里。公共处理部分(框架)主动调用函数表里的函数。主体为公共处理部分

如果将公共部分抽象出来成函数,将特定的小函数和公共处理函数封装成函数,就成了实验一中的特定函数。估计在公共处理部分只是整个程序的一小部分时才会这么做吧,比如说库。opencv的特定滤波器好像就这么实现的

代码

#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>#include <numeric>
#include <iostream>
#include <vector>
#include <map>
#include <functional>
#include <string>using namespace cv;
using namespace std;
using namespace std::placeholders;float gauss_mean = 0, gauss_stdev = 15, pulse_prcnt = 0.01;// line's point's x-aixs gap is depend on point number and image's width.
void plot_poly(Mat &imgIO, Mat &pts, const Scalar color, bool reset_scale=true)
{static float scale = 1.;Mat points;pts.convertTo(points, CV_32F);int width = imgIO.cols, height = imgIO.rows, pts_num = points.total();if (reset_scale) {double max_val;minMaxLoc(points, NULL, &max_val);scale = (double)height / max_val;}Mat tmpM(imgIO.size(), imgIO.type(), Scalar::all(0));for (int i = 1; i < pts_num; ++i)//Round operator should be done at last.line(tmpM,Point(cvRound((float)(i-1) / pts_num * width), height - cvRound(points.at<float>(i-1) * scale)),Point(cvRound((float)(i) / pts_num * width), height - cvRound(points.at<float>(i) * scale)),color, 2, LINE_AA, 0);imgIO += tmpM;
}void add_gaussian_noise(const Mat & imgI, Mat & imgO, float mean, float stdev)
{cout << "Add gussian noise.\tmean:" << mean << "\tstdev:" << stdev << endl;Mat noise(imgI.size(), imgI.type());randn(noise, Scalar::all(mean), Scalar::all(stdev));add(imgI, noise, imgO);
}void add_pulse_noise(const Mat &imgI, Mat &imgO, float percent, uchar value)
{CV_Assert(imgI.type() == CV_8U);cout << "Add pulse noise.\tpulse value:" << (int)value << endl;RNG rng(getTickCount());imgO = imgI.clone();int rows = imgI.rows, cols = imgI.cols;int counts = rows * cols * percent;for (int i = 0; i < counts; ++i)imgO.at<uchar>(rng.uniform(0, rows), rng.uniform(0, cols)) = value;
}void filter2Dfun(const Mat &imgI, Mat &imgO, function<uchar(const Mat&)> pf, int m=3, int n=0)
{if (!n) n = m;cout << "\n\tsize(mxn):" << m << "x" << n;CV_Assert(m % 2 == 1);CV_Assert(n % 2 == 1);imgO = imgI.clone();// imgI.convertTo(imgO, CV_64F);int cols = imgI.cols, rows = imgI.rows;// top == (n - 1) / 2 == n / 2;  left == (m - 1) / 2 == m / 2;int top = n / 2, bottom = rows - top, left = m / 2, right = cols - left;for (int y = top; y < bottom; ++y) {for (int x = left; x < right; ++x) {Mat roi(imgI, Rect(x - left, y - top, m, n));imgO.at<uchar>(Point(x, y)) = pf(roi);}}
}void apply_arithmetic_mean_filter(const Mat &imgI, Mat &imgO, int m=3, int n=0)
{if (!n) n = m;cout << "apply arithmetic mean filter.";auto fun = [=](const Mat &roi) -> uchar { return mean(roi)[0]; };filter2Dfun(imgI, imgO, fun, m, n);cout << endl;
}void apply_geometric_mean_filter(const Mat &imgI, Mat &imgO, int m=3, int n=0)
{if (!n) n = m;cout << "apply geometric mean filter.";auto fun = [=](const Mat &roi) -> uchar {Mat tmpM;roi.convertTo(tmpM, CV_64F);// cv::pow(tmpM, (double)1/(m*n), tmpM);// TODO: split 2-D into 1-D's may be betterauto product = std::accumulate(tmpM.begin<double>(), tmpM.end<double>(), (double)1., [](double lhs, double rhs) -> double {if (!lhs) lhs = 1;if (!rhs) rhs = 1;return lhs * rhs;});product = pow(product, 1./m/n);// auto product = std::accumulate(tmpM.begin<double>(), tmpM.end<double>(), (double)1., multiplies<double>());return saturate_cast<uchar>(product);};filter2Dfun(imgI, imgO, fun, m, n);cout << endl;
}void apply_harmonic_mean_filter(const Mat &imgI, Mat &imgO, int m=3, int n=0)
{if (!n) n = m;cout << "apply harmonic mean filter.";auto fun = [=](const Mat &roi) -> uchar {Mat tmpM;roi.convertTo(tmpM, CV_64F);divide(1, tmpM, tmpM);return saturate_cast<uchar>((double)m * n / sum(tmpM)[0]);};filter2Dfun(imgI, imgO, fun, m, n);cout << endl;
}void apply_inverse_harmonic_mean_filter(const Mat &imgI, Mat &imgO, int Q, int m=3, int n=0)
{if (!n) n = m;cout << "apply inverse harmonic mean filter.\tQ:" << Q;auto fun = [=](const Mat &roi) -> uchar {Mat tmpM, tmpM_Qp1, tmpM_Q;roi.convertTo(tmpM, CV_64F);pow(tmpM, Q, tmpM_Q);pow(tmpM, Q+1, tmpM_Qp1);return saturate_cast<uchar>(sum(tmpM_Qp1)[0] / sum(tmpM_Q)[0]);};filter2Dfun(imgI, imgO, fun, m, n);cout << endl;
}void apply_median_filter(const Mat &imgI, Mat &imgO, int m=3, int n=0)
{if (!n) n = m;cout << "apply median filter.";auto fun = [=](const Mat &roi) -> uchar {Mat tmpM = roi.clone();nth_element(tmpM.begin<uchar>(), tmpM.begin<uchar>() + tmpM.total()/2, tmpM.end<uchar>());return tmpM.at<uchar>(tmpM.total()/2);};filter2Dfun(imgI, imgO, fun, m, n);cout << endl;
}void apply_adaptive_mean_filtering(const Mat &imgI, Mat &imgO, int m=3, int n=0)
{if (!n) n = m;cout << "apply adaptive mean filter.";float var_g = gauss_stdev;auto fun = [=](const Mat &roi) -> uchar {Mat mean_l, stdev_l;meanStdDev(roi, mean_l, stdev_l);double var_l = stdev_l.at<double>(0) * stdev_l.at<double>(0);if (var_g > var_l) {return saturate_cast<uchar>(mean_l.at<double>(0));} else {uchar val = roi.at<uchar>(roi.total()/2);return saturate_cast<uchar>(val - var_g / var_l * (val - mean_l.at<double>(0)));}};filter2Dfun(imgI, imgO, fun, m, n);cout << endl;
}void apply_adaptive_median_filtering(const Mat &imgI, Mat &imgO, int S_max=9)
{int m = 3, r_max = (sqrt(S_max)-1)/2;cout << "apply adaptive median filter.";auto fun = [=](const Mat &roi0) -> uchar {uchar z_med, z_min, z_max, z_xy = roi0.at<uchar>(roi0.total()/2);Size sz;Point ofs;roi0.locateROI(sz, ofs);int w = sz.width, h = sz.height, cx = ofs.x + roi0.cols/2, cy = ofs.y + roi0.rows/2;Mat roi = roi0;// cout << endl << "cx:" << cx << "\tcy:" << cy << endl;for (int r = 1; r<=cx && r<=cy && r<w-cx && r<h-cy && r<=r_max; ++r) {auto z_minmax = minmax_element(roi.begin<uchar>(),roi.end<uchar>());z_min = *z_minmax.first, z_max = *z_minmax.second;Mat tmpM = roi.clone();nth_element(tmpM.begin<uchar>(), tmpM.begin<uchar>() + tmpM.total()/2, tmpM.end<uchar>());z_med =  tmpM.at<uchar>(tmpM.total()/2);if (z_min < z_med && z_med < z_max) {// cout << "return form program B." << endl;return (z_min < z_xy  && z_xy < z_max) ? z_xy : z_med;} else {roi.adjustROI(1, 1, 1, 1);// cout << "roi.size():" << roi.size() << endl;}}// cout << "size can't be bigger.return from program A." << endl;return z_med;};filter2Dfun(imgI, imgO, fun, m);cout << "~" << r_max *2 + 1 << "x" << r_max * 2 + 1 << endl;
}void update_display(vector<string> wndwnms, vector<Mat*> images, string hist_wn="hist_img")
{namedWindow(hist_wn);Mat hist_img(images[0]->rows, images[0]->cols, CV_8UC3, Scalar::all(0));// origin image pdf, noise image pdf, processed image pdfvector<Mat> pdfs(3);float range[] = {0, 256};const float * hist_range = {range};int hist_size = 256;// cout << images[1] << endl;for (int i = 0; i < 3; ++i) {calcHist(images[i], 1, 0, Mat(), pdfs[i], 1, &hist_size, &hist_range);// plot_poly(hist_img,pdfs[i],Scalar(255*(0==i),255*(1==i),255*(2==i)));plot_poly(hist_img, pdfs[i], Scalar(255*(0==i),255*(1==i),255*(2==i)), i==0);imshow(wndwnms[i], *images[i]);}imshow(hist_wn, hist_img);waitKey();destroyWindow(hist_wn);
}int main(int argc, char const *argv[])
{const char *image_path = (argc > 1) ? argv[1] : "img_test.jpg";Mat img, image, image_color, image_gray, image_noise, image_dst;img = imread(image_path, IMREAD_COLOR);if (img.empty()) {cout << "Cannot read image: " << image_path << std::endl;return -1;}image_color = img;cvtColor(image_color, image_gray, CV_BGR2GRAY);image = image_gray;vector<Mat*> imgs {&image, &image_noise, &image_dst};vector<string> wndnms {"image_src", "image_noise", "image_processed"};for (auto it : wndnms)namedWindow(it, CV_WINDOW_AUTOSIZE);vector<function<void(const Mat&, Mat&)>> add_noise_funs {bind(add_gaussian_noise, _1, _2, gauss_mean, gauss_stdev), bind(add_pulse_noise, _1, _2, pulse_prcnt, 0), bind(add_pulse_noise, _1, _2, pulse_prcnt, 255), // TODO: [add_pulse_noise][&](const Mat& imgI, Mat& imgO) -> void {add_pulse_noise(imgI, imgO, pulse_prcnt, 0); add_pulse_noise(imgO, imgO, pulse_prcnt, 255);}};vector<function<void(const Mat&, Mat&)>> apply_mean_filters {bind(apply_arithmetic_mean_filter, _1, _2, 5, 5),bind(apply_geometric_mean_filter, _1, _2, 5, 5),bind(apply_harmonic_mean_filter, _1, _2, 5, 5),bind(apply_inverse_harmonic_mean_filter, _1, _2, 1, 5, 5)};for (auto apply_mean_filter : apply_mean_filters) {for (auto add_noise : add_noise_funs) {add_noise(image, image_noise);apply_mean_filter(image_noise, image_dst);update_display(wndnms, imgs);cout << endl;}}for (size_t i = 1; i < add_noise_funs.size(); ++i) {add_noise_funs[i](image, image_noise);apply_median_filter(image_noise, image_dst, 5);update_display(wndnms, imgs);cout << endl;apply_median_filter(image_noise, image_dst, 9);update_display(wndnms, imgs);cout << endl;}add_gaussian_noise(image, image_noise, gauss_mean, gauss_stdev);apply_arithmetic_mean_filter(image_noise, image_dst);update_display(wndnms, imgs);apply_adaptive_mean_filtering(image_noise, image_dst, 7);update_display(wndnms, imgs);cout << endl;add_pulse_noise(image, image_noise, pulse_prcnt, 255);add_pulse_noise(image_noise, image_noise, pulse_prcnt, 0);apply_median_filter(image_noise, image_dst, 7);update_display(wndnms, imgs);apply_adaptive_median_filtering(image_noise, image_dst, 7*7);update_display(wndnms, imgs);cout << endl;image = image_color;vector<Mat> bgr_planes;split(image, bgr_planes);for (auto &plane : bgr_planes) {add_gaussian_noise(plane, plane, gauss_mean, gauss_stdev);add_pulse_noise(plane, plane, pulse_prcnt, 0);add_pulse_noise(plane, plane, pulse_prcnt, 255);}merge(bgr_planes, image_noise);split(image_noise, bgr_planes);for(auto &plane : bgr_planes) {apply_arithmetic_mean_filter(plane, plane, 5);}merge(bgr_planes, image_dst);for (size_t i = 0; i < imgs.size(); ++i)imshow(wndnms[i], *imgs[i]);waitKey();split(image_noise, bgr_planes);for(auto &plane : bgr_planes) {apply_geometric_mean_filter(plane, plane, 5);}merge(bgr_planes, image_dst);for (size_t i = 0; i < imgs.size(); ++i)imshow(wndnms[i], *imgs[i]);waitKey();return 0;
}

图像处理实验4:图像去噪相关推荐

  1. 图像处理边缘增强matlab,数字图像处理实验 matlab 图像增强 边缘检测 图像操作.doc...

    数字图像处理实验 matlab 图像增强 边缘检测 图像操作 实验1 点运算和直方图处理 实验目的 1. 掌握利用Matlab图像工具箱显示直方图的方法 2. 掌握运用点操作进行图像处理的基本原理. ...

  2. Python+OpenCV图像处理实验

    目录 1.灰度化功能 2.反转功能 3.通道分离功能 4.噪音.滤波功能 5.高斯双边滤波功能 6.均值偏移滤波功能 7.图像二值化功能 8.Canny边缘检测功能 9.直线检测功能 10.圆形检测功 ...

  3. 数字图像处理实验(总计23个)汇总

    以下这些实验中的代码全部是我自己编写调试通过的,到此,最后进行一下汇总. 数字图像处理实验(1):PROJECT 02-01, Image Printing Program Based on Half ...

  4. 数字图像处理matlab实验对图像复原,数字图像处理实验07图像的复原处理

    数字图像处理实验 一.数字图像处理实验 实验七 图像的复原处理 一.实验目的 熟悉几种在实际应用中比较重要的图像复原技术,学会用MATLAB复原函数对退化图像进行复原处理. 二.实验内容 1.用点扩散 ...

  5. 中南民族大学计算机图像处理实验报告,中南民族大学数字图像处理程序及图像...

    数字图像处理实验课 matlab实验程序 以及图像结果 附带有命名图 仅供参考 定有错误 木有绝对正确 实验1 1-1 close all; clear; f=zeros(40,40);% f(10: ...

  6. 数字图像处理实验——Python语言实现

    数字图像处理实验--Python语言实现 实验一:数字图像处理入门 实验二:直方图均衡 实验三:线性平滑和锐化--掩模法 实验四:非线性平滑--中值滤波 实验五:非线性锐化--梯度法 GitHub地址 ...

  7. 数字图像处理实验三图像增强

    一.实验目的 (1)了解图像增强的目的及意义,加深对图像增强的 感性认识,巩固所学的图像增强的理论知识和相 关算法. (2)熟练掌握直方图均衡化和直方图规定化的计算过 程. (3)熟练掌握空域滤波中常 ...

  8. 数字图像处理实验四图像频域增强

    一.实验目的 (1)了解图像增强的目的及意义,加深对图像增强的感性认识,巩固所学的图像增强的理论知识和相关算法. (2)熟练掌握低通.高通.带通.同态滤波器的使用方法,明确不同性质的滤波器对图像的影响 ...

  9. 数字图像处理实验5图像复原

    一.实验目的 (1)了解图像复原的目的及意义,加深对图像复原理论的认识. (2)掌握维纳滤波复原基本原理. (3)掌握约束最小二乘方复原方法. (4)掌握盲解卷积复原方法 二.实验内容  (1)维纳滤 ...

最新文章

  1. [转载]Android开发常用调试技术记录
  2. 基本表改变视图不改变为什么_中国白酒包装是真的很丑吗,为什么不改变包装?...
  3. 用cascade删除有约束的表或记录
  4. 008_JavaScript输出
  5. 多窗体、窗体传值、打开唯一窗体操作
  6. 迭代器和生成器的区别
  7. 获取java异常堆栈信息_Java 实例 - 获取异常的堆栈信息
  8. 05_学生管理系统,xml读写,布局的综合应用
  9. java中的正则操作总结
  10. yii2基础之分页的基本使用及其配置详解
  11. 全国计算机OFFICE二级考试大纲,全国计算机等级考试二级MSOffice高级应用考试大纲...
  12. STM32——红外遥控器实验
  13. 灵异:各国家千年诅咒悬迷——不可思议
  14. java 命令行工具_分享java自带命令行工具jmap、jhat与jinfo的方法详解
  15. 建筑设计的未来是什么?| 建筑 · 人工智能专栏
  16. Ruby(了解第二天)
  17. 使用命令行强制注销远程登录用户
  18. EPICS记录参考--模拟输入记录(ai)
  19. 基于业务描述语言BDL的需求方法论
  20. uniapp 关于swiper组件和moveable-area、moveable-view组件搭配的图片预览高度集成组件

热门文章

  1. C-使用Unrar SDK列出文件示例
  2. Linux/Windos搭建安装Kaldi环境实现ASR语音识别
  3. 联想服务器测试项目,联想服务器集成测试系统iPTS今上线
  4. Repair Pipelining for Erasure-Coded Storage(ATC‘17)
  5. 天猫店铺基础知识分享
  6. 【附代码】图像分类 — 测评指标
  7. 碳交易机制下考虑需求响应的综合能源系统优化运行
  8. Google Earth Engine(GEE)——栅格转矢量
  9. CAN总线多节点通信异常分析及解决
  10. java的三层架构是什么_java中的三层架构