Python 基于 OpenCV 视觉图像处理实战 之 图像相关的基本概念,以及图像的基础操作 二

Python 基于 OpenCV 视觉图像处理实战 之 图像相关的基本概念,以及图像的基础操作 二

目录

Python 基于 OpenCV 视觉图像处理实战 之 图像相关的基本概念,以及图像的基础操作 二

一、简单介绍

二、图像的几何变换

三、插值算法

1、最近邻插值算法

2、双线性插值算法

3、插值算法的实现

四、图像的缩放

1、知识介绍

2、简单案例:图像的缩放

五、图像的平移

1、知识介绍

2、简单案例:图像平移

六、图像的旋转

1、知识介绍

2、简单案例:图像的旋转

七、图像的镜像变换

1、知识介绍

2、简单案例:图像镜像变换

八、图像色彩空间基础知识

1、图像的色调、色相、饱和度、亮度和对比度

2、RGB色彩空间

3、HSV色彩空间

4、HSI色彩空间

九、图像的直方图

1、图像直方图的基本概念

2、绘制灰度图像的直方图

3、绘制彩色图像的直方图

4、图像直方图均衡化

5、图像直方图反向投影


一、简单介绍

Python是一种跨平台的计算机程序设计语言。是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越多被用于独立的、大型项目的开发。Python是一种解释型脚本语言,可以应用于以下领域: Web 和 Internet开发、科学计算和统计、人工智能、教育、桌面界面开发、软件开发、后端开发、网络爬虫。

这里使用 Python  基于 OpenCV 进行视觉图像处理,......

二、图像的几何变换

图像的几何变换是指在不改变图像内容的前提下对图像的像素进行空间几何变换,主要包括图像的平移变换、镜像变换、缩放和旋转等。

一个几何变换需要两部分运算:

  • 第一部分是求解空间变换坐标函数,用以描述平移、缩放、旋转和镜像等变换后输出图像与输入图像之间的像素映射关系;
  • 第二部分是插值运算,因为按照这种变换关系进行计算时,输出图像的像素可能被映射到输入图像的非整数坐标上。

设原图像f(x0,y0)经过几何变换产生的目标图像为g(x1,y1),则该空间变换(映射)关系可表示为:

x1=s(x0,y0)

y1=t(x0,y0)

其中,s(x0,y0)和t(x0,y0)为由f(x0,y0)到g(x1,y1)的坐标变换函数。

求解出坐标变换函数后开始计算变换后的图像像素位置,然后插值到变换后的图像上。

三、插值算法

对于数字图像而言,像素的坐标是离散型非负整数,在进行空间坐标变换计算的过程中,有可能产生浮点坐标值。

例如,原图像坐标(11,11)在缩放过程中缩小到一半的时候,坐标变成了(5.5,5.5),这种坐标值是无效的。

插值算法就是用来处理这些浮点坐标的。

常见的插值算法有最邻近插值法、双线性插值法、二次立方插值法、三次立方插值法等。

其中最常见的是 最邻近插值双线性插值,接下来会具体介绍这两种插值算法。

1、最近邻插值算法

这是最简单的一种插值方法。在坐标(i,j)的四邻域空间中,按照坐标将邻域划分成四个范围,分别标记为A、B、C、D,将计算出来的像素坐标放到这个邻域中,看坐标在哪个区域就将距离最近的邻接像素灰度值赋予它,如下图

设u、v为大于0小于1的小数,(i+u,j+v)为输入的像素坐标,则待求像素灰度值为f(i+u,j+v),根据u、v值的不同,f(i+u,j+v)的值也不同,具体规则如下:

如果u<0.5,v<0.5,则(i+u,j+v)落在A区,f(i+u,j+v)=f(i,j);

如果u>=0.5,v<0.5,则(i+u,j+v)落在B区,f(i+u,j+v)=f(i+1,j);

如果u<0.5,v>0.5,则(i+u,j+v)落在C区,f(i+u,j+v)=f(i,j+1);

如果u>0.5,v>=0.5,则(i+u,j+v)落在D区,f(i+u,j+v)=f(i+1,j+1)。

从上述算法中可以看出,最近邻插值的计算量很小,但是不可避免地造成了图像灰度上的不连续,在灰度变化密集的地方很容易出现锯齿。

2、双线性插值算法

同样,对于一个目标像素,设置坐标通过反向变换得到的浮点坐标为(i+u,j+v),其中i、j均为非负整数,u、v为[0,1)区间的浮点数,则这个像素的值f(i+u,j+v)可由原图像中坐标为(i,j)、(i+1,j)、(i,j+1)、(i+1,j+1)所对应的周围4个像素的值来决定,即

f(i+u,j+v)=(1-u)(1-v)f(i,j)+(1-u)vf(i,j+1)+u(1-v)f(i+1,j)+uvf(i+1,j+1)

其中,f(i,j)表示源图像(i,j)处的的像素值。

跟最近邻插值算法相比,双线性插值计算量大,但缩放后图像质量高,不会出现像素值不连续的情况。但是双线性插值具有低通过滤器的特性,在插值计算中可能会损失图像高频分量,使图像轮廓在一定程度上变得模糊。

3、插值算法的实现

根据上面的算法规则描述,插值算法可以自己实现的难度不大,在图像处理过程中插值经常配合其他操作使用,因此在OpenCV很多函数里面集成了插值的实现,比如OpenCV函数resize(),里面已经集成了大量的插值算法。

resize()函数可以实现图像大小变换,默认插值方法为双线性插值。函数声明如下:

dst=cv2.resize(src, dsize, fx, fy, interpolation)

参数说明:

  • src:输入图像。
  • dst:输出图像。
  • dsize:输出图像的大小。如果这个参数不为0,那么就代表将原图像缩放到这个Size(width,height)指定的大小;如果这个参数为0,那么原图像缩放之后的大小就要通过公式来计算,dsize=Size(round(fx*src.cols),round(fy*src.rows))。其中,fx和fy是图像Width方向和Height方向的缩放比例。
  • fx:Width方向的缩放比例,如果是0,那么就会按照dsize.width/src.cols来计算。
  • fy:Height方向的缩放比例,如果是0,那么就会按照dsize.height/src.rows来计算。
  • interpolation:表示插值方式。

四、图像的缩放

1、知识介绍

图像的缩放主要用于改变图像的大小。缩放后,图像的宽度和高度会发生变化。图像缩放包含两个系数:水平缩放系数和垂直缩放系数。

水平缩放系数控制图像宽度的缩放,其值为1,则图像的宽度不变;其值小于1,则图像的宽度变窄;其值大于1,则图像的宽度变宽。垂直缩放系数控制图像高度的缩放,其值为1,则图像的高度不变;其值小于1,则图像的宽度变矮;其值大于1,则图像的宽度变高。如果水平缩放系数和垂直缩放系数不相等,那么缩放后图像的宽度和高度的比例会发生变化,使图像变形。要保持图像宽度和高度的比例不发生变化,就需要水平缩放系数和垂直缩放系数相等。

缩放原理

设水平缩放系数为fx,垂直缩放系数为fy,(x0,y0)为缩放前的坐标,(x,y)为缩放后的坐标,其缩放的坐标映射关系如下:

x=x0×fx

y=y0×fy

注意:图像在放大的时候调用了插值算法,放大的图片会出现一些失真,尤其在放大倍数很大的时候会出现模糊的现象,但是缩小后作为下采样则不会出现上述问题。

2、简单案例:图像的缩放

1)编写代码

2)运行效果

3)具体代码

"""
图像的缩放1)输入的原图,2)调用了resize()函数,3)一张图片是整体尺寸缩小到了100×100,4)一张图片是等比例放大2倍。5)resize()函数既可以指定输出图像的具体尺寸,也可以指定图像水平或垂直缩放的比例。
"""import cv2def main():img = cv2.imread("Images/Dog.jpg")# 图片尺寸height, width, n = img.shape# 缩小downscale = cv2.resize(img, (100, 100), interpolation=cv2.INTER_LINEAR)# 放大upscale = cv2.resize(img, (2 * width, 2 * height), interpolation=cv2.INTER_LINEAR)# 设置窗口属性,并显示图片cv2.namedWindow("downscale", cv2.WINDOW_KEEPRATIO)cv2.imshow("downscale", downscale)# 设置窗口属性,并显示图片cv2.namedWindow("upscale", cv2.WINDOW_KEEPRATIO)cv2.imshow("upscale", upscale)# 设置窗口属性,并显示图片cv2.namedWindow("Dog", cv2.WINDOW_KEEPRATIO)cv2.imshow("Dog", img)cv2.waitKey(0)if __name__ == '__main__':main()

五、图像的平移

1、知识介绍

图像的平移变换就是将图像所有的像素坐标分别加上指定的水平偏移量和垂直偏移量。

tx、ty分别代表水平和垂直方向上平移的距离。

这里利用np.array()创建这个矩阵,然后调用warpAffine来实现这个变换并保持图像大小不变。

OpenCV的warpAffine()函数声明如下:

dst=cv2. warpAffine( src, M, dsize)

参数说明:

  • src ---- 代表图像 。
  • M ---- 代表一个2行3列的矩阵,根据此矩阵的值变换原图中像素的位置 。
  • dsize ----代表输出图像的尺寸大小 。
  • dst ---- 代表经过仿射变换后输出的图像。

平移是让图像中所有像素同时沿着水平或垂直方向移动。在平移的操作中,我们需要把M设置为以下格式实现平移操作。

M = [[1, 0, 水平移动的距离], [0, 1, 垂直移动的距离]]

若水平移动的距离为正数,图像会向右移动,若为负数,图像会向左移动;

若垂直移动的距离为正数,图像会向下移动,若为负数,图像会向上移动。

2、简单案例:图像平移

1)编写代码

2)运行效果

代码中,图片的平移并没有设置改变图像的尺寸,因此平移后无像素的地方显示为黑色。

3)代码

"""
图像平移1)首先构建变换矩阵M,设置向左、向下各平移50个像素,则M=[[1,0,-100],[0,1,100]。2)图片的平移并没有设置改变图像的尺寸,因此平移后无像素的地方显示为黑色。
"""import numpy as np
import cv2def main():img = cv2.imread('Images/Dog.jpg')height, width, n = img.shapeM = np.array([[1, 0, 100], [0, 1, 100]], np.float32)# 图像平移img_tr = cv2.warpAffine(img, M, img.shape[:2])# 设置窗口属性,并显示图片cv2.namedWindow("img_tr", cv2.WINDOW_KEEPRATIO)cv2.imshow('img_tr', img_tr)# 设置窗口属性,并显示图片cv2.namedWindow("Dog", cv2.WINDOW_KEEPRATIO)cv2.imshow('Dog', img)cv2.waitKey(0)if __name__ == '__main__':main()

六、图像的旋转

1、知识介绍

图像的旋转就是让图像按照某一点旋转到指定的角度。

图像旋转后不会变形,但是其垂直对称轴和水平对称轴都会发生改变,旋转后图像的坐标和原图像坐标之间的关系已不能通过简单的加减乘除来得到,而需要通过一系列的复杂运算得到。

需要确定3个参数:图像的旋转中心点、旋转角度和缩放因子。

OpenCV中集成了getRotationMatrix2D()函数来实现图像的旋转,具体函数声明如下:

 M = cv2.getRotationMatrix2D(center, angle, scale)

参数说明:

  • center ---- 代表旋转的中心点坐标。
  • angle ---- 代表旋转的角度,正数表示逆时针旋转,负数表示顺时针旋转。
  • scale ----代表缩放比例,浮点类型。
  • M ---- 代表计算出的仿射矩阵。

调用getRotationMatrix2D()函数之后得到了图像的变换矩阵M,然后再调用warpAffine()函数,输入图像变换矩阵M得到最终的结果

注意:图像在旋转和平移后都会出现图像被裁剪的问题。对于这种情况,需要先计算输出图像的尺寸,然后调整参数,即可避免这个问题。

2、简单案例:图像的旋转

1)编写代码

2)运行结果

旋转之后依旧不改变图像的尺寸,所以会出现图像信息丢失的情况

3)具体代码

"""
图像旋转
"""import cv2def main():img = cv2.imread("Images/Dog.jpg")height, width, n = img.shape# 中心旋转 90°M = cv2.getRotationMatrix2D((width / 2, height / 2), 90, 1)img_rotatin = cv2.warpAffine(img, M, img.shape[:2])# 设置窗口属性,并显示图片cv2.namedWindow("img_rotatin", cv2.WINDOW_KEEPRATIO)cv2.imshow('img_rotatin', img_rotatin)# 设置窗口属性,并显示图片cv2.namedWindow("Dog", cv2.WINDOW_KEEPRATIO)cv2.imshow('Dog', img)cv2.waitKey(0)if __name__ == '__main__':main()

七、图像的镜像变换

1、知识介绍

图像的镜像变换分为两种:水平镜像和垂直镜像。

水平镜像以图像垂直中线为轴,将图像的像素进行对换,也就是将图像的左半部和右半部对调。

垂直镜像则是以图像的水平中线为轴,将图像的上半部分和下半部分对调。

镜像变换原理

设输入图像的变换坐标为(x0,y0),变换后的坐标为(x,y),Width是图像的宽,Height为图像的高,因此可以得出:

  • 水平镜像变换:x=width-x0-1,y=y0;
  • 垂直镜像变换:x=x0,y=height-y0-1。

OpenCV中集成了直接实现镜像变换的flip()函数,函数声明如下:

dst=cv2.flip( src, flipCode, dst=None)

参数说明:

  • src:输入图像。
  • flipCode:翻转模式,flipCode==0垂直翻转(沿x翻转),flipCode>0水平翻转(沿y翻转),flipCode<0水平垂直翻转(先沿x轴翻转,再沿y翻转,等价于旋转180°)。
  • 输出为变换后的图像。

2、简单案例:图像镜像变换

1)编写代码

2)运行结果

3)具体代码

"""
图像镜像变换
"""import cv2def main():img = cv2.imread("Images/Dog.jpg")# 水平翻转xImg = cv2.flip(img, 1, dst=None)# 垂直翻转yImg = cv2.flip(img, 0, dst=None)# 设置窗口属性,并显示图片cv2.namedWindow("xImg Horizontal", cv2.WINDOW_KEEPRATIO)cv2.imshow("xImg Horizontal", xImg)# 设置窗口属性,并显示图片cv2.namedWindow("yImg Vertical", cv2.WINDOW_KEEPRATIO)cv2.imshow("yImg Vertical", yImg)# 设置窗口属性,并显示图片cv2.namedWindow("Dog Origin", cv2.WINDOW_KEEPRATIO)cv2.imshow("Dog Origin", img)cv2.waitKey(0)if __name__ == '__main__':main()

八、图像色彩空间基础知识

在计算机视觉和图像处理领域,色彩空间指的是组织色彩的特定方式,是进行颜色信息研究的理论基础,它将颜色从人们的主观感受量化为具体的表达,为用计算机来记录和表现颜色提供了有力的依据。

一幅图像可以用不同的色彩空间表示,有很多很有用的不同的颜色空间。

其中,一些常见的颜色空间有RGB、HSI、HSV和HSB等。不同的颜色空间有不同的优点。

接下来将介绍几种常见的色彩空间描述,以及图像的颜色参数,如色调、色相、饱和度、对比度和亮度等。

1、图像的色调、色相、饱和度、亮度和对比度

1)色调 (Hue)

色调是指色彩外观的基本倾向,描述了图像色彩模式下原色的明暗程度,范围为0~255,共256级色调。对于灰度图像,当色调级别为255时就是白色,当级别为0时就是黑色,中间是各种程度不同级别的灰色。在RGB色彩空间下,色调代表红、绿、蓝三种原色的明暗程度,而红色有淡红色、玫红色、深红色、暗红色等不同的色调。

2)色相 (Hue)

色调是色彩的基本属性之一,它描述了我们所感知到的颜色的种类或者色系。比如,从红到紫的不同色调代表了不同的颜色类别,它们都在色谱中占据着不同的位置。从艳丽的橙色到深邃的蓝色,色调的变化带来了丰富多彩的视觉体验。

3)饱和度 (Saturation)

饱和度定义了颜色的纯度或者强度。当一种颜色完全饱和时,它呈现出鲜艳、浓郁的外观,没有任何混合或者灰色调。相反,当饱和度较低时,颜色变得柔和、淡雅,甚至可能变成灰色或无色。

4)亮度 (Brightness)

亮度是指颜色的相对明暗程度。它决定了我们感知到的颜色是否看起来明亮或暗淡。比如,一种明亮的黄色会比同样的颜色的低亮度版本更容易引起注意,因为它更加醒目和生动。

5)对比度 (Contrast)

对比度是描述图像中不同区域之间亮度或颜色的差异程度。高对比度意味着图像中的明暗或颜色差异很大,使得物体轮廓清晰,细节丰富,色彩生动。而低对比度则使得图像显得柔和,细节较少,色彩过渡平滑。

2、RGB色彩空间

RGB色彩空间是最常见的颜色空间。R、G、B分别代表红色(Red)、绿色(Green)、蓝色(Blue)。在这个颜色空间中,每一种颜色都由R、G、B的不同权重代表。在几何上,以R、G、B三个互相垂直的轴所构成的空间坐标系被称为RGB模型。RGB色彩系统用R、G、B三原色通过不同比例的混合来表示任一种色彩,其优点是直观、易于理解。

但是三个颜色分量之间是高度相关的,如果一个颜色的某一个分量发生了一定程度的改变,那么这个颜色很可能也要发生改变。例如,如果改变图像的亮度,那么RGB的3个分量都会相应地改变。

3、HSV色彩空间

HSV(Hue,Saturation,Value)色彩空间对应于画家配色的方法。画家用改变色浓和色深的方法从某种纯色获得不同色调的颜色,在一种纯色中加入白色以改变色浓,加入黑色以改变色深,同时加入不同比例的白色和黑色,即可获得各种不同的色调。

在几何上用圆柱坐标系中的一个圆锥形子集来描述HSV模型,圆锥的顶面对应于V=1,它包含RGB模型中的R=1、G=1、B=1这3个面。色彩H由绕V轴的旋转角给定。红色对应于角度0°,绿色对应于角度120°,蓝色对应于角度240°。

HSV模型中的V轴对应于RGB颜色空间中的主对角线。在圆锥顶面的圆周上的颜色,V=1、S=1这种颜色是纯色。

4、HSI色彩空间

HIS(Hue,Intensity,Saturation)色彩空间从视觉感官出发,用色调(Hue)、饱和度(Saturation)和亮度(Intensity)来描述颜色。HIS空间可以用圆锥空间模型来描述。其中,色调H由角度表示,取值范围为0~360°,每隔60°表示一种基本颜色(其他度数是相邻的基本度数之间的颜色):红(RGB(255,0,0))→黄(RGB(255,255,0))→绿(RGB(0,255,0))→青(RGB(0,255,255))→蓝(RGB(0,0,255))→紫(RGB(255,0,255))→红。

饱和度S是HIS彩色空间中轴线到彩色点的半径长度,彩色点离轴线的距离越近,表示颜色的白光越多。强度I用轴线方向上的高度表示,圆锥体的轴线描述了灰度级,强度最小值时为黑色,强度最大值时为白色。每个和轴线正交的切面上的点,其强度值都是相等的。

5、简单案例:调整图片亮度对比度

代码:

"""
调整图片亮度对比度
"""import cv2
import numpy as np# 修改图像的对比度,coefficent>0, <1降低对比度,>1提升对比度 建议0-2
def change_contrast(img, coefficent):imggray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)m = cv2.mean(img)[0]graynew = m + coefficent * (imggray - m)img1 = np.zeros(img.shape, np.float32)k = np.divide(graynew, imggray, out=np.zeros_like(graynew), where=imggray != 0)img1[:, :, 0] = img[:, :, 0] * kimg1[:, :, 1] = img[:, :, 1] * kimg1[:, :, 2] = img[:, :, 2] * kimg1[img1 > 255] = 255img1[img1 < 0] = 0return img1.astype(np.uint8)# 修改图像的亮度,brightness取值0~2 <1表示变暗 >1表示变亮
def change_brightness(img, brightness):[averB, averG, averR] = np.array(cv2.mean(img))[:-1] / 3k = np.ones((img.shape))k[:, :, 0] *= averBk[:, :, 1] *= averGk[:, :, 2] *= averRimg = img + (brightness - 1) * kimg[img > 255] = 255img[img < 0] = 0return img.astype(np.uint8)def cvshow(name, img):cv2.namedWindow(name, cv2.WINDOW_NORMAL)cv2.resizeWindow(name, 1280, 720)cv2.imshow(name, img)cv2.waitKey(0)cv2.destroyWindow(name)def main():# 加载图片 读取彩色图像image = cv2.imread('Images/Dog.jpg', cv2.IMREAD_COLOR)l = 50c = 50MAX_VALUE = 100# 调节饱和度和亮度的窗口cv2.namedWindow("changImage", cv2.WINDOW_AUTOSIZE)def nothing(*arg):pass# 滑动块cv2.createTrackbar("l", "changImage", l, MAX_VALUE, nothing)cv2.createTrackbar("c", "changImage", c, MAX_VALUE, nothing)while True:# 得到 l、 s 、c的值l = cv2.getTrackbarPos('l', "changImage")c = cv2.getTrackbarPos('c', "changImage")img = np.copy(image.astype(np.float32))# 亮度 -1~1img = change_brightness(img, float(l - 50) / float(50))# 对比度 0~2img = change_contrast(img, c / 50)# 显示调整后的效果img = cv2.resize(img, (1280, 720))cv2.imshow("changImage", img)ch = cv2.waitKey(5)# 按 ESC 键退出if ch == 27:break# 关闭所有的窗口cv2.destroyAllWindows()if __name__ == "__main__":main()

九、图像的直方图

直方图应用于统计学中。一系列高度不等的线段用来描述数据分布。在图像处理中直方图的意义很大,经常用来统计不同颜色的分布情况等。

另外,对直方图的一些变换可以改变图像的一些特性,比如直方图均衡化操作。

1、图像直方图的基本概念

图像直方图有两个参数:bins和range。bins表示特征统计量。例如,在图像直方图中,可以把一个灰度值设置为一个bin,0~255强度的灰度值一共就需要256个bin。range表示一个bins能够达到的最大和最小的范围。例如,一张10×10的图片,如果直方图是按照亮度统计像素数量,那么range的范围就是0~100。

在图像处理中,bins不仅是指灰度值,而且它作为直方图的统计数据参量,可能是任何能有效描述图像的特征,比如梯度、方向、色彩或任何其他特征等。

一张用以表示数字图像中亮度分布的直方图,描绘了图像中亮度值的像素数。可以借助观察该直方图了解如何调整亮度分布,直方图中横坐标的左侧为纯黑或较暗的区域,右侧为纯白较亮的区域。因此,对于一幅较暗的图片的图像直方图,其数据多集中于左侧和中间部分,而整体明亮、只有少量阴影的图像直方图中则集中于右侧部分。直方图的意义如下:

  • 直方图是图像中像素强度分布的图形表达方式。
  • 直方图统计了每个强度值所具有的像素个数。

2、绘制灰度图像的直方图

1)在Python中,图像的直方图绘制需要用到Matplotlib库,它是一个Python的2D绘图库。

在环境中,pip install matplotlib 安装即可

安装成功后,开始绘制图像的直方图,其中用到了OpenCV的alcHist()函数,其主要功能是计算图像直方图,函数原型如下:

hist=cv2.calcHist(images, channels, mask, histSize, ranges, hist=None,
accumulate=None)

参数说明:

  • images:输入图像,传入时应该用中括号[]括起来。
  • channels:传入图像的通道,如果是灰度图像,那么只有一个通道,值为0;如果是彩色图像(有3个通道),那么在0、1、2中选择一个值,对应着BGR的各个通道,这个值也得用[]传入。
  • mask:掩膜图像,如果统计整幅图,那么为None;如果要统计部分图的直方图,就得构造相应的掩膜来计算。
  • histSize:灰度级的个数,需要中括号,比如[256]。
  • range:像素值的范围,通常为[0,256]。此外,假如channels为[0,1],ranges为[0,256,0,180],则代表0通道范围是0~256,1通道范围0~180。
  • 输出为计算出来的直方图。

2)灰度图像直方图的绘制

按照一张输入图像的灰度格式,x坐标代表0~255级的bins,y坐标代表不同bins下的像素个数。从下图中可以看出,该图像在低灰度区域和高灰度区域中的像素分布比较多。

代码:

"""
绘制灰度图像直方图1)按照一张输入图像的灰度格式,x坐标代表0~255级的bins,y坐标代表不同bins下的像素个数。
"""import cv2
from matplotlib import pyplot as pltdef main():img = cv2.imread("Images/Gray_Dog.jpg")# 设置窗口属性,并显示图片cv2.namedWindow("Dog", cv2.WINDOW_KEEPRATIO)cv2.imshow("Dog", img)hist = cv2.calcHist([img], [0], None, [256], [0, 256])# 新建一个图像plt.figure()# 图坐标图标题plt.title("Grayscale Histogram")# 图像 x 轴标签plt.xlabel("Bins")# 图像 y 轴标签plt.ylabel("# of Pixels")# 画图plt.plot(hist)# 设置 x 轴 的坐标范围plt.xlim([0, 256])# 显示图坐标plt.show()# input()cv2.waitKey()# 关闭所有的窗口cv2.destroyAllWindows()if __name__ == '__main__':main()

3、绘制彩色图像的直方图

灰度图像只有一个通道,因此绘制比较简单。

对于彩色图像,它需要用到之前的split()函数将图像通道分开,然后进行绘制。

R、G、B三种颜色都绘制在同一张直方图上,可以看出相同bins下不同颜色的数目分布

代码:

"""
彩色图像直方1)R、G、B三种颜色都绘制在同一张直方图上,可以看出相同bins下不同颜色的数目分布
"""import cv2
from matplotlib import pyplot as pltdef main():img = cv2.imread("Images/Dog.jpg")# 设置窗口属性,并显示图片cv2.namedWindow("Dog", cv2.WINDOW_KEEPRATIO)cv2.imshow("Dog", img)chans = cv2.split(img)colors = ('b', 'g', 'r')# 新建一个图像plt.figure()# 图像的标题plt.title(" Flattened Color Hisogram")# x 轴标签plt.xlabel("Bins")# y 轴标签plt.xlabel("# of Pixels")for (chan, color) in zip(chans, colors):hist = cv2.calcHist([chan], [0], None, [256], [0, 256])plt.plot(hist, color=color)plt.xlim([0, 256])# 显示图像plt.show()# input()cv2.waitKey()# 关闭所有的窗口cv2.destroyAllWindows()if __name__ == '__main__':main()

4、图像直方图均衡化

图像的直方图展示了图像不同灰度级别的像素分布。

从前面绘制的直方图中可以看出,图像的像素分布很不均衡。在图像处理中,如果一幅图像的像素占有很多的灰度级而且分布均匀,那么这样的图像往往有高对比度。直方图均衡化就是调整输入图像的直方图信息,使得图像像素在灰度级别上均衡分布的的一种图像变化方法。

直方图均衡化的基本思想是:

对图像中像素个数多的灰度级进行展宽,而对图像中像素个数少的灰度进行压缩,从而扩展图像像素取值的动态范围。

图像均衡化的作用是提高对比度和灰度色调的变化,使图像更加清晰。

OpenCV的equalizeHist()函数,该函数功能是实现直方图均衡化,其原型如下:

dst=equalizeHist(src)

参数说明:

  • src:输入图像。
  • 输出为图像均衡化后的图像。

注意:直方图均衡化对图像对比度增强的效果非常明显,原本图像中亮的地方亮度增加,图像暗的地方更加暗。但是图像均衡化并不适用于所有的场景,对于一些输入图像,均衡化高亮的部分会出现光斑,视觉效果很差。

灰度图像直方图均衡化示例,运行效果如下

代码:

"""
灰度图像直方图均衡化(全局)
"""import cv2
import numpy as npdef main():# 读取图片并且灰度化img = cv2.imread("Images/Cullet.jpg", 0)# 图像均衡化eq = cv2.equalizeHist(img)# 设置窗口属性,并显示图片cv2.namedWindow("Histogram Equalization", cv2.WINDOW_KEEPRATIO)cv2.imshow("Histogram Equalization", np.hstack([img, eq]))cv2.waitKey(0)if __name__ == "__main__":main()

以上展示的是图片的全局直方图均衡化,也就是对整张图像都进行了处理。

在实际项目中,有的时候这种操作并不是很好,会把某些不该调整的部分调整了,而我们需要的可能只是对图像的某一块区域进行均衡化处理。

OpenCV中还有一种局部直方图均衡化函数,也就是说把整个图像分成许多小块(如按8×8把图像分成多个小块),再对每个小块进行均衡化。

调用了OpenCV的createCLAHE()函数,其声明如下:

clahe=createCLAHE([, clipLimit[, tileGridSize]])

参数说明:

  • clipLimit:对比度的大小。
  • tileGridSize:每次处理块的大小。

灰度图像直方图局部均衡化处理,运行效果如下:

如图所示,可以看出,提升的对比度没有之前明显,程序的主要功能是把图片切分成了几个8×8的小块,并对每个小块里面进行直方图均衡化。

代码:

"""
灰度图像直方图局部均衡化
"""import cv2
import numpy as npdef main():img = cv2.imread("Images/Cullet.jpg", 0)# 创建一个 8x8 的 clashclahe = cv2.createCLAHE(5, (8, 8))# 图片切分成 8x8 的小块dst = clahe.apply(img)# 设置窗口属性,并显示图片cv2.namedWindow("Local Histogram Equalization", cv2.WINDOW_KEEPRATIO)cv2.imshow("Local Histogram Equalization", np.hstack([img, dst]))cv2.waitKey(0)if __name__ == "__main__":main()

5、图像直方图反向投影

图像直方图的反向投影定义是通过直方图来生成图像,反向投影生成图在某一位置的像素值就是原图对应位置的像素值在原图像中的总数目。

反向投影的实现过程比图像计算直方图的过程容易理解,就是统计图像中像素分布的概率,而反向投影正好相反,是通过直方图来形成图像。在由反向投影生成的图像中,如某像素值在直方图中的值越大,在进行反向投影操作时其对应的像素值越大,如某灰度值所占面积越小,其反向投影后像素值就会更小。

OpenCV中定义了calcBackProject()函数用来计算直方图反向投影,函数原型如下:

st=calcBackProject(images, channels, hist, ranges, scale[, dst])

参数说明:

  • images:输入图像(HSV图像)。
  • channels:用于计算反向投影的通道列表,通道数必须与直方图维度相匹配。
  • hist:输入的模板图像直方图。
  • ranges:直方图中每个维度bin的取值范围(即每个维度有多少个bin)。
  • scale:可选输出反向投影的比例因子,一般取1。

首先读入两幅图片,sample对应的图像比较大,target对应的图像比较小,然后将两幅图像都转换成HSV空间,计算sample图像的直方图roiHist,接着调研归一化函数normalize()并对其做归一化处理,归一化到0~255区间,然后输入target图像的hsv空间的target_hsv图像和sample图像归一化了的直方图roiHist,反向计算出图像dst并显示出来。从显示结果可以看出,反向投影的效果能够反映图像的轮廓,可以找到target图像在sample图像中的大致位置。

直方图反向投影示例,运行效果如下:

可以看出,图像直方图的反向投影用于在比较大的输入图像中查找特定图像(通常较小的模板图像最匹配的区域),也就是定位模板图像出现在输入图像的位置。

代码:

"""
图像反向投影1)首先读入两幅图片,sample对应的图像比较大,target对应的图像比较小,2)然后将两幅图像都转换成HSV空间,计算sample图像的直方图roiHist,3)接着调研归一化函数normalize()并对其做归一化处理,归一化到0~255区间,4)然后输入target图像的hsv空间的target_hsv图像和sample图像归一化了的直方图roiHist,反向计算出图像dst并显示出来
"""import numpy as np
import cv2
from matplotlib import pyplot as pltdef main():sample = cv2.imread("Images/BackProjectHist01.png")target = cv2.imread("Images/BackProjectHist02.png")# 图像转HSV空间roi_hsv = cv2.cvtColor(sample, cv2.COLOR_BGR2HSV)target_hsv = cv2.cvtColor(target, cv2.COLOR_BGR2HSV)# 设置窗口属性,并显示图片cv2.namedWindow("sample", cv2.WINDOW_KEEPRATIO)cv2.imshow("sample", sample)# 设置窗口属性,并显示图片cv2.namedWindow("target", cv2.WINDOW_KEEPRATIO)cv2.imshow("target", target)# 计算直方图roiHist = cv2.calcHist([roi_hsv], [0, 1], None, [32, 30], [0, 180, 0, 256])# 直方图归一化cv2.normalize(roiHist, roiHist, 0, 255, cv2.NORM_MINMAX)# 直方图反向投影计算dst = cv2.calcBackProject([target_hsv], [0, 1], roiHist, [0, 180, 0, 256], 1)# 设置窗口属性,并显示图片cv2.namedWindow("Back Projection Demo", cv2.WINDOW_KEEPRATIO)cv2.imshow("Back Projection Demo", dst)cv2.waitKey(0)if __name__ == '__main__':main()

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java kafka客户端何时设置的kafka消费者默认值

kafka为什么有些属性没有配置却能正常工作&#xff0c;那是因为kafka-clients对有些消费者设置了默认值&#xff0c;具体看下ConsumerConfig类的静态模块&#xff0c;具体如下所示&#xff1a; kafka为什么有些属性没有配置却能正常工作&#xff0c;那是因为kafka-clients对有…

AJAX 02 案例、Bootstrap框架

AJAX 学习 AJAX 2 综合案例黑马 API01 图书管理Bootstrap 官网Bootstrap 弹框图书管理-渲染列表图书管理-添加图书图书管理-删除图书图书管理 - 编辑图书 02 图片上传03 更换图片04 个人信息设置信息渲染头像修改补充知识点&#xff1a;label扩大表单的范围 AJAX 2 综合案例 黑…

【FPGA】DDR3学习笔记(二)丨从SDRAM到DDR3的IP核设计

本篇文章包含的内容 一、DDR SDRAM1.1 基本概述1.2 工作时序&#xff08;以读取为例&#xff09; 二、DDR2 SDRAM2.1 基本概述2.2 工作时序 三、DDR3 SDRAM3.1 基本概述3.2 硬件设计3.3 读写时序3.4 MIG IP核设计3.5 读写代码设计 开发板&#xff1a;正点原子的达芬奇开发板&am…

【Leetcode每日一题】 递归 - 合并两个有序链表(难度⭐)(35)

1. 题目解析 题目链接&#xff1a;21. 合并两个有序链表 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 1. 递归函数定义与功能 递归函数的主要任务是将两个有序链表合并成一个新的有序链表&#xff0c;并返回合并后…

Git 学习笔记 三个区域、文件状态、分支、常用命令

Git 学习 GitGit概念VS Code中使用仓库&#xff08;repository&#xff09;示例 Git 使用时的三个区域示例 Git 文件状态示例 Git 暂存区示例 Git 回退版本删除文件忽略文件示例 分支分支的使用分支的合并与删除分支的合并冲突 Git常用命令Git远程仓库 (HTTP)步骤远程仓库 克隆…

【Linux】Linux命令速查表

Linux 命令列表 – 目录 文件和目录操作命令 文件权限命令文件压缩和归档命令进程管理命令系统信息命令 联网命令 IO重定向命令环境变量命令 用户管理命令 快捷键命令列表 Bash 快捷键命令 Nano 快捷键命令 VI 快捷键命令 Vim 快捷键命令Linux 命令备忘单常见问题解答 1. 文件和…

[linux]信号处理:信号编码、基本API、自定义函数和集合操作的详解

一、信号的概述 1、定义 信号是 Linux 进程间通信的最古老的方式。信号是软件中断&#xff0c;它是在软件层次 上对中断机制的一种模拟&#xff0c;是一种异步&#xff08;不等待&#xff09;通信的方式 。信号可以导致一个正在运行的进程被 另一个正在运行的异步进程中断&a…

PyCharm创建一个简单的Django项目

1.Django简介 Django 是一个开放源代码的 Web 应用程序框架&#xff0c;由 Python 编写而成。它遵循 MVC&#xff08;模型-视图-控制器&#xff09;的软件设计模式&#xff0c;采用了 MTV&#xff08;模型-模板-视图&#xff09;的架构。Django 的设计目标是使开发复杂的、数据…

【MATLAB源码-第162期】基于matlab的MIMO系统的MMSE检测,软判决和硬判决误码率曲线对比。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 MIMO系统(Multiple-Input Multiple-Output&#xff0c;多输入多输出系统)是现代无线通信技术中的关键技术之一&#xff0c;它能够显著增加通信系统的容量和频谱效率&#xff0c;而不需要增加额外的带宽或发射功率。在MIMO系统…

边缘计算全面概述

什么是边缘计算&#xff1f; 边缘计算是一种分布式计算概念&#xff0c;将智能集成到边缘设备&#xff08;边缘节点&#xff09;中&#xff0c;使数据能够在数据采集源附近实时处理和分析。由于边缘计算在网络边缘本地处理数据&#xff0c;而不是在云端或集中式数据中心&#…

云端巨擘:大数据与云计算的时代航向

文章目录 大数据时代大数据特点(4v1C大数据与云计算的关系 云计算云计算定义云计算特点云计算分类&#xff08;服务类型&#xff09;云计算实现机制云计算体系结构云计算的管理中间件层 大数据时代 大数据定义&#xff1a;海量数据或巨量数据&#xff0c;其规模巨大到无法通过…

学生时期学习资源同步-1 第一学期结业考试题9

原创作者&#xff1a;田超凡&#xff08;程序员田宝宝&#xff09; 版权所有&#xff0c;引用请注明原作者&#xff0c;严禁复制转载

ArrayList 是如何进行扩容的?

典型回答 ArrayList 在添加元素时&#xff0c;会自动进行扩容操作&#xff0c;它的执行步骤如下&#xff1a; 当 ArrayList 的内部数组空间不足以容纳新增的元素时&#xff0c;会触发扩容机制。ArrayList 会创建一个新的更大的数组&#xff0c;通常是当前数组长度的 1.5倍 (可…

LAMP网站部署(Discuz论坛网站部署)

目录 mysql命令 语法 选项 参数 实例 安装php 安装Mariadb 关掉防火墙和selinux 启动HTTP服务 初始化数据库 查看数据库是否创建成功 修改HTTP的配置文件 浏览器打开 将以下所有目录都加上权限 最后首页效果 mysql命令 是MySQL数据库服务器的客户端工具&#xff0c;它工作在命…

从根到叶:深度理解哈希表

​​​​​​​ 一.哈希表的概念 关于查找元素时&#xff1a; 在顺序结构以及平衡树 中&#xff0c;元素关键码与其存储位置之间没有对应的关系&#xff0c;因此在 查找一个元素时&#xff0c;必须要经过关键 码的多次比较 。 顺序查找时间复杂度为 O(N) &#xff0c;平衡树中…

Acwing-基础算法课笔记之动态规划(背包问题)

Acwing-基础算法课笔记之动态规划&#xff08;背包问题&#xff09; 一、01背包问题1、概述2、过程模拟 二、完全背包问题1、概述2、闫氏dp分析完全背包问题3、过程模拟代码模板 三、多重背包问题1、概述2、过程模拟3、多重背包问题的优化版本 分组背包问题1、概述2、过程模拟3…

修改vscode的相对路径计算逻辑

vscode的相对路径计算逻辑是&#xff0c;"./"表示当前项目的文件夹&#xff0c;而不是当前文件所在的文件夹 做出如下修改&#xff1a; File-->Preferences-->settings 搜索Execute in File Dir , 然后取消勾选

粒子群算法对pi控制器进行参数优化,随时优化pi参数以控制直流无刷电机转速。

粒子群算法对pi控制器进行参数优化&#xff0c;随时优化pi参数以取得设定直流无刷电机转速。 PSO优化PID&#xff0c;用于BLDC速度控制 仿真平台为&#xff1a;MATLAB 采用的是Simulinkm程序相配合 仿真结果以及程序示例&#xff1a;

如何配置Apache的反向代理

目录 前言 一、反向代理的工作原理 二、Apache反向代理的配置 1. 安装Apache和相关模块 2. 配置反向代理规则 3. 重启Apache服务器 三、常见的使用案例 1. 负载均衡 2. 缓存 3. SSL加密 总结 前言 随着Web应用程序的不断发展和扩展&#xff0c;需要处理大量的请求和…

Excel第26享:模糊查找之Hlookup函数与通配符的嵌套

1、需求描述 如下图所示&#xff0c;现第一行有三个参考值&#xff1a;人S、羊E、猪3&#xff0c;在第三行有5个字&#xff1a;马、牛、人、羊、猪&#xff0c;每个字如果出现在第一行的三个参考值中&#xff0c;就返回该单元格的数值。如&#xff0c;人&#xff0c;就返回“人…