当前位置: 首页 > news >正文

计算机视觉实验:图像增强应用实践

本次实验主要从基于统计、函数映射的图像增强方法和基于滤波的图像增强方法两种方法中对一些图像增强的算法进行实现。主要的编程语言为python,调用了python自带的PIL图像库用于读取图像,利用numpy进行图像运算,最后使用opencv第三方库进行对比验证。下面为实验的详细步骤与过程。

基于统计、函数映射的图像增强方法

图像反转

所谓的图像反转是将颜色或灰度进行颠倒,如白色变成黑色,亮变暗暗变亮等等。其原理在于用255减去每个像素的颜色值或灰度值,从而达到反转的效果,R/G/B = 255 - R/G/B。下面使用代码进行实现(完整代码见 图片反转.py)。

  • 调用Image与numpy读取图像信息
  1.  img = np.array(Image.open(path))
  1. 根据shape判断是否是彩色图并用255减去颜色值
  1. if len(img.shape) > 2:
  2.         img = np.array(list(map(lambda x:list(map(lambda y:list(map(lambda z:255-z, y)), x)), img)))
  3. else:
  4.         img = np.array(list(map(lambda x:list(map(lambda y:255-y, x)) , img)))
  • 保存图像
  1. 下面的uint8是为了改变数据类型 否则会报错
  2. image = Image.fromarray(np.uint8(img))
  3. 保存图片
  4. image.save(f'./output/reverse/{path[7:]}')
  5. image.show()

调用opencv进行结果对比

代码如下所示,此代码调用了opencv库进行图像反转操作。完整代码见图片反转opencv.py

与上面的代码基本一致,不同点在于调用Opencv来代替Image与numpy的部分操作。其关键不同代码如下所示。

  1. 创建空图像
  2. dst = np.zeros((height, width, 3), np.uint8)
  3. for i in range(height):
  4.  for j in range(width):
  5.         (b, g, r) = img[i, j]
  6.         b = 255 - b
  7.         g = 255 - g
  8.         r = 255 - r
  9.         dst[i, j] = (b, g, r)
  10. 部分代码参考于https://laoai.blog.csdn.net/article/details/81133070

最后两者结果如下图图1所示

图1 图像反转结果对比图

从结果中可以看出,与原始图像相比颜色发生了很大的反转。而未用Openvc处理与使用了Opencv处理的结果是一样的。

直方图均衡化

直方图均衡化只要是让灰度能均匀分布而不是集中在某个范围内。使得某些地方特别亮某些特别暗。直方图均衡化的操作流程一般如下图图2所示,首先需要计算出目前原始图像的灰度直方图。然后对数量占比进行累加。累加得到的结果均在0-1之间。那么用255乘以结果,以获取最新的映射关系,此时再绘制直方图那么就可看出其分布更均匀。下面利用代码进行实现。

图2 直方图均衡化流程图

此处使用一张灰度图进行处理coins.png

  • 计算直方图

利用字典统计每个灰度值的数量映射

  1. def show_hist(img):
  2.     hist = collections.defaultdict(int)
  3.     for i in img:
  4.         for j in i:
  5.             hist[j] += 1
  6.     绘制直方图
  7.     plt.title('灰度直方图')
  8.     plt.xlabel('Bins')
  9.     plt.xlim([0256])
  10.     plt.ylabel('Pixels')
  11.     plt.bar(hist.keys(), hist.values())
  12.     plt.show()
  13.     return hist

 累加操作

  1. for i in range(256):
  2.     if i:
  3.         reduction_hist[i] = hist[i]+reduction_hist[i-1]
  4.     else:
  5.         reduction_hist[i] = hist[i]
  • 计算新的映射关系
  1. for index, i in enumerate(img):
  2.     for jndex, j in enumerate(i):
  3.         img[index][jndex] = reduction_hist[img[index][jndex]]*255

调用opencv进行结果对比

Opencv只需要调用下面的库函数即可进行直方图均衡化操作。详细代码可见直方图均衡化cv.py

  1. img = cv2.equalizeHist(img)

将原始图像、非opencv处理的直方图均衡化图像与opencv处理的直方图均衡化图像进行对比,如下图图3所示。可以看到后面两者与前面原始图像相比其直方图分布更均匀。而后面两者基本无差别。

图3 直方图均衡化结果对比图

伽马变换

伽马变换的数学公式如下所示,其中s为变换后的值,c为一常数此处取1,$\gamma$是用于控制变换幅度的,而r则是原图像的输入范围在0-1。

在查阅资料后发现,opencv并未自带伽马变换的相关函数,所以此处不进行与opencv的结果对比。根据学习发现,伽马变换需要进行以下步骤。

  • 图像数据归一化
  • 图像各像素点进行乘幂运算

最后代码如下:

  1. def gama_transfer(img,power1):
  2.     if len(img.shape) > 3:
  3.          img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
  4.     img = 255*np.power(img/255,power1)
  5.     img = np.around(img)
  6.     img[img>255] = 255
  7.     out_img = img.astype(np.uint8)
  8.     return out_img
  9. 参考于https://zhuanlan.zhihu.com/p/340513008?utm_id=0

结果输出如下图图4所示,

图4 伽马变换结果对比图

从图片对比中可以看出, 时暗部变量,对于此图可以看得更清晰, 时暗部变暗,图片则更难看清。

基于滤波的图像增强方法

均值滤波

均值滤波的原理在于将图像中的每个像素点的值都变成其周围n阶矩阵的平均值。所以在编程实现中,首先需要创建一个大小一样的0矩阵用以记录平均值。然后遍历一次图像,将计算得到的平均值填充进0矩阵中即可得到均值滤波的结果。其核心代码如下(完整可见`均值滤波.py`):

  1. for index in range(height):
  2.         for jndex in range(width):
  3.             判断是否为边界
  4.             if index <= int((kernel-1)/2) - 1 or index >= height - 1 - int((kernel-1)/2) \
  5.                     or jndex <= int((kernel-1)/2) - 1 or jndex >= height - int((kernel-1)/2) - 1:
  6.                 result[index, jndex] = img[index, jndex]
  7.             else:  均值值滤波
  8.                 result[index, jndex] = np.average(
  9.                     img[index - int((kernel-1)/2):index + int((kernel-1)/2) + 1,
  10.                     jndex - int((kernel-1)/2):jndex + int((kernel-1)/2) + 1])
  11. 部分参考于https://blog.csdn.net/qq_43633939/article/details/120854570

此处对于边界不做任何处理。上面的代码是针对灰度图的,若需要对彩色图片进行滤波处理,则可在后面加上三个通道即可如下面代码所示。

  1. for kndex in range(3):
  2.     result[index, jndex, kndex] = np.average(
  3.         img[index - int((kernel - 1) / 2):index + int((kernel - 1) / 2) + 1,
  4.             jndex - int((kernel - 1) / 2):jndex + int((kernel - 1) / 2) + 1, kndex])

调用opencv进行结果对比

均值滤波对于opencv存在一个函数调用,只需要指定滤波核即可进行操作。此处滤波核均选择3*3。

  1. import cv2
  2. path = './pics/save.bmp'
  3. # img = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
  4. img = cv2.imread(path)
  5. ksize = [3,3]
  6. dst=cv2.blur(img,ksize)
  7. cv2.imshow('img', dst)
  8. cv2.imwrite(f'./cv-output/mean-filtering/{path[7:]}', img)
  9. cv2.waitKey(0)

最后将输出结果进行对比,如下图图5所示。

图5 均值滤波结果对比图

可以看出原图和滤波后的图像差别还是很大的,原图的噪点颗粒很清晰,而滤波后则变得模糊。同时opencv的结果和自编代码的结果差别不大。

高斯滤波

高斯滤波的流程图如下图图6所示,

图6 高斯滤波流程图

对于高斯滤波首先需要根据下面的高斯公式计算出各点的高斯值,

其中x,y均是离中心点的距离,所以说对于整个图像高斯值是固定的。在得到这些值后,将他们的各自除以他们的和以进行归一化。最后中心值等于归一化的结果除以周围点颜色值后求和。根据以上思路可进行编程如下:

  • 计算高斯值
  1. kernel = 3
  2. sigma = 1.3
  3. K = np.zeros([kernel, kernel])
  4. 计算高斯值
  5. for x in range(-12):
  6.     for y in range(-1,2):
  7.         K[x+1, y+1] = np.exp( -(x ** 2 + y ** 2) / (2 * (sigma ** 2)))

  • 归一化
  1. 归一化
  2. K = K/np.sum(K)
  • 加权求和
  1. result[index, jndex] = np.sum(K*img[index - int((kernel-1)/2):index + int((kernel-1)/2) + 1,
  2.                     jndex - int((kernel-1)/2):jndex + int((kernel-1)/2) + 1])

完整代码可见于`高斯滤波.py`

调用opencv进行结果对比

对于opencv高斯滤波只需要一个函数即可进行。完整代码见高斯滤波cv.py。

  1. result = cv2.GaussianBlur(img, (33), 1.3)

最后输出结果如下图图7所示,

图7 高斯滤波结果对比图

可以看到和原图相比高斯滤波后的结果变得模糊,同时有些噪点也变得不明显。高斯滤波的结果和opencv的结果基本一致。

实验结论或体会

本次实验完成了图像反转、直方图均衡化、伽马变换、均值滤波、高斯滤波五种图像增强方法的代码实现。并将输出的图片与opencv的结果进行对比发现基本一致,说明本次实验编程实现的方法基本与实际相符合。同时图像增强后的图像与原图进行对比,可以看出不同增强方法的作用,比如说高斯滤波可以减弱图像的噪点,伽马变换可以让原图的暗部或亮部细节更突出以获得隐藏的信息,直方图均衡化可以让图像亮度或颜色分布更均匀使得图像原本不能看出的细节可清晰显示等等。

在此次实验中,对图像进行增强需要用到python的PIL库和numpy库,这些的使用让我们更加地了解图像处理的方式。同时通过对这些库的练习也让我更加熟练地直接操作图像的像素点。理论课中讲解的关于图像增强方法的知识,在代码编辑实现过程中均得以体现,通过实验对理论知识理解也更加深入。总而言之,此次的实验让我对图像增强方法以及图像的处理方法有了更加深入的了解。

相关文章:

计算机视觉实验:图像增强应用实践

本次实验主要从基于统计、函数映射的图像增强方法和基于滤波的图像增强方法两种方法中对一些图像增强的算法进行实现。主要的编程语言为python&#xff0c;调用了python自带的PIL图像库用于读取图像&#xff0c;利用numpy进行图像运算&#xff0c;最后使用opencv第三方库进行对…...

ES6:Generator函数详解

ES6&#xff1a;Generator函数详解 1、 概念2、yield表达式2.1 yield 语句与 return 语句区别2.2 Generator函数不加yield语句&#xff0c;这时变成了一个单纯的暂缓执行函数2.3 yield 表达式只能用在 Generator 函数里面&#xff0c;用在其它地方都会报错2.4 yield 表达式如果…...

前端小练-产品宣传页面

文章目录 前言页面结构固定钉头部轮播JS特效 完整代码总结 前言 经过一个月的爆肝&#xff0c;花费了一个月&#xff08;期间还花费了将近半个月的时间打比赛&#xff0c;还要备研&#xff09;算是把数二高数的内容强化了一遍&#xff0c;接下来刷熟练度即可&#xff0c;可惜的…...

arm学习之stm32设备树学习-中断控制led灯亮灭+字符设备指令控制led灯亮灭

中断控制led灯亮灭 驱动文件源码 led-key.c #include<linux/init.h> #include<linux/module.h> #include<linux/of.h> #include<linux/of_gpio.h> #include<linux/gpio.h> #include<linux/of_irq.h> #include<linux/interrupt.h> s…...

快速开发框架若依的基础使用详解

Hi I’m Shendi 快速开发框架若依的基础使用详解 最近在为公司制作新的项目&#xff0c;经过了一段时间的技术沉淀&#xff0c;我开始尝试接触市面上用的比较多的快速开发框架&#xff0c;听的最多的当属若依吧 于是就选用了若依 介绍 为什么选&#xff1f;目的是为了提高开发…...

RabbitMQ 教程 | 第4章 RabbitMQ 进阶

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的编码爱好者 大家好&#xff0c;我是 DevO…...

小程序如何从分类中移除商品

​有时候商家可能需要在商品分类中删除某些商品&#xff0c;无论是因为商品已下架、库存不足还是其他原因。在这篇文章中&#xff0c;我们将介绍如何从分类中移除商品。 方式一&#xff1a;分类管理中删除商品。 进入小程序管理后台&#xff0c;找到分类管理&#xff0c;在分…...

P1219 [USACO1.5] 八皇后 Checker Challenge

题目 思路 非常经典的dfs题&#xff0c;需要一点点的剪枝 剪枝①&#xff1a;行、列&#xff0c;对角线的标记 剪枝②&#xff1a;记录每个皇后位置 代码 #include<bits/stdc.h> using namespace std; const int maxn105; int a[maxn];int n,ans; bool vis1[maxn],vis…...

如何在不使用脚本和插件的情况下手动删除 3Ds Max 中的病毒?

如何加快3D项目的渲染速度&#xff1f; 3D项目渲染慢、渲染卡顿、渲染崩溃&#xff0c;本地硬件配置不够&#xff0c;想要加速渲染&#xff0c;在不增加额外的硬件成本投入的情况下&#xff0c;最好的解决方式是使用渲云云渲染&#xff0c;在云端批量渲染&#xff0c;批量出结…...

SpringCloud Gateway 在微服务架构下的最佳实践

作者&#xff1a;徐靖峰&#xff08;岛风&#xff09; 前言 本文整理自云原生技术实践营广州站 Meetup 的分享&#xff0c;其中的经验来自于我们团队开发的阿里云 CSB 2.0 这款产品&#xff0c;其基于开源 SpringCloud Gateway 开发&#xff0c;在完全兼容开源用法的前提下&a…...

Android studio修改app图标

步骤如下&#xff1a; 1.右键app名称→New→ImageAsset 2. 进行下面的配置 图源&#xff1a;https://blog.csdn.net/Qingshan_z/article/details/126661650 3.配置分辨率 4.图标自动保存在mipmap文件夹下 再启动就更换成功了&#xff01;&#xff01;&#xff01; 参考&…...

<C++> 三、内存管理

1.C/C内存分布 我们先来看下面的一段代码和相关问题 int globalVar 1; static int staticGlobalVar 1; void Test() {static int staticVar 1;int localVar 1;int num1[10] {1, 2, 3, 4};char char2[] "abcd";const char *pChar3 "abcd";int *ptr1…...

大模型开发(十五):从0到1构建一个高度自动化的AI项目开发流程(上)

全文共5600余字&#xff0c;预计阅读时间约13~20分钟 | 满满干货(附全部代码)&#xff0c;建议收藏&#xff01; 本文目标&#xff1a;提出一种利用大语言模型(LLMs)加快项目的开发效率的解决思路&#xff0c;本文作为第一部分&#xff0c;主要集中在如何完整的执行引导Chat模…...

HarmonyOS 开发基础(二)组件拼凑简单登录页面

一、简单登录页面 Entry Component /* 组件可以基于struct实现&#xff0c;组件不能有继承关系&#xff0c;struct可以比class更加快速的创建和销毁。*/ struct Index {State message: string Hello Worldbuild() {// https://developer.harmonyos.com/cn/docs/documentation/…...

flutter minio

背景 前端 经常需要上传文件 图片 视频等等 到后端服务器&#xff0c; 如果到自己服务器 一般会有安全隐患。也不方便管理这些文件。如果要想使用一些骚操作 比如 按照前端请求生成不同分辨率的图片&#xff0c;那就有点不太方便了。 这里介绍以下 minio&#xff0c;&#xff0…...

ChatGPT:人工智能交互的新时代

ChatGPT的背景和发展&#xff1a; ChatGPT是OpenAI公司在GPT-3基础上的进一步升级。GPT&#xff08;Generative Pre-trained Transformer&#xff09;是一种基于Transformer架构的深度学习模型&#xff0c;它能够处理自然语言&#xff0c;实现自动对话、写作等任务。而ChatGPT在…...

C. Binary String Copying - 思维

分析&#xff1a; 赛时我是直接模拟的&#xff0c;tle然后mle&#xff0c;补提&#xff0c;发现规律&#xff0c;每一个改变的字符串都只会对应一个需要改变的区间&#xff0c;例如第一个样例前两个101100 -> 011100和101100 -> 011100&#xff0c;对应区间在确定改变的范…...

哈工大计算机网络课程网络安全基本原理详解之:密钥分发中心与公钥认证中心

哈工大计算机网络课程网络安全基本原理详解之&#xff1a;密钥分发中心与公钥认证中心 在介绍密钥分发中心的概念前&#xff0c;先来回顾一下之前介绍的身份认证协议AP4.0&#xff1a;利用随机数R来避免“回放攻击”&#xff0c;并借助于对称加密算法来保证R的加密传输和解密&…...

md5sum

概念作用及原理 md5sum是一种常用的哈希算法&#xff0c;用于计算数据的MD5哈希值。MD5&#xff08;Message Digest Algorithm 5&#xff09;是一种广泛使用的加密散列函数&#xff0c;用于将任意长度的数据映射为固定长度的哈希值&#xff08;通常是128位&#xff09;。这个哈…...

图文档数字化:实现高效管理的几大步骤

在当今数字化时代&#xff0c;企业越来越意识到数字化管理对于图文档的重要性。传统的纸质文件管理往往效率低下&#xff0c;容易出现丢失和混乱的情况。为了提高工作效率、降低成本并确保数据安全&#xff0c;许多企业选择采用PDM&#xff08;产品数据管理&#xff09;系统来实…...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解

在 C/C 编程的编译和链接过程中&#xff0c;附加包含目录、附加库目录和附加依赖项是三个至关重要的设置&#xff0c;它们相互配合&#xff0c;确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中&#xff0c;这些概念容易让人混淆&#xff0c;但深入理解它们的作用和联…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…...

c++第七天 继承与派生2

这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分&#xff1a;派生类构造函数与析构函数 当创建一个派生类对象时&#xff0c;基类成员是如何初始化的&#xff1f; 1.当派生类对象创建的时候&#xff0c;基类成员的初始化顺序 …...

nnUNet V2修改网络——暴力替换网络为UNet++

更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...