OpenCV-Python接口-0图像基础

本文介绍了OpenCV在Ubuntu22.04环境下用于图像处理的基本操作,包括读取、显示、保存图像,以及图像的截取、颜色通道处理、图像加法运算、几何变换(缩放、翻转、旋转)。此外,还涉及了色彩空间转换(BGR到HSV)、图像阈值处理、平滑处理和形态学操作等图像处理技术。
摘要由CSDN通过智能技术生成

一、基本介绍

OpenCV(open source computer vision library)是一个基于BSD许可(开源)发行的跨平台计算机视觉库。由一系列 C 函数和少量 C++ 类构成,同时提供了C++、Python、Java、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法,还提供了机器学习的基础算法调用,从而使得图像处理和图像分析变得更加易于上手,让开发人员更多的精力花在算法的设计上。

编译环境,ubuntu22.04,VS code,Python3.10,OpenCV4

打开终端安装opencv-python

pip install opencv-python

在计算机视觉的深度学习研究方面,图像的预处理相比起模型构建本身也同样重要。

区分两个概念:图像处理和计算机视觉的区别:图像处理侧重于“处理”图像–如增强,还原,去噪,分割等等;而计算机视觉重点在于使用计算机来模拟人的视觉,因此模拟才是计算机视觉领域的最终目标。

  • OpenCV中彩色图是以B-G-R通道顺序存储的,灰度图只有一个通道。

  • OpenCV默认使用BGR格式,而RGB和BGR的颜色转换不同,即使转换为灰度也是如此。一些开发人员认为R+G+B/3对于灰度是正确的,但最佳灰度值称为亮度(luminosity),并且具有公式:0.21R+0.72G+0.07*B

  • 图像坐标的起始点是在左上角,所以行对应的是y,列对应的是x。

OpenCV的一些基本的图像操作都是基于位图和像素点的

位图Bitmap),又称栅格图(英语:Raster graphics)或点阵图,是使用像素阵列(Pixel-array/Dot-matrix点阵)来表示的图像。

位图的像素都分配有特定的位置和颜色值。每个像素的颜色信息由RGB组合或者灰度值表示。

根据位深度,可将位图分为1、4、8、16、24及32位图像等。每个像素使用的信息位数越多,可用的颜色就越多,颜色表现就越逼真,相应的数据量越大。例如,位深度为 1 的像素位图只有两个可能的值(黑色和白色),所以又称为二值位图。位深度为 8 的图像有256个可能的值。位深度为 8 的灰度模式图像有 256 个可能的灰色值。

RGB图像由三个颜色通道组成。8 位/通道的 RGB 图像中的每个通道有 256 个可能的值,这意味着该图像有 1600 万个以上可能的颜色值。有时将带有 8 位/通道 (bpc) 的 RGB 图像称作 24 位图像(8 位 x 3 通道 = 24 位数据/像素)。通常将使用24位RGB组合数据位表示的的位图称为真彩色位图。

二、图像

1.图像的基本操作

  • 读入图像
  • 显示图像
  • 保存图像
  • 截取图像(提取像素区域)
import cv2                           #opencv读取的格式是BGR
import matplotlib.pyplot as plt
import numpy as np 

#%matplotlib inline 


# 定义了一个图像显示的函数,
# 其中imshow()为显示函数,
# waitKey(0)为无限时间的显示函数,如果改为参数1就是显示1ms以此类推,
# destroyAllWindows()按下任意键便可关闭窗口。
def cv_show(name, img, i = 0):
    cv2.imshow(name, img) 
    cv2.waitKey(i*1000) 
    cv2.destroyAllWindows()



#---------------------图像基本操作------------------------------
#cv2.IMREAD_COLOR:彩色图像,采用BGR三通道显示
#cv2.IMREAD_GRAYSCALE:灰度图像
#读入彩色图像
img = cv2.imread('/home/meta/Pictures/Screenshots/cat.jpg')
print("cat.jpg shape:", img.shape)      #(381, 482, 3)
#cv_show("img",img)


#读入灰度图像
img0 =cv2.imread("/home/meta/Pictures/Screenshots/cat.jpg",cv2.IMREAD_GRAYSCALE)
print("img0_shape:", img0.shape)        #(381, 482)
cv2.imwrite('mycatimg0.png',img0)
img_gray = img0


# #提取像素区域
# #对图片进行截取,因为图片就是一个二维数组,可以按照二维数组那样截取
# img2 = img[0:50,0:200] 
# cv_show('img214', img2)
# #保存图片
# cv2.imwrite('mycatimg2.png',img2)

2.图像处理基础

二值图像、灰度图像

彩色图像

RGB模式的彩色图在读入OpenCV内进行处理时,会按照方向依次读取RGB的B,G,R通道的像素点,每个通道的数值范围在[0,255],其在OpenCV内以BGR模式的三维数组形式存储

img[0,0]访问图像img第0行第0列像素点的BRG值 [B,G,R]
img[0,0,0]访问img第0行第0列第0通道的像素值,会得到B通道第0行第0列的值
img[0,0,2]访问img第0行第0列第2通道的像素值,会得到R通道第0行第0列的值

  • 像素处理
  • 颜色通道拆分
  • 颜色通道合并
  • 获取图像属性(shape, size, dtype))
  • 图片边界填充
# #对图片进行颜色通道提取
# b, g, r = cv2.split(img)
# #对图片进行颜色通道合并
# img1 = cv2.merge((b,g,r))
# cv2.imwrite('mycatimg1.png',img)

# 获取图像属性
print("彩色图像lena属性:")
color_lena=cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

print("color_lena.shape={}".format(color_lena.shape))
print("color_lena.size={}".format(color_lena.size))
print("color_lena.dtype={}".format(color_lena.dtype))


# #对图片进行边界填充,主要是改变图片最外围的边框,共有五种方法:
# top_size,bottom_size,left_size,right_size = (50,50,50,50)
# #BORDER_REPLICATE:复制法,也就是复制最边缘像素
# replicate = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_REPLICATE)
# #BORDER_REFLECT:反射法,对感兴趣的图像中的像素在两边进行复制
# reflect = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size,cv2.BORDER_REFLECT)
# #BORDER_REFLECT_101:反射法,也就是以最边缘像素为轴,对称
# reflect101 = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_REFLECT_101)
# #BORDER_WRAP:外包装法
# wrap = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_WRAP)
# #BORDER_CONSTANT:常量法,常数值填充
# constant = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size,cv2.BORDER_CONSTANT, value=0)
# plt.subplot(231), plt.imshow(img, 'gray'), plt.title('ORIGINAL')
# plt.subplot(232), plt.imshow(replicate, 'gray'), plt.title('REPLICATE')
# plt.subplot(233), plt.imshow(reflect, 'gray'), plt.title('REFLECT')
# plt.subplot(234), plt.imshow(reflect101, 'gray'), plt.title('REFLECT_101')
# plt.subplot(235), plt.imshow(wrap, 'gray'), plt.title('WRAP')
# plt.subplot(236), plt.imshow(constant, 'gray'), plt.title('CONSTANT')

# plt.show()

3.图像运算

  • 图像加法运算
  • 图像加权运算(图像融合)
  • 位平面分解
  • 几何变换之缩放(更改图片长宽比)
  • 几何变换之翻转
  • 仿射
  • 旋转
  • 重映射
#-----------------------------图像运算------------------------------
#图像加法运算
# +  运算符
#图像融合(图像加权运算)
img_cat = cv2.imread('/home/meta/Pictures/Screenshots/cat.jpg')
img_long = cv2.imread('/home/meta/Pictures/Screenshots/konglong.jpg')
img_cat = cv2.resize(img_cat, (500, 414))  
img_long = cv2.resize(img_long, (500, 414))               #将两个图片改为同样大小

img_plus = img_cat + img_long                            #将对应位置像素相加,遵循一定原则
img_plus = cv2.add(img_cat, img_long)                    #将对应位置像素相加,遵循一定原则
res = cv2.addWeighted(img_cat, 0.4, img_long, 0.6, 0)    #猫占0.4权重,konglong占0.6权重
cv2.imwrite('catKonglong.png', res)
#cv_show("res",res)
#plt.imshow(res)
#plt.show()


#二进制位平面分解技术(BBD)
# BBD可以将灰度图像拆分成8个二进制平面。
# 第一个位平面是由灰度图像中每一个像素的二进制表示的所有第一位所组成的
# 在组成一张图的过程中,高位的图往往起到了更加关键的作用
lena = cv2.imread(r"/home/meta/Pictures/Screenshots/lena.jpg", 0)
plt.imshow(lena)
r, c = lena.shape[0], lena.shape[1]
x = np.zeros((r, c, 8), dtype = np.uint8)
for i in range(8):
    x[:, :, i] = 2 ** i
r = np.zeros((r, c, 8), dtype = np.uint8)
for i in range(8):
    r[:, :, i] = cv2.bitwise_and(lena, x[:, :, i])
    mask = r[:, :, i] > 0
    r[mask] = 255
#     plt.gray()
#     plt.subplot(3, 3, i+1)
#     plt.imshow(r[:, :, i])
#     plt.axis('off')  # 去掉坐标轴
#     plt.title(str(i+1))
# plt.show()


#几何变换
#更改图片长宽比
res0 = cv2.resize(img, (0, 0), fx=1, fy=3)
#cv_show("res0", res0)

# 缩放
lena = cv2.imread("/home/meta/Pictures/Screenshots/lena.jpg")
print(lena.shape)                               #变换前的大小
r, c = lena.shape[0],lena.shape[1]
lena=cv2.resize(lena,(int(c*0.9),int(r*0.6)))   #宽度变为原来的0.9,高度变为原来的0.6
lena=cv2.cvtColor(lena,cv2.COLOR_BGR2RGB)
print(lena.shape)                               #变换后的大小
plt.imshow(lena)
plt.show()

lena = cv2.imread("/home/meta/Pictures/Screenshots/lena.jpg")
print(lena.shape)                               #变换前的大小
lena=cv2.resize(lena,None,fx=2,fy=0.5)          #长度变为原来的2倍,高度变为原来的0.5
lena=cv2.cvtColor(lena,cv2.COLOR_BGR2RGB)
print(lena.shape)                               #变换后的大小
plt.imshow(lena)
plt.show()


# 翻转
lena=cv2.imread("/home/meta/Pictures/Screenshots/lena.jpg")
lena=cv2.cvtColor(lena,cv2.COLOR_BGR2RGB)
x=cv2.flip(lena,0)      #0表示绕x轴变换
y=cv2.flip(lena,1)      #1表示绕y轴变换
xy=cv2.flip(lena,-1)    #-1表示绕xy轴进行变换
plt.subplot(1,3,1), plt.imshow(x)
plt.subplot(1,3,2), plt.imshow(y)
plt.subplot(1,3,3), plt.imshow(xy)
plt.show()


# 旋转
# 对lena进行逆时针45度的翻转,并进行0.6倍缩放
lena=cv2.imread("/home/meta/Pictures/Screenshots/lena.jpg")
lena=cv2.cvtColor(lena, cv2.COLOR_BGR2RGB)
height,width=lena.shape[:2]
M=cv2.getRotationMatrix2D((width/2, height/2), 15, 0.6)
rotate=cv2.warpAffine(lena, M, (width, height))
plt.imshow(rotate)
plt.show()


# 仿射
# 仿射变换是指图像可以通过一系列的几何变换来实现平移,旋转等多种操作。该变换能够保持图像的平直性和平行性。
# 平直性是指图像经过仿射变换后,直线仍然是直线;
# 平行性是指图像在完成仿射变换后,平行线仍然是平行线。
lena = cv2.imread("/home/meta/Pictures/Screenshots/lena.jpg")
lena = cv2.cvtColor(lena, cv2.COLOR_BGR2RGB)
height, width = img.shape[ : 2]
x = 100                             #x轴平行的距离
y = 200                             #y轴平行的距离
M = np.float32([[1,0,x], [0,1,y]])   #建立矩阵
move=cv2.warpAffine(img, M, (width, height)) #x,y分别向右,向下移动100,200个像素
plt.subplot(1,2,1), plt.imshow(lena)
plt.subplot(1,2,2), plt.imshow(move)
plt.show()


# 重映射
# 把一幅图像的像素点放置到另一副图像内的指定位置,这个过程成为重映射
#用remap复制lena
lena=cv2.imread('例.jpg')
rows,cols=lena.shape[:2]
mapx=np.zeros(lena.shape[:2], np.float32)
mapy=np.zeros(lena.shape[:2], np.float32)
for i in range(rows):
    for j in range(cols):
        mapx.itemset((i,j),j)
        mapy.itemset((i,j),i)
res=cv2.remap(lena, mapx, mapy, cv2.INTER_LINEAR)
res=cv2.cvtColor(res, cv2.COLOR_BGR2RGB)
lena=cv2.cvtColor(lena, cv2.COLOR_BGR2RGB)
plt.subplot(1,2,1), plt.title("original"), plt.imshow(lena)
plt.subplot(1,2,2), plt.title("result"), plt.imshow(res)
plt.show()

4.图像处理

  1. 色彩空间转换(BGR转HSV)
  2. 图像阈值处理(单通道图像,灰度图)
  3. 图像平滑处理(均值滤波、中值滤波、高斯滤波)
  4. 形态学-腐蚀操作
  5. 形态学-膨胀操作
  6. 开运算:先腐蚀,再膨胀
  7. 闭运算:先膨胀,再腐蚀
  8. 梯度运算 = 膨胀-腐蚀(可以提取图片边缘)
  9. 礼帽(顶帽)运算 = 原图像 - 开运算
  10. 黑帽运算 = 原图像 - 闭运算
  11. 图像梯度运算(Sobel算子、Scharr算子、laplacian算子)提取图像边缘的效果不同

------------------------图像处理-------------------------------------
# BGR转HSV
# 在 HSV 颜色空间下,比 BGR 更容易跟踪某种颜色的物体,常用于分割指定颜色的物体
# HSV 表达彩色图像的方式由三个部分组成:
# -Hue(色调、色相)# -Saturation(饱和度、色彩纯净度)# -Value(明度)
# 圆柱体来表示 HSV 颜色空间,圆柱体的横截面可以看做是一个极坐标系 ,
# H 用极坐标的极角表示,S 用极坐标的极轴长度表示,V 用圆柱中轴的高度表示。
# 在Hue一定的情况下:
# 饱和度减小,就是往光谱色中添加白色,光谱色所占的比例也在减小,饱和度减为0,表示光谱色所占的比例为零,整个颜色呈现白色。
# 明度减小,就是往光谱色中添加黑色,光谱色所占的比例也在减小,明度减为0,表示光谱色所占的比例为零,整个颜色呈现黑色。
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
#cv_show("hsv", hsv)


#图像阈值处理
# ret, dst = cv2.threshold(src, thresh, maxval, type)
# src: 输入图,只能输入单通道图像,通常来说为灰度图
# dst: 输出图
# thresh: 阈值
# maxval: 当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值
# type:二值化操作的类型,包含以下5种类型:
# 大于阈值部分取maxval(最大值),其他取0
ret, thresh1 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
# 大于阈值部分取0,其他取maxval(最大值)
ret, thresh2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV)
# 大于阈值部分设为阈值,其他不变
ret, thresh3 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TRUNC)
# 大于阈值部分不改变,其他设为0
ret, thresh4 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO)
# 大于阈值部分设为0,其他不变
ret, thresh5 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO_INV)

titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]

# for i in range(6):
#     plt.subplot(2, 3, i + 1), plt.imshow(images[i], 'gray')
#     plt.title(titles[i])
#     plt.xticks([]), plt.yticks([])
#plt.show()


#图像平滑
#其中可以看出中值滤波的效果最佳
img = cv2.imread('/home/meta/Pictures/Screenshots/lenaNoise.png')
blur = cv2.blur(img, (3, 3))# 均值滤波
box1 = cv2.boxFilter(img,-1,(3,3), normalize=True)  # 方框滤波
box2 = cv2.boxFilter(img,-1,(3,3), normalize=False) # 方框滤波
aussian = cv2.GaussianBlur(img, (5, 5), 1)  # 高斯滤波
median = cv2.medianBlur(img, 5)  # 中值滤波
resLvbo = np.hstack((blur, box1, aussian, median))  #把上面的图像连接成一个
# print(blur)
# print(resLvbo)

# cv_show("blur", resLvbo)


#形态学操作
# 腐蚀
pie = cv2.imread('/home/meta/Pictures/Screenshots/pie.png')
# 控制每次腐蚀速率的参数, 腐蚀三次
kernel = np.ones((20,15), np.uint8) 
erosion_1 = cv2.erode(pie, kernel, iterations = 1)
erosion_2 = cv2.erode(pie, kernel, iterations = 2)
erosion_3 = cv2.erode(pie, kernel, iterations = 3)
resErode = np.hstack((erosion_1, erosion_2, erosion_3))
#print(kernel)

# cv2.imshow('resErode', resErode)
# cv2.waitKey(0)
# cv2.destroyAllWindows()


# 膨胀
pie = cv2.imread('/home/meta/Pictures/Screenshots/pie.png')
# 控制每次膨胀速率的参数, 膨胀三次
kernel = np.ones((20, 5), np.uint8) 
dilate_1 = cv2.dilate(pie, kernel, iterations = 1)
dilate_2 = cv2.dilate(pie, kernel, iterations = 2)
dilate_3 = cv2.dilate(pie, kernel, iterations = 3)
resDilate = np.hstack((dilate_1, dilate_2, dilate_3))
# cv_show('resDilate', resDilate)


#开运算与闭运算
# 开:先腐蚀,再膨胀
img = cv2.imread('/home/meta/Pictures/Screenshots/dige.png')
kernel = np.ones((5,5),np.uint8) 
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)

# cv_show('opening', opening)



# 闭:先膨胀,再腐蚀
img = cv2.imread('/home/meta/Pictures/Screenshots/dige.png')
kernel = np.ones((30,15),np.uint8) 
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)

#cv_show('closing', closing, 2)



#梯度运算
# 梯度=膨胀-腐蚀
# 通过梯度运算可以将图片的边缘提取出
pie = cv2.imread('/home/meta/Pictures/Screenshots/pie.png')
kernel = np.ones((7,7), np.uint8) 
dilate = cv2.dilate(pie, kernel, iterations = 10)
erosion = cv2.erode(pie, kernel, iterations = 1)
gradient = cv2.morphologyEx(pie, cv2.MORPH_GRADIENT, kernel)
link = np.hstack((dilate, erosion, gradient))

#cv_show('link', link, 1)




# 礼帽与黑帽
# 礼帽 = 原始输入-开运算结果
# 黑帽 = 闭运算-原始输入
# 礼帽 突出了原图像中更亮的局域
# 黑帽 突出了原图像中更暗的局域
#礼帽
img = cv2.imread('/home/meta/Pictures/Screenshots/pie.png')
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
#cv_show('tophat', tophat, 1)

#黑帽
img = cv2.imread('/home/meta/Pictures/Screenshots/dige.png')
blackhat  = cv2.morphologyEx(img,cv2.MORPH_BLACKHAT, kernel)
#cv_show('blackhat ', blackhat, 1)



# 图像梯度-Sobel算子
# dst = cv2.Sobel(src, ddepth, dx, dy, ksize)
# ddepth:图像的深度
# dx和dy分别表示水平和竖直方向
# ksize是Sobel算子的大小
img = cv2.imread('/home/meta/Pictures/Screenshots/pie.png', cv2.IMREAD_GRAYSCALE)
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)

#cv_show('sobelx', sobelx, 2)

#sobelx与sobely分开算效果更加完美
sobelx = cv2.convertScaleAbs(sobelx)
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)
sobely = cv2.convertScaleAbs(sobely)  
sob=np.hstack((sobelx, sobely))
#cv_show('sob', sob, 2)

sobelxy = cv2.Sobel(img, cv2.CV_64F, 1, 1, ksize=3)
sobelxy = cv2.convertScaleAbs(sobelxy) 
#cv_show('sobelxy', sobelxy, 2)


#不同算子的差异
img = cv2.imread('/home/meta/Pictures/Screenshots/lena.jpg',cv2.IMREAD_GRAYSCALE)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)   
sobely = cv2.convertScaleAbs(sobely)  
sobelxy =  cv2.addWeighted(sobelx,0.5,sobely,0.5,0)  

scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
scharrx = cv2.convertScaleAbs(scharrx)   
scharry = cv2.convertScaleAbs(scharry)  
scharrxy =  cv2.addWeighted(scharrx,0.5,scharry,0.5,0) 

laplacian = cv2.Laplacian(img,cv2.CV_64F)
laplacian = cv2.convertScaleAbs(laplacian)   

link = np.hstack((sobelxy,scharrxy,laplacian))
#cv_show('link', link, 1)
#从不同算子的效果图,可以看出Scharr要比Sobel显示的边缘更加多,而Laplacian就显示的更加少了

12. Canny边缘检测

  • 使用高斯滤波器,以平滑图像,滤除噪声。
  • 计算图像中每个像素点的梯度强度和方向。
  • 应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应。
  • 应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘,调整阈值参数。
  • 通过抑制孤立的弱边缘最终完成边缘检测。

13. 图像金字塔(图像放缩)

高斯金字塔:向下采样方法(缩小);向上采样方法(放大);

上采样和下采样是非线性处理,不可逆,有损的处理!

 如果想在缩小和放大整个过程中减少信息的丢失,用这些数据形成拉普拉斯金字塔

拉普拉斯金字塔:

用来从金字塔低层图像重建上层未采样图像,在数字图像处理中也即是预测残差,

 可以对图像进行最大程度的还原,配合高斯金字塔一起使用。

14. 图像轮廓

检索图像轮廓,轮廓特征计算面积、周长,轮廓近似,边界矩形包围

# Canny边缘检测
# 使用高斯滤波器,以平滑图像,滤除噪声。
# 计算图像中每个像素点的梯度强度和方向。
# 应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应。
# 应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘。
# 通过抑制孤立的弱边缘最终完成边缘检测。
img = cv2.imread("/home/meta/Pictures/Screenshots/lena.jpg",cv2.IMREAD_GRAYSCALE)
#可以通过改变最大值和最小值来进行调整参数
v1 = cv2.Canny(img, 80, 150)
v2 = cv2.Canny(img, 50, 100)

link = np.hstack((v1, v2))
#cv_show('link', link, 2)


#图像金字塔
# 高斯金字塔
# pyrUp()放大图像,空白的像素点补0.
# pyrDown()缩小图像,将奇数行和列去掉。
# 放大缩小后会比原图像模糊,因为有像素值丢失。
def gaussian(original_image, down_times):
    temp = original_image.copy()
    gaussian_pyramid = [temp]
    for i in range(down_times):
        temp = cv2.pyrDown(temp)
        gaussian_pyramid.append(temp)
    return gaussian_pyramid


# a = cv2.imread("/home/meta/Pictures/Screenshots/konglong.jpg", -1)
# gaussian_pyramid = gaussian(a, down_times=5)
# plt.subplot(1, 3, 1), plt.imshow(a, cmap='gray')
# plt.subplot(1, 3, 2), plt.imshow(gaussian_pyramid[2], cmap='gray')
# plt.subplot(1, 3, 3), plt.imshow(gaussian_pyramid[4], cmap='gray')
# #plt.show()
# print(gaussian_pyramid[0].shape, gaussian_pyramid[1].shape, gaussian_pyramid[5].shape)
 

#拉普拉斯金字塔
# 用来从金字塔低层图像重建上层未采样图像,在数字图像处理中也即是预测残差,
# 可以对图像进行最大程度的还原,配合高斯金字塔一起使用
def laplacian(gaussian_pyramid, up_times):
    #数组中最后一位
    laplacian_pyramid = [gaussian_pyramid[-1]]
    for i in range(up_times, 0, -1):
        print(i)
        temp_pyrUp = cv2.pyrUp(gaussian_pyramid[i])
        if temp_pyrUp.shape != gaussian_pyramid[i-1].shape:   
            x = gaussian_pyramid[i-1].shape[0]  
            y = gaussian_pyramid[i-1].shape[1]   
            # print("x=", x)     
            # print("y=", y)    
            temp_pyrUp = cv2.resize(temp_pyrUp, (y, x))  
            
        #两个图像矩阵相减, 要求两个矩阵必须有相同大小和通道数
        temp_lap = cv2.subtract(gaussian_pyramid[i-1], temp_pyrUp)
        laplacian_pyramid.append(temp_lap)

        if (gaussian_pyramid[i-1] == temp_pyrUp).all():
            print("same")
        else:
            print("diffrent")
        print(temp_pyrUp.shape )
        print(gaussian_pyramid[i-1].shape)

    return laplacian_pyramid


# a = cv2.imread("/home/meta/Pictures/Screenshots/konglong.jpg", -1)
# gaussian_pyramid = gaussian(a, down_times=5)
# laplacian_pyramid = laplacian(gaussian_pyramid, up_times=5)

# print("length_gaussian_pyramid = ", len(gaussian_pyramid))
# print("length_laplacian_pyramid = ", len(laplacian_pyramid))

# plt.subplot(2, 3, 1), plt.imshow(a, cmap='gray')
# plt.subplot(2, 3, 2), plt.imshow(gaussian_pyramid[2], cmap='gray')
# plt.subplot(2, 3, 3), plt.imshow(gaussian_pyramid[4], cmap='gray')
# plt.subplot(2, 3, 4), plt.imshow(laplacian_pyramid[0], cmap='gray')
# plt.subplot(2, 3, 5), plt.imshow(laplacian_pyramid[2], cmap='gray')
# plt.subplot(2, 3, 6), plt.imshow(laplacian_pyramid[4], cmap='gray')
# plt.show()
# print(gaussian_pyramid[0].shape, len(gaussian_pyramid), len(laplacian_pyramid))





#图像轮廓
# cv2.findContours(img,mode,method)
# mode:轮廓检索模式
# RETR_EXTERNAL :只检索最外面的轮廓;
# RETR_LIST:检索所有的轮廓,并将其保存到一条链表当中;
# RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;
# RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次;
# method:轮廓逼近方法
# CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。
# CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。
img = cv2.imread('/home/meta/Pictures/Screenshots/contours.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)      #阈值处理

#输出参数:contours  轮廓  M*N  M是轮廓个数  N是每个轮廓的点
#        hierarchy 轮廓等级关系 M*4
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

# 传入绘制图像,轮廓,轮廓索引,颜色模式,线条厚度
# 注意需要copy,要不原图会变
draw_img = img.copy()
resdraw = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2)  #-1表示显示所有轮廓,123表示第123个轮廓
cv_show('resdraw', resdraw)


#轮廓特征
cnt = contours[0]
#面积
area = cv2.contourArea(cnt)
print("area =", area)
#周长,True表示闭合的
perimeter = cv2.arcLength(cnt, True)
print("perimeter =", perimeter)


# 轮廓近似
# 用最少的线来代替,在几个点之间的直线,如果能用更少的点来表示,就采用更少的点。
epsilon = 0.1*cv2.arcLength(cnt, True)          #主要进行调参的函数
approx = cv2.approxPolyDP(cnt, epsilon, True)   #函数的输出为近似多边形的顶点坐标

draw_img = img.copy()
resApprox = cv2.drawContours(draw_img, [approx], -1, (0, 0, 255), 2)
cv_show('resApprox', resApprox)


# 边界矩形
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = contours[0]

x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
cv_show('img', img)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值