图像处理实验4:图像去噪
要求
- 均值滤波
具体内容:利用 OpenCV 对灰度图像像素进行操作,分别利用算术均值滤波器. 几何均值滤波器. 谐波和逆谐波均值滤波器进行图像去噪。模板大小为5*5。(注:请分别为图像添加高斯噪声. 胡椒噪声. 盐噪声和椒盐噪声,并观察滤波效果) - 中值滤波
具体内容:利用 OpenCV 对灰度图像像素进行操作,分别利用 5*5 和 9*9尺寸的模板对图像进行中值滤波。(注:请分别为图像添加胡椒噪声. 盐噪声和椒盐噪声,并观察滤波效果) - 自适应均值滤波。
具体内容:利用 OpenCV 对灰度图像像素进行操作,设计自适应局部降低噪声滤波器去噪算法。模板大小 7*7 (对比该算法的效果和均值滤波器的效果) - 自适应中值滤波
具体内容:利用 OpenCV 对灰度图像像素进行操作,设计自适应中值滤波算法对椒盐图像进行去噪。模板大小 7*7(对比中值滤波器的效果) - 彩色图像均值滤波
具体内容:利用 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:图像去噪相关推荐
- 图像处理边缘增强matlab,数字图像处理实验 matlab 图像增强 边缘检测 图像操作.doc...
数字图像处理实验 matlab 图像增强 边缘检测 图像操作 实验1 点运算和直方图处理 实验目的 1. 掌握利用Matlab图像工具箱显示直方图的方法 2. 掌握运用点操作进行图像处理的基本原理. ...
- Python+OpenCV图像处理实验
目录 1.灰度化功能 2.反转功能 3.通道分离功能 4.噪音.滤波功能 5.高斯双边滤波功能 6.均值偏移滤波功能 7.图像二值化功能 8.Canny边缘检测功能 9.直线检测功能 10.圆形检测功 ...
- 数字图像处理实验(总计23个)汇总
以下这些实验中的代码全部是我自己编写调试通过的,到此,最后进行一下汇总. 数字图像处理实验(1):PROJECT 02-01, Image Printing Program Based on Half ...
- 数字图像处理matlab实验对图像复原,数字图像处理实验07图像的复原处理
数字图像处理实验 一.数字图像处理实验 实验七 图像的复原处理 一.实验目的 熟悉几种在实际应用中比较重要的图像复原技术,学会用MATLAB复原函数对退化图像进行复原处理. 二.实验内容 1.用点扩散 ...
- 中南民族大学计算机图像处理实验报告,中南民族大学数字图像处理程序及图像...
数字图像处理实验课 matlab实验程序 以及图像结果 附带有命名图 仅供参考 定有错误 木有绝对正确 实验1 1-1 close all; clear; f=zeros(40,40);% f(10: ...
- 数字图像处理实验——Python语言实现
数字图像处理实验--Python语言实现 实验一:数字图像处理入门 实验二:直方图均衡 实验三:线性平滑和锐化--掩模法 实验四:非线性平滑--中值滤波 实验五:非线性锐化--梯度法 GitHub地址 ...
- 数字图像处理实验三图像增强
一.实验目的 (1)了解图像增强的目的及意义,加深对图像增强的 感性认识,巩固所学的图像增强的理论知识和相 关算法. (2)熟练掌握直方图均衡化和直方图规定化的计算过 程. (3)熟练掌握空域滤波中常 ...
- 数字图像处理实验四图像频域增强
一.实验目的 (1)了解图像增强的目的及意义,加深对图像增强的感性认识,巩固所学的图像增强的理论知识和相关算法. (2)熟练掌握低通.高通.带通.同态滤波器的使用方法,明确不同性质的滤波器对图像的影响 ...
- 数字图像处理实验5图像复原
一.实验目的 (1)了解图像复原的目的及意义,加深对图像复原理论的认识. (2)掌握维纳滤波复原基本原理. (3)掌握约束最小二乘方复原方法. (4)掌握盲解卷积复原方法 二.实验内容 (1)维纳滤 ...
最新文章
- [转载]Android开发常用调试技术记录
- 基本表改变视图不改变为什么_中国白酒包装是真的很丑吗,为什么不改变包装?...
- 用cascade删除有约束的表或记录
- 008_JavaScript输出
- 多窗体、窗体传值、打开唯一窗体操作
- 迭代器和生成器的区别
- 获取java异常堆栈信息_Java 实例 - 获取异常的堆栈信息
- 05_学生管理系统,xml读写,布局的综合应用
- java中的正则操作总结
- yii2基础之分页的基本使用及其配置详解
- 全国计算机OFFICE二级考试大纲,全国计算机等级考试二级MSOffice高级应用考试大纲...
- STM32——红外遥控器实验
- 灵异:各国家千年诅咒悬迷——不可思议
- java 命令行工具_分享java自带命令行工具jmap、jhat与jinfo的方法详解
- 建筑设计的未来是什么?| 建筑 · 人工智能专栏
- Ruby(了解第二天)
- 使用命令行强制注销远程登录用户
- EPICS记录参考--模拟输入记录(ai)
- 基于业务描述语言BDL的需求方法论
- uniapp 关于swiper组件和moveable-area、moveable-view组件搭配的图片预览高度集成组件