使用Numpy和Opencv完成图像的基本数据分析(Part III)

简介: 使用Numpy和Opencv完成图像的基本数据分析第三部分,主要包含图像变换、卷积操作等。

0

引言

       本文是使用python进行图像基本处理系列的第三部分,在本人之前的文章里介绍了一些非常基本的图像分析操作,见文章《使用Numpy和Opencv完成图像的基本数据分析Part I》和《使用Numpy和Opencv完成图像的基本数据分析 Part II》,下面我们将继续介绍一些有关图像处理的好玩内容。
       本文介绍的内容基本反映了我本人学习的图像处理课程中的内容,并不会加入任何工程项目中的图像处理内容,本文目的是尝试实现一些基本图像处理技术的基础知识,出于这个原因,本文继续使用 SciKit-Image,numpy数据包执行大多数的操作,此外,还会时不时的使用其他类型的工具库,比如图像处理中常用的OpenCV等:
       本系列分为四个部分,分别为part I、part II、part III及part IV。刚开始想把这个系列分成两个部分,但由于内容丰富且各种处理操作获得的结果是令人着迷,因此不得不把它分成四个部分。系列所有的源代码地址:GitHub-Image-Processing-Python
       在上一篇文章中,我们已经完成了以下一些基本操作。为了跟上今天的内容,回顾一下之前的基本操作:

       现在开始本节的内容:

强度变换|Intensity Transformation

       首先导入一张图像作为开始:

%matplotlibinline

import imageio
import matplotlib.pyplot as plt
import warnings
import matplotlib.cbook
warnings.filterwarnings("ignore",category=matplotlib.cbook.mplDeprecation)

pic=imageio.imread('img/parrot.jpg')

plt.figure(figsize=(6,6))
plt.imshow(pic);
plt.axis('off');
AI 代码解读

1

图像底片|Image Negative

       强度变换函数在数学上定义为:

S = T(r)


       其中r是输入图像的像素,S是输出图像的像素,T是一个转换函数,它将r的每个像素值映射到s中对应的像素值。
       负变换,即恒等变换的逆。在负变换中,输入图像的每个像素值从L-1中减去并映射到输出图像上。
       在这种情况下,完成以下转换:

S =(L-1)-r


       因此,每个像素值都减去255。这样的操作导致的结果是,较亮的像素变暗,较暗的图像变亮,类似于图像底片。
negative =255- pic # neg = (L-1) - img

plt.figure(figsize= (6,6))
plt.imshow(negative);
plt.axis('off');
AI 代码解读

2

对数变换|Log transformation

       对数转换可以通过以下公式定义:

s = c *log(r + 1)


       其中s和r是输出和输入图像的像素值,c是常数。输入图像的每个像素值都会加1,之后再进行对数操作,这是因为如果图像中的像素值为0时,log(0)的结果等于无穷大。因此,为了避免这种情况的发生,输入图像中的每个像素值都加1,使最小像素值至少为1。
       在对数变换过程中,与较高像素值相比,图像中的低像素被扩展。较高的像素值在对数变换中被压缩,这导致图像增强。
       对数变换中的c值调整了我们想要的增强程度:
%matplotlibinline

import imageio
import numpyasnp
import matplotlib.pyplotasplt

pic=imageio.imread('img/parrot.jpg')
gray=lambdargb:np.dot(rgb[...,:3],[0.299,0.587,0.114])
gray=gray(pic)


'''
log transform
-> s = c*log(1+r)

So, we calculate constant c to estimate s
-> c = (L-1)/log(1+|I_max|)

'''


max_=np.max(gray)

def log_transform():
return(255/np.log(1+max_))*np.log(1+gray)

plt.figure(figsize=(5,5))
plt.imshow(log_transform(),cmap=plt.get_cmap(name='gray'))
plt.axis('off');
AI 代码解读

3

伽马校正| Gamma Correction

       伽马校正,或通常简称为伽玛,是用于对视频或静止图像系统中的亮度或三刺激值进行编码和解码的非线性操作,伽玛校正也称为幂律变换。首先,图像的像素值大小范围必须从0~255被缩放至0~1.0。然后,通过应用以下等式获得伽马校正后的输出图像:

Vo = Vi ^(1 / G)


       其中Vi是我们的输入图像,G是设置的伽玛值,然后将输出图像Vo缩放回0-255范围。
       对于伽马值而言,G <1有时被称为编码伽玛,并且利用该压缩幂律非线性进行编码的过程被称为伽马压缩; Gamma值小于1会将图像移向光谱的较暗端。
相反,伽马值G> 1被称为解码伽马,并且膨胀幂律非线性的应用被称为伽马展开。Gamma值大于1将使图像显得更亮。将伽玛值设置为G = 1时对输入图像没有影响:
import imageio
import matplotlib.pyplotasplt

# Gamma encoding 
pic=image io.imread('img/parrot.jpg')
gamma=2.2# Gamma < 1 ~ Dark ; Gamma > 1 ~ Bright

gamma_correction=((pic/255)**(1/gamma))
plt.figure(figsize=(5,5))
plt.imshow(gamma_correction)
plt.axis('off');
AI 代码解读

4

伽马校正的原因|Reason for Gamma Correction

       我们应用伽马校正的原因是,由于我们的眼睛感知颜色和亮度这一过程与数码相机中的传感器的工作原理不同。当数码相机上的传感器获得两倍的光子量时,信号会加倍。但是,我们人类的眼睛的工作原理与这不同,当我们的眼睛感知两倍的光量时,视野中只有一小部分显得更亮。因此,数码相机在亮度之间具有线性关系,而我们人类的眼睛具有非线性关系。为了解释这种关系,我们应用伽玛校正。
       还有一些其他的线性变换函数,比如:

  • 对比度拉伸(Contrast Stretching)
  • 强度切片(Intensity-Level Slicing)
  • 位平面切片(Bit-Plane Slicing)

卷积|Convolution

       在上一篇文章中,对卷积操作作了简要讨论。当计算机看到图像时,它看到不是一整幅图像,它的眼里看到的只是一个像素值数组。假设读取一个32X32大小的彩色图像,根据图像的分辨率和大小,计算机它将看到一个32 x 32 x 3维的数字数组,其中3表示RGB值或三通道。假设现在我们有一个PNG格式的彩色图像,它的大小是480 x 480。将其读入后,其表示数组将是480 x 480 x 3维。数组中的所有的每个数字值范围都在0到255之间,它描述的是那个点的像素强度。
       就像我们刚才提到的那样,假设输入图像是一个32 x 32 x 3的像素值数组,解释卷积的最佳方法是想象一个闪烁在图像左上方的手电筒。假设手电筒照射区域大小为3 x 3。现在,让我们假设这个手电筒滑过输入图像的所有区域。在机器学习术语中,这个手电筒被称为过滤器(filter)或内核(kernel),或者有时被称为权重(weights) 或  掩模(mask),它所照射的区域称为 感受野(receptive field)
       现在,此过滤器也是一个数字数组,数组中的数字称为权重或参数,在这里要着重注意一点,此过滤器的深度必须与输入图像的深度相同,即通道数相同,因此此过滤器的尺寸为3 x 3 x 3。
       图像内核 或过滤器是一个小矩阵,用于应用我们可能在Photoshop或Gimp中找到的效果,例如模糊、锐化、轮廓或浮雕等。此外,它们还被用于在机器学习中进行图像特征提取(CNN),这是一种用于确定图像最重要部分的技术。更多相关信息,请查看Gimp关于使用Image kernel的文档,我们可以该文档中找到最常见的内核列表  。
       现在,让我们将过滤器放在图像的左上角。当滤波器围绕输入图像滑动或卷积时,它将滤波器中的值乘以图像的原始像素值(也称为计算元素乘法)。这些乘法操作最后都会求和,所以卷积操作后只得到一个数字值。请记住,此数字仅代表过滤器位于图像的左上角。现在,我们对输入图像上的每个位置重复此过程,移动过滤器使其与图像矩阵的每个像素值进行卷积操作,这个过程需要设置移动步幅,依此类推,完成整幅图像的卷积操作。输入图中的每个唯一位置都会生成一个数字。步幅的取值一般为1,也可以取其它大小的值,但我们关心的是它是否适合输入图像。

5


       过滤器滑过输入图像上的所有位置后,我们会发现,我们剩下的是一个30 x 30 x 1的数组,我们将其称为激活图 或特征图。将3 x 3过滤器可以放在32 x 32输入图像上,可以得到30 x 30大小的阵列,原因是有300个不同的位置,这900个数字映射到30 x 30阵列。我们可以通过以下方式计算卷积图像后图像的大小:
  • 卷积:(N-F)/ S + 1

       其中N和F分别代表输入图像大小和卷积核大小,S代表步幅或步长。因此,对于上述情况,输出图像的大小将是

  • 32-31 + 1 = 30

       假设我们有一个3x3滤波器,在5x5大小的矩阵上进行卷积,根据等式,我们应该得到一个3x3矩阵,现在让我们看一下:

6


       此外,我们实际上使用的过滤器不止一个,过滤器的数量自己设定,假设过滤器的数量设置为n,则我们的输出将是28x28xn大小(其中n是特征图的数量  )。
       通过使用更多的过滤器,我们能够更好地保留空间维度信息。
       然而,对于图像矩阵边界上的像素,卷积核的一些元素移动时会出现在图像矩阵之外,因此不具有来自图像矩阵的任何对应元素。在这种情况下,我们可以消除这些位置的卷积运算,最终输出矩阵大小将会小于输入图像,或者我们可以对输入图像矩阵进行 填充(padding),以保证输出图像大小维度不变。
       为了保持本系列的简洁而保持内容的完整性,本文提供了全部的资源链接,在其中更详细地解释了有关内容。
       下面,让我们首先将一些自定义卷积核个数的窗口应用于图像中,这可以通过平均每个像素值与附近的像素值来处理图像:
%%time
import numpy as np
import imageio
import matplotlib.pyplot as plt
from scipy.signal import convolve2d

def Convolution(image, kernel):
conv_bucket= []
for d in range(image.ndim):
conv_channel= convolve2d(image[:,:,d], kernel, 
                               mode="same", boundary="symm")
conv_bucket.append(conv_channel)
returnnp.stack(conv_bucket, axis=2).astype("uint8")


kernel_sizes= [9,15,30,60]
fig, axs=plt.subplots(nrows=1, ncols=len(kernel_sizes), figsize=(15,15));

pic =imageio.imread('img:/parrot.jpg')

for k, ax in zip(kernel_sizes, axs):
    kernel =np.ones((k,k))
    kernel /=np.sum(kernel)
ax.imshow(Convolution(pic, kernel));
ax.set_title("Convolved By Kernel: {}".format(k));
ax.set_axis_off();
Wall time: 43.5 s
AI 代码解读

7


       更多内容可以 在此查看,其中已经深入讨论了各种类型的内核,并展示了它们之间的差异。

作者信息

Mohammed Innat,机器学习和数据科学研究者
本文由阿里云云栖社区组织翻译。
文章原标题《Basic Image Data Analysis Using Numpy and OpenCV – Part 3》,译者:海棠,审校:Uncle_LLD。
文章为简译,更为详细的内容,请查看原文

目录
打赏
0
1
1
0
1807
分享
相关文章
Opencv学习笔记(三):图像二值化函数cv2.threshold函数详解
这篇文章详细介绍了OpenCV库中的图像二值化函数`cv2.threshold`,包括二值化的概念、常见的阈值类型、函数的参数说明以及通过代码实例展示了如何应用该函数进行图像二值化处理,并展示了运行结果。
1359 0
Opencv学习笔记(三):图像二值化函数cv2.threshold函数详解
opencv图像形态学
图像形态学是一种基于数学形态学的图像处理技术,它主要用于分析和修改图像的形状和结构。
89 4
PIL图像转换为Numpy数组:技术与案例详解
本文介绍了如何将PIL图像转换为Numpy数组,以便利用Numpy进行数学运算和向量化操作。首先简要介绍了PIL和Numpy的基本功能,然后详细说明了转换过程,包括导入库、打开图像文件、使用`np.array()`或`np.asarray()`函数进行转换,并通过打印数组形状验证转换结果。最后,通过裁剪、旋转和缩放等案例展示了转换后的应用,以及如何将Numpy数组转换回PIL图像。此外,还介绍了处理base64编码图像的完整流程。
77 4
解锁 Python 数据分析新境界:Pandas 与 NumPy 高级技巧深度剖析
Pandas 和 NumPy 是 Python 中不可或缺的数据处理和分析工具。本文通过实际案例深入剖析了 Pandas 的数据清洗、NumPy 的数组运算、结合两者进行数据分析和特征工程,以及 Pandas 的时间序列处理功能。这些高级技巧能够帮助我们更高效、准确地处理和分析数据,为决策提供支持。
83 2
Opencv的基本操作(一)图像的读取显示存储及几何图形的绘制
本文介绍了使用OpenCV进行图像读取、显示和存储的基本操作,以及如何绘制直线、圆形、矩形和文本等几何图形的方法。
Opencv的基本操作(一)图像的读取显示存储及几何图形的绘制
探索Python科学计算的边界:NumPy、Pandas与SciPy在大规模数据分析中的高级应用
【10月更文挑战第5天】随着数据科学和机器学习领域的快速发展,处理大规模数据集的能力变得至关重要。Python凭借其强大的生态系统,尤其是NumPy、Pandas和SciPy等库的支持,在这个领域占据了重要地位。本文将深入探讨这些库如何帮助科学家和工程师高效地进行数据分析,并通过实际案例来展示它们的一些高级应用。
119 0
探索Python科学计算的边界:NumPy、Pandas与SciPy在大规模数据分析中的高级应用
Python数据分析加速器:深度挖掘Pandas与NumPy的高级功能
在Python数据分析的世界里,Pandas和NumPy无疑是两颗璀璨的明星,它们为数据科学家和工程师提供了强大而灵活的工具集,用于处理、分析和探索数据。今天,我们将一起深入探索这两个库的高级功能,看看它们如何成为数据分析的加速器。
74 1
python利用opencv进行相机标定获取参数,并根据畸变参数修正图像附有全部代码(流畅无痛版)
该文章详细介绍了使用Python和OpenCV进行相机标定以获取畸变参数,并提供了修正图像畸变的全部代码,包括生成棋盘图、拍摄标定图像、标定过程和畸变矫正等步骤。
python利用opencv进行相机标定获取参数,并根据畸变参数修正图像附有全部代码(流畅无痛版)
Python数据分析篇--NumPy--进阶
Python数据分析篇--NumPy--进阶
46 0
Python数据分析篇--NumPy--入门
Python数据分析篇--NumPy--入门
81 0