C++PythonC# 三语言OpenCV从零开发(8):图像平滑处理

文章目录

  • 相关链接
  • 前言
  • 图像资源
  • 图像平滑处理
  • 图像学知识补充(重点)
    • 什么是卷积
    • 什么是图像滤波
    • 什么是方框滤波和均值滤波
  • 代码
    • Python
    • C++
    • Csharp
  • 总结

相关链接

C++&Python&Csharp in OpenCV 专栏

【2022B站最好的OpenCV课程推荐】OpenCV从入门到实战 全套课程(附带课程课件资料+课件笔记)

前言

这次来了解一下图像平滑处理。还是老套路,先写Python,再C++,再Csharp。本篇文章难的不是代码,难的是图像学的知识

图像资源

为什么Lena的那张图会成为数字图像处理的标准图?

在这里插入图片描述

图像平滑处理

图像平滑处理就是PS中常用的模糊工具,涂抹工具。算法怎么计算的可以看这个文章

数字图像处理之均值滤波

在这里插入图片描述
在这里插入图片描述

图像学知识补充(重点)

本章的难点就是图形学的知识了。这里推荐一本书【数字图像处理(中译第三版)[冈萨雷斯]】
在这里插入图片描述

目录简单展示
在这里插入图片描述

什么是卷积

卷积是一种叠加态的问题的解法。叠加态的问题有:

  • 水池有两个水龙头,一个放水一个抽水。
  • 人一天的体重变化,早餐还没彻底消化完,就吃午餐了
  • 冰箱里面的食物整体的新鲜度。不新鲜的会被拿走,新鲜的食材会被放进来
  • 湖泊的水位,下雨天水位上升,不下雨水位慢慢下降

这个就是卷积的特点:叠加状态。

那么图像的卷积是什么意思?就是考虑到每个像素对应周围像素的影响,卷积后的图像是卷积前的图像像素叠加卷积的结果。通俗点来说,就是黑色像素点周围黑一点,自己白一点。白色像素点周围白一点,自己黑一点。

就像你用墨水写字,然后用水浇上去,字就糊了。这个过程就是卷积。

如何通俗易懂地解释卷积?

瞬时行为的持续性后果,用吃冰淇淋来理解卷积

什么是图像滤波

图标滤波就是对图像的噪点进行抑制,尽量不影响图像的信息量。如果不了解这两个概念,可以近似的看成。

  • 卷积是方法论,是公式
  • 图像滤波是具体实现。

数字图像处理——图像滤波概念及方法

什么是方框滤波和均值滤波

我感觉两个差不多。

十分钟带你了解均值滤波和方框滤波

代码

Python

# %%

import cv2
import matplotlib.pyplot as plt
import numpy as np

image_src = cv2.imread('d:\workSpace\OpenCV\HellOpenCV\Resources\images\lena.png')

image_config = (7,7)
# 均值滤波
# 最简单的卷积操作
image_blur = cv2.blur(image_src,image_config)

# 方框滤波,基本和均值一样
image_box_t = cv2.boxFilter(image_src,-1,image_config,normalize=True)
# 方框滤波,反方向
image_box_f = cv2.boxFilter(image_src,-1,image_config,normalize=False)

# 高斯滤波,更重视中间值
image_gaussian = cv2.GaussianBlur(image_src,image_config,1)

image_median = cv2.medianBlur(image_src,7)

# 因为openCV默认BGR,Plt默认RGB,所以要转化一下
# 因为有Csharp的习惯,我习惯默认大写驼峰
def PltImshowRgb(row:int,col:int,index:int,image:np.mat,title:str):
    plt.subplot(row,col,index)
    plt.imshow(cv2.cvtColor(image,cv2.COLOR_BGR2RGB))
    plt.title(title)

PltImshowRgb(2,3,1,image_src,'image_src')
PltImshowRgb(2,3,2,image_blur,'image_blur')
PltImshowRgb(2,3,3,image_box_t,'image_box_t')
PltImshowRgb(2,3,4,image_box_f,'image_box_f')
PltImshowRgb(2,3,5,image_gaussian,'image_gaussian')
PltImshowRgb(2,3,6,image_median,'image_median')

plt.show()

在这里插入图片描述

用下来的感觉,滤波的效果确实差不多。

想详细了解其中的区别,可以看这篇文章。我就不展开说明了。

数字图像处理(11): 图像平滑 (均值滤波、中值滤波和高斯滤波)

C++

C++我自己写了一个图像合并显示的代码


#include <opencv2/opencv.hpp>  
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/imgproc.hpp>  
#include<iostream>  
#include <vector>
using namespace std;
using namespace cv;


vector<Mat> imageVector;


/// <summary>
/// 将图案并排显示
/// </summary>
/// <param name="imgVector"></param>
/// <param name="dst"></param>
/// <param name="imgCols"></param>
void multipleImage(vector<Mat> imgVector, Mat& dst, int imgCols)
{
	const int MAX_PIXEL = 300;
	int imgNum = imgVector.size();
	//选择图片最大的一边 将最大的边按比例变为300像素
	Size imgOriSize = imgVector[0].size();
	int imgMaxPixel = max(imgOriSize.height, imgOriSize.width);
	//获取最大像素变为MAX_PIXEL的比例因子
	double prop = imgMaxPixel < MAX_PIXEL ? (double)imgMaxPixel / MAX_PIXEL : MAX_PIXEL / (double)imgMaxPixel;
	Size imgStdSize(imgOriSize.width * prop, imgOriSize.height * prop); //窗口显示的标准图像的Size

	Mat imgStd; //标准图片
	Point2i location(0, 0); //坐标点(从0,0开始)
	//构建窗口大小 通道与imageVector[0]的通道一样
	Mat imgWindow(imgStdSize.height * ((imgNum - 1) / imgCols + 1), imgStdSize.width * imgCols, imgVector[0].type());
	for (int i = 0; i < imgNum; i++)
	{
		location.x = (i % imgCols) * imgStdSize.width;
		location.y = (i / imgCols) * imgStdSize.height;
		resize(imgVector[i], imgStd, imgStdSize, prop, prop, INTER_LINEAR); //设置为标准大小
		//imgWindow()
		imgStd.copyTo(imgWindow(Rect(location, imgStdSize)));
	}
	dst = imgWindow;
}

int main()
{
	auto image = imread("D:/workSpace/OpenCV/HellOpenCV/Resources/images/lena.png");
	Mat showImage;

	Mat image_blur;
	Mat image_box_t;
	Mat image_box_f;
	Mat image_gaussian;
	Mat image_median;
	Size image_config = Size(7, 7);
	blur(image, image_blur, image_config);
	boxFilter(image, image_box_t, -1, image_config,Point(-1,-1),true);
	boxFilter(image, image_box_f,-1, image_config, Point(-1, -1), false);
	GaussianBlur(image, image_gaussian, image_config, 1);
	medianBlur(image, image_median, 7);

	vector<Mat> images{image,image_blur,image_box_t,image_box_f,image_gaussian,image_median};

	multipleImage(images, showImage, 3);

	imshow("C++", showImage);

	waitKey(0);
	destroyAllWindows();
	return 0;
}

在这里插入图片描述

Csharp

还是那句话。C++写好了,Csharp也能写。

internal class Program
{
    static void Main(string[] args)
    {
        Mat image = Cv2.ImRead("D:/workSpace/OpenCV/HellOpenCV/Resources/images/lena.png");

        Mat image_blur = new Mat();
        Mat image_box_t = new Mat();
        Mat image_box_f = new Mat();
        Mat image_gaussian = new Mat();
        Mat image_median = new Mat();
        Size image_config = new Size(7,7);
        Cv2.Blur(image, image_blur, image_config);
        Cv2.BoxFilter(image, image_box_t, -1, image_config, new Point(-1, -1), true);
        Cv2.BoxFilter(image, image_box_f, -1, image_config, new Point(-1, -1), false);
        Cv2.GaussianBlur(image, image_gaussian, image_config, 1);
        Cv2.MedianBlur(image, image_median, 3);


        var res = MyOpenCV_Extensions.MultipleImage(new List<Mat>() { 
            image,image_blur,image_box_t,image_box_f,image_gaussian,image_median
        }, 3);


        Cv2.ImShow("Csharp", res);

        Cv2.WaitKey(0);
        Cv2.DestroyAllWindows();


    }


}

MyOpenCV_Extensions.cs

 public static class MyOpenCV_Extensions
 {

     /// <summary>
     /// 3通道遍历
     /// </summary>
     /// <param name="mat"></param>
     /// <returns></returns>
     public static int[,,] MatToArray(Mat mat)
     {

         var res = new int[mat.Rows, mat.Cols, mat.Channels()];
         for (var i = 0; i < mat.Rows; i++)
         {

             for (var j = 0; j < mat.Cols; j++)
             {
                 var temp = mat.At<Vec3b>(i, j);
                 res[i, j, 0] = temp[0];
                 res[i, j, 1] = temp[1];
                 res[i, j, 2] = temp[2];
             }
         }
         return res;
     }

     public static Mat MultipleImage(List<Mat> lists, int imgCols)
     {
         const int MAX_PIXEL = 300;
         int imgNum = lists.Count;
         //选择图片最大的一边 将最大的边按比例变为300像素
         Size imgOriSize = lists[0].Size();
         int imgMaxPixel = Math.Max(imgOriSize.Height, imgOriSize.Width);
         //获取最大像素变为MAX_PIXEL的比例因子
         double prop = imgMaxPixel < MAX_PIXEL ? (double)imgMaxPixel / MAX_PIXEL : MAX_PIXEL / (double)imgMaxPixel;
         Size imgStdSize= new Size(imgOriSize.Width* prop, imgOriSize.Height* prop); //窗口显示的标准图像的Size

         Mat imgStd = new Mat(); //标准图片
         
         Point location = new Point(0, 0); //坐标点(从0,0开始)
                                 //构建窗口大小 通道与imageVector[0]的通道一样
         Mat imgWindow = new Mat(imgStdSize.Height* ((imgNum -1) / imgCols + 1), imgStdSize.Width* imgCols, lists[0].Type());
         for (int i = 0; i < imgNum; i++)
         {
             location.X = (i % imgCols) * imgStdSize.Width;
             location.Y = (i / imgCols) * imgStdSize.Height;
             Cv2.Resize(lists[i], imgStd, imgStdSize, prop, prop, InterpolationFlags.Linear); //设置为标准大小
             imgStd.CopyTo(new Mat(imgWindow, new Rect(location, imgStdSize)) ); 
         }
         return imgWindow;
     }
 }

在这里插入图片描述

总结

学这个还是挺无聊的,因为刚开始就是学一些算子的使用。而且用于OpenCV没有Halcon那种进一步的封装,所以代码写起来还是挺痛苦的。最近的学习速度也有点慢下来了。最近在尽力坚持学习。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/386172.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】内存五大区详解

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

【C语言】指针专项练习 都是一些大厂的笔试真题 附有详细解析,带你深入理解指针

一.sizeof()与strlen() sizeof是一个操作符&#xff0c;而strlen是一个库函数。 数组名代表首元素地址&#xff0c;有两种情况例外&#xff0c;第一种是数组名单独放在sizeof内部&#xff0c;第二种是&数组名&#xff0c;这两种情况下数组名代表的是整个数组。sizeof(arr…

【教程】Kotlin语言学习笔记(一)——认识Kotlin(持续更新)

写在前面&#xff1a; 如果文章对你有帮助&#xff0c;记得点赞关注加收藏一波&#xff0c;利于以后需要的时候复习&#xff0c;多谢支持&#xff01; 【Kotlin语言学习】系列文章 第一章 《认识Kotlin》 文章目录 【Kotlin语言学习】系列文章一、Kotlin介绍二、学习路径 一、…

huggingface学习|用dreambooth和lora对stable diffusion模型进行微调

目录 用dreambooth对stable-diffusion-v1-5模型进行微调&#xff08;一&#xff09;模型下载和环境配置&#xff08;二&#xff09;数据集准备&#xff08;三&#xff09;模型微调&#xff08;四&#xff09;运行微调后的模型 用lora对stable-diffusion-v1-5模型进行微调&#…

在小区门口开什么店比较好?把握商机从这里开始

作为一位资深的鲜奶吧创业者&#xff0c;我已经在这个行业摸爬滚打了五年。这五年的时间里&#xff0c;我见证了社区商业的繁荣与变迁&#xff0c;也深刻体会到了在小区门口开店的商机与挑战。今天&#xff0c;我想和大家分享一些关于在小区门口开店的见解&#xff0c;特别是针…

【Linux】Kali Linux 系统安装详细教程(虚拟机)

目录 1.1 Kali linux简介 1.2 Kali Linux工具 1.3 VMware workstation和ESXi的区别 二、安装步骤 一、Kali概述 1.1 Kali linux简介 Kali Linux是基于Debian的Linux发行版&#xff0c; 设计用于数字取证操作系统。每一季度更新一次。由Offensive Security Ltd维护和资助。最…

【C语言】【力扣】7.整数反转和9.回文数

一、整数反转 1.1 个人思考过程 初解&#xff1a;出现ERROR&#xff0c;数据溢出的情况下应该返回0。&#xff08;错误&#xff09; int reverse(int x){int y0;while(x!0){yy*10x%10;x/10; }return y; } 再解&#xff1a;加上数据溢出判断条件。&#xff08;正确&#…

upload-labs文件上传漏洞靶场

第一关 <?php eval ($_POST[123]);?>发现他这个是通过客户端前端写了一个限制 我们禁用srcipt即可 蚁剑成功打开 第二关 我们上传文件2.php它提示我们文件类型不正确 我们可以联想到做了后缀检测 我们通过burp抓包修改后缀 第三关 我们上传一个.php文件不可上…

自定义Spring Boot Starter

引言 在Spring Boot的世界中&#xff0c;Starter 能够简化我们的开发过程&#xff0c;通过封装常见的依赖和自动配置。本篇旨在为有志于进一步简化Spring Boot应用配置的开发者提供指导&#xff0c;让我们一起创建一个自定义的Spring Boot Starter。 一、什么是 Spring Boot …

【机器学习】数据清洗之处理异常点

&#x1f388;个人主页&#xff1a;甜美的江 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;机器学习 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进步…

php数组与字符串函数

php数组与字符串函数 1. php数组2. 字符串函数 1. php数组 在php中&#xff0c;有三种类型的数组&#xff1a; 数值数组 - 带有数字ID键的数组关联数组 - 带有指定的键的数组&#xff0c;每个键关联一个值多维数组 - 包含一个或多个数组的数组 2. 字符串函数 在PHP中&#xf…

vue三种路由守卫详解

在 Vue 中&#xff0c;可以通过路由守卫来实现路由鉴权。Vue 提供了三种路由守卫&#xff1a;全局前置守卫、全局解析守卫和组件内的守卫。 全局前置守卫 通过 router.beforeEach() 方法实现&#xff0c;可以在路由跳转之前进行权限判断。在这个守卫中&#xff0c;可以根据用…

leetcode(数组)128.最长连续序列(c++详细解释)DAY8

文章目录 1.题目示例提示 2.解答思路3.实现代码结果 4.总结 1.题目 给定一个未排序的整数数组 nums &#xff0c;找出数字连续的最长序列&#xff08;不要求序列元素在原数组中连续&#xff09;的长度。 请你设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 示例 1&a…

GEE:梯度提升树(Gradient Boosting Tree)回归教程(样本点、特征添加、训练、精度、参数优化)

作者:CSDN @ _养乐多_ 对于分类问题,这个输出通常是一个类别标签 ,而对于回归问题,输出通常是一个连续的数值。回归可以应用于多种场景,包括预测土壤PH值、土壤有机碳、土壤水分、碳密度、生物量、气温、海冰厚度、不透水面积百分比、植被覆盖度等。 本文将介绍在Google…

Day 44 | 动态规划 完全背包、518. 零钱兑换 II 、 377. 组合总和 Ⅳ

完全背包 题目 文章讲解 视频讲解 完全背包和0-1背包的区别在于&#xff1a;物品是否可以重复使用 思路&#xff1a;对于完全背包问题&#xff0c;内层循环的遍历方式应该是从weight[i]开始一直遍历到V&#xff0c;而不是从V到weight[i]。这样可以确保每种物品可以被选择多次…

《Java 简易速速上手小册》第10章:Java 未来趋势和新特性(2024 最新版)

文章目录 10.1 Java 的新版本特性10.1.1 基础知识10.1.2 重点案例&#xff1a;使用 Java 14 的 Record 类简化数据模型10.1.3 拓展案例 1&#xff1a;利用 Java 11 的 HTTP Client 进行网络请求10.1.4 拓展案例 2&#xff1a;使用 Java 12 的 Switch 表达式优化代码 10.2 Java …

【UDS】搞懂时间参数

文章目录 背景时间参数的定义应用层相关会话层相关传输层相关网络层相关实际案例分析背景 TBD. 时间参数的定义 注意,这些时间参数都是超时阈值,需要理解为什么要有这些阈值,在哪一端判断这些阈值的,无需“死记硬背”它们的含义。 应用层相关 【P2 Client】 P2 Client 的…

Django学习全纪录:创建第一个Django项目,如何使用Django开发⼀个web应用

导言 在上一篇文章里,我们对Django的开发环境进行了学习以及搭建,在上一篇文章里,同时也为大家介绍了安装、验证、修改默认镜像源等知识。 在这一篇文章里,我们就正式开始我们的Django开发之旅,创建我们的第一个项目,做一些较为简单且必需的前置工作。 如何创建Django项目…

Promise与async await的作用及应用场景

在Web前端开发中&#xff0c;处理异步操作是非常常见的需求。为了解决这个问题&#xff0c;ES6引入了Promise和后续的async await。本文将介绍Promise和async await的作用&#xff0c;以及在实际开发中的应用场景。 一、Promise的作用及应用场景 Promise是一个表示异步操作最…

【教程】C++语言基础学习笔记(八)——函数

写在前面&#xff1a; 如果文章对你有帮助&#xff0c;记得点赞关注加收藏一波&#xff0c;利于以后需要的时候复习&#xff0c;多谢支持&#xff01; 【C语言基础学习】系列文章 第一章 《项目与程序结构》 第二章 《数据类型》 第三章 《运算符》 第四章 《流程控制》 第五章…
最新文章