OpenCv_02——图像处理


上一篇: OpenCv_01——图像的基本操作
下一篇: OpenCv_03——图像特征

2. 图像处理

测试图像自取区

boss.jpg car.jpg card1 card2 cat.jpg dog.jpg girl.jpg girl1.jpg girl1_.jpg huo1.jpg img1.jpg maliao.jpg maliao_coin.jpg

page.jpg yuan.jpg

2.1 图像阙值

image-20220904130531702

#导包
import cv2
import matplotlib.pyplot as plt
#读取图片
img_cat=cv2.imread('cat.jpg')

ret,thresh1=cv2.threshold(img_cat,127,255,cv2.THRESH_BINARY)
ret,thresh2=cv2.threshold(img_cat,127,255,cv2.THRESH_BINARY_INV)
ret,thresh3=cv2.threshold(img_cat,127,255,cv2.THRESH_TRUNC)
ret,thresh4=cv2.threshold(img_cat,127,255,cv2.THRESH_TOZERO)
ret,thresh5=cv2.threshold(img_cat,127,255,cv2.THRESH_TOZERO_INV)

titles=['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
images=[img_cat,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()

image-20220904130751220

2.2 图像平滑

#导包
import cv2
import matplotlib.pyplot as plt
#读数据
img=cv2.imread('cat.jpg')
#输出图片
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

#均值滤波
#简单的平均卷积操作
blur=cv2.blur(img,(3,3))

cv2.imshow('blur',blur)
cv2.waitKey(0)
cv2.destroyAllWindows()

image-20220904131029804

#方框滤波
#基本和均值一样,可以选择归一化
box=cv2.boxFilter(img,-1,(3,3),normalize=True)

cv2.imshow('box',box)
cv2.waitKey(0)
cv2.destroyAllWindows()

image-20220904131110023

#方框滤波
#基本和均值一样,可以选择归一化,容易越界
box=cv2.boxFilter(img,-1,(3,3),normalize=True)

cv2.imshow('box',box)
cv2.waitKey(0)
cv2.destroyAllWindows()

image-20220904131152761

#高斯滤波
#高斯模糊的卷积核里的数值是满足高斯分布,相当于更重视中间的
aussian=cv2.GaussianBlur(img,(1,1),1)

cv2.imshow('aussian',aussian)
cv2.waitKey(0)
cv2.destroyAllWindows()

image-20220904131331866

#中值滤波
#相当于用中值代替
median=cv2.medianBlur(img,5)

cv2.imshow('median',median)
cv2.waitKey(0)
cv2.destroyAllWindows()

image-20220904131404347

import numpy as np

#展示所有的
res=np.hstack((blur,aussian,median))
print(res)
cv2.imshow('median vc average',res)
cv2.waitKey(0)
cv2.destroyAllWindows()
[[[122 147 191]
  [121 146 190]
  [120 145 189]
  ...
  [114 138 184]
  [114 138 184]
  [115 139 185]]

 [[121 146 190]
  [121 146 190]
  [119 144 188]
  ...
  [113 137 183]
  [114 138 184]
  [114 138 184]]

 [[120 145 189]
  [119 144 188]
  [118 143 187]
  ...
  [112 136 182]
  [113 137 183]
  [114 138 184]]

 ...

 [[178 201 233]
  [178 201 233]
  [178 201 233]
  ...
  [191 211 240]
  [192 212 242]
  [193 213 243]]

 [[180 203 235]
  [180 203 235]
  [180 203 235]
  ...
  [192 211 242]
  [192 212 242]
  [193 213 243]]

 [[181 204 236]
  [181 204 236]
  [181 204 236]
  ...
  [192 212 243]
  [192 212 243]
  [193 213 243]]]

2.3 形态学操作

2.3.1 腐蚀操作

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

img=cv2.imread('huo1.jpg')

cv2.imshow('huo',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
image-20220904131831570
#腐蚀操作
kernel=np.ones((3,3),np.uint8)
erosion=cv2.erode(img,kernel,iterations=1)

cv2.imshow('erosion',erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()
image-20220904131903460
#膨胀操作
kernel=np.ones((3,3),np.uint8)
dilate=cv2.dilate(img,kernel,iterations=1)

cv2.imshow('dilate',dilate)
cv2.waitKey(0)
cv2.destroyAllWindows()
image-20220904132011245

2.3.2 开运算与闭运算

import cv2
import numpy as np

#开运算:先腐蚀,再膨胀
img=cv2.imread('huo1.jpg')

kerne1=np.ones((5,5),np.uint8)
opening=cv2.morphologyEx(img,cv2.MORPH_OPEN,kerne1)

cv2.imshow('opening',opening)
cv2.waitKey(0)
cv2.destroyAllWindows()
image-20220904133340381
#闭运算:先膨胀,再腐蚀
img=cv2.imread('huo1.jpg')

kerne1=np.ones((5,5),np.uint8)
closing=cv2.morphologyEx(img,cv2.MORPH_CLOSE,kerne1)

cv2.imshow('closing',closing)
cv2.waitKey(0)
cv2.destroyAllWindows()
image-20220904133401255

2.3.3 梯度运算

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

#分别输出膨胀与腐蚀的图片
pie=cv2.imread('yuan.jpg')
kernel=np.ones((7,7),np.uint8)
dilate=cv2.dilate(pie,kernel,iterations=5)
erosion=cv2.erode(pie,kernel,iterations=5)

res=np.hstack((dilate,erosion))

cv2.imshow('res',res)
cv2.waitKey(0)
cv2.destroyAllWindows()
image-20220904133611776
#梯度=膨胀-腐蚀
#梯度运算,输出边界图
gradient=cv2.morphologyEx(pie,cv2.MORPH_GRADIENT,kernel)

cv2.imshow('gradient',gradient)
cv2.waitKey(0)
cv2.destroyAllWindows()
image-20220904133653646

2.3.4 礼帽与黑帽

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

#礼帽=原始数据-开运算结果
img=cv2.imread('huo1.jpg')
kernel=np.ones((7,7),np.uint8)
tohat=cv2.morphologyEx(img,cv2.MORPH_TOPHAT,kernel)
cv2.imshow('tohat',tohat)
cv2.waitKey(0)
cv2.destroyAllWindows()

image-20220904133953812

#黑帽
img=cv2.imread('huo1.jpg')
kernel=np.ones((7,7),np.uint8)
blackhat=cv2.morphologyEx(img,cv2.MORPH_BLACKHAT,kernel)
cv2.imshow('blackhat',blackhat)
cv2.waitKey(0)
cv2.destroyAllWindows()

image-20220904134103101

2.4 图像梯度

2.4.1 Sobel算子

image-20220904134313600

image-20220904135008271

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

img=cv2.imread('yuan.jpg',cv2.IMREAD_GRAYSCALE)
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
image-20220904134410221
def cv_show(name,img):
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
sobelx=cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
#白到黑是整数,黑到白就是负数了,所有的负数会被截断成0,所以要取绝对值
cv_show('sobelx',sobelx)
image-20220904135300584
sobelx=cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobelx=cv2.convertScaleAbs(sobelx)
cv_show('sobelx',sobelx)
image-20220904135334871
sobely=cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobely=cv2.convertScaleAbs(sobely)
cv_show('sobely',sobely)
image-20220904135403247
#同时输出,比较
res=np.hstack((sobelx,sobely))
cv_show('res',res)
image-20220904135431245
#分别计算x和y,再求和
sobelxy=cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
cv_show('sobelxy',sobelxy)
image-20220904135600152
#不建议直接计算
sobelxy=cv2.Sobel(img,cv2.CV_64F,1,1,ksize=3)
sobelxy=cv2.convertScaleAbs(sobelxy)
cv_show('sobelxy',sobelxy)

image-20220904135627636

#读取图片,用Sobel算子进行边缘输出
img=cv2.imread('boss.jpg',cv2.IMREAD_GRAYSCALE)

sobelx=cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobelx=cv2.convertScaleAbs(sobelx)

sobely=cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobely=cv2.convertScaleAbs(sobely)

sobelxy=cv2.addWeighted(sobelx,0.5,sobely,0.5,0)

#效果图与原图的灰度图合并输出
res=np.hstack((img,sobelxy))
cv_show('res',res)
image-20220904135759612
sobelxy=cv2.Sobel(img,cv2.CV_64F,1,1,ksize=3)
sobelxy=cv2.convertScaleAbs(sobelxy)
cv_show('sobelxy',sobelxy)
image-20220904135928499

2.4.2 Scharr算子与Lapkacian算子

Scharr算子

image-20220904140308896

Lapkacian算子

image-20220904140338923

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

def cv_show(name,img):
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
#比较
img=cv2.imread('boss.jpg',cv2.IMREAD_GRAYSCALE)

#Sobel算子
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)

#Scharr算子
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算子
laplacian=cv2.Laplacian(img,cv2.CV_64F)
laplacian=cv2.convertScaleAbs(laplacian)

#输出比较
res=np.hstack((sobelxy,scharrxy,laplacian))
cv_show('res',res)

image-20220904140936673

2.5 边缘检测

Canny边缘检测

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

高斯滤波器

image-20220904141550441

梯度和方向

image-20220904141710899

非极大值抑制

image-20220904141804291

image-20220904141828855

双阙值检测

image-20220904141911787

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

def cv_show(name,img):
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

img=cv2.imread('cat.jpg',cv2.IMREAD_GRAYSCALE)

#进行边缘检测
#minvalue和maxvalue的值由自己设置
v1=cv2.Canny(img,20,60)
v2=cv2.Canny(img,50,100)

res=np.hstack((v1,v2))
cv_show('res',res)

image-20220904142711681

2.6 图像金字塔

向下采样法(缩小)

image-20220904143203297

向上采样法(放大)

image-20220904143342949

  1. 将图像在每个方向扩大为原来的两倍,新增的行和列用0填充
  2. 使用先前同样的内核(乘以四)与放大后的图像卷积,获得近似值

普拉斯金字塔

对输入图像实现金字塔的reduce操作就会生成不同分辨率的图像、对这些图像进行金字塔expand操作,然后使用reduce减去expand之后的结果就会得到图像拉普拉斯金字塔图像。

输入图像G(0)
金字塔reduce操作生成 G(1), G(2), G(3)
拉普拉斯金字塔:
L0 = G(0)-expand(G(1))
L1 = G(1)-expand(G(2))
L2 = G(2)–expand(G(3))
G(0)减去expand(G(1))得到的结果就是两次高斯模糊输出的不同,所以L0称为DOG(高斯不同)、它约等于LOG所以又称为拉普拉斯金字塔。所以要求的图像的拉普拉斯金字塔,首先要进行金字塔的reduce操作,然后在通过expand操作,最后相减得到拉普拉斯金字塔图像。

拉普拉斯金字塔生成过程

image-20220904144356598

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

def cv_show(name,img):
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
img=cv2.imread('girl.jpg')
cv_show('img',img)
print(img.shape)
image-20220904143756578
#向上采样法
up=cv2.pyrUp(img)
cv_show('up',up)
print(up.shape)
#(1392, 1200, 3)

#向下采样法
down=cv2.pyrDown(img)
cv_show('down',down)
print(down.shape)
#(348, 300, 3)

#拉普拉斯金字塔
down=cv2.pyrDown(img)
down_up=cv2.pyrUp(down)
result=img-down_up
cv_show('result',result)
image-20220904144303914

2.7 轮廓检测

2.7.1 图像轮廓

cv2.findContours(img,mode,method)

mode:轮廓检索模式

参数说明
RETR_EXTERNAL只检索最外面的轮廓
RETR_LIST检索所有的轮廓,并将其保存到一条链表中
RETR_CCOMP检索所有的轮廓,并将它们组织为两层;顶层是各部分的外部链接,第二层是空洞的边界
RETR_TREE检索所有的轮廓,并重构嵌套轮廓的层次

medthod:轮廓逼近方法

参数说明
CHAIN_APPROX_NONE以Freem链码的方式输出轮廓,所有其他方法输出多边形(顶点的轮廓)
CHAIN_APPROX_SIMPLE压缩水平的、垂直的和斜的部分,也就是,函数只保留它们的终点部分

为了更高的准确率,使用二值图像

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

def cv_show(name,img):
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

#为了更高的准确率,使用二值图像
img=cv2.imread('car.jpg')
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
cv_show('thresh',thresh)

binary,contours,hierarchy=cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cv_show('binary',binary)
image-20220904152321883

2.7.2 绘制轮廓

cv2.drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None)

参数说明
第一个参数指明在哪幅图像上绘制轮廓;image为三通道才能显示轮廓
第二个参数是轮廓本身,在Python中是一个list;

thickness参数指定绘制轮廓list中的哪条轮廓,如果是-1,则绘制其中的所有轮廓。其中thickness表明轮廓线的宽度,如果是-1(cv2.FILLED),则为填充模式。

#引入绘制图像,轮廓,轮廓索引,颜色模式,线条厚度
#需要注意copy,要不原图会变
res=img.copy()
res=cv2.drawContours(res,contours,-1,(0,0,255),2)
cv_show('res',res)
image-20220904152416483
#轮廓特征
cnt=contours[0]
#面积
cv2.contourArea(cnt)
#0.0
#周长,True表示闭合的
cv2.arcLength(cnt,True)
#0.0

2.7.3 轮廓近似

cv2.approxPolyDP(InputArray curve, OutputArray approxCurve, double epsilon, bool closed)

参数说明
InputArray curve输入的点集
OutputArray approxCurve输出的点集,当前点集是能最小包容指定点集的。画出来即是一个多边形
double epsilon指定的精度,也即是原始曲线与近似曲线之间的最大距离
bool closed若为true,则说明近似曲线是闭合的,反之,若为false,则断开
img=cv2.imread('img1.jpg')

gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
binary,contours,hierarchy=cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt=contours[0]

draw_img=img.copy()
res=cv2.drawContours(draw_img,[cnt],-1,(0,0,255),2)
cv_show('res',res)
image-20220904152838721
espsilon=0.05*cv2.arcLength(cnt,True)
approx=cv2.approxPolyDP(cnt,espsilon,True)

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

image-20220904152859153

2.7.4 边界矩形

cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)

  • 第一个参数:img是原图

  • 第二个参数:(x,y)是矩阵的左上点坐标

  • 第三个参数:(x+w,y+h)是矩阵的右下点坐标

  • 第四个参数:(0,255,0)是画线对应的rgb颜色

  • 第五个参数:2是所画的线的宽度

img=cv2.imread('img1.jpg')

gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
binary,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)
image-20220904153123870
#轮廓面积与边界矩形比
area=cv2.contourArea(cnt)
x,y,w,h=cv2.boundingRect(cnt)
rect_area=w*h
extent=float(area)/rect_area
print("轮廓面积与边界矩形比",extent)
#轮廓面积与边界矩形比 0.7065451180472189

2.7.5 外接圆

center, radius = cv.minEnclosingCircle( points )

参数描述
center返回值,圆的中心
radius返回值,半径
points目标物体的点
(x,y),radius=cv2.minEnclosingCircle(cnt)
center=(int(x),int(y))
radius=int(radius)
img=cv2.circle(img,center,radius,(0,2555,0),2)
cv_show('img',img)
image-20220904153337132

2.8 模板匹配

模板匹配和卷积原理很像,模板在原图像上从原点开始滑动,计算模板与(图像被模板覆盖的地方)的差别程度,这个差别程度的计算方法在opencv中有6种,然后将每次计算的结果放入一个矩阵里,作为结果输出。假如原图形是A乘B大小,而模板是a乘b大小,则结果输出的矩阵是(A-a+1)×(B-b+1)

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

def cv_show(name,img):
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
#模板匹配
img=cv2.imread('girl1.jpg',0)
template=cv2.imread('girl1_.jpg',0)
h,w=template.shape[:2]

h
#901
w
#629
img.shape
#(2340, 1080)
template.shape
#(901, 629)

methods=['cv2.TM_CCOEFF','cv2.TM_CCOEFF_NORMED','cv2.TM_CCORR',
        'cv2.TM_CCORR_NORMED','cv2.TM_SQDIFF','cv2.TM_SQDIFF_NORMED']
方法说明
TM_CCOEFF计算相关系数,计算出来的值越大,越相关。
TM_CCOEFF_NORMED计算归一化相关系数,计算出来的值越接近1,越相关。
TM_CCORR计算相关性,计算出来的值越打,越相关。
TM_CCORR_NORMED计算归一化相关性,计算出来的值越接近1,越相关。
TM_SQDIFF计算平方不同,计算出来的值越小,越相关。
TM_SQDIFF_NORMED计算归一化平方不同,计算出来的值越接近0,越相关。
res=cv2.matchTemplate(img,template,cv2.TM_SQDIFF)
res.shape
#(1440, 452)

cv2.minMaxLoc(src, mask=None)

函数功能:假设有一个矩阵a,现在需要求这个矩阵的最小值,最大值,并得到最大值,最小值的索引。

咋一看感觉很复杂,但使用这个cv2.minMaxLoc()函数就可全部解决。函数返回的四个值就是上述所要得到的

min_val,max_val,min_loc,max_loc=cv2.minMaxLoc(res)
min_val
#190976.0

max_val
#8067120640.0

min_loc
#(256, 422)

max_loc
#(451, 0)

eval是Python的一个内置函数,功能十分强大,这个函数的作用是,返回传入字符串的表达式的结果。

就是说:将字符串当成有效的表达式 来求值 并 返回计算结果。

cv2.rectangle(img, pt1, pt2, color, thickness, lineType, shift )

for meth in methods:
    img2=img.copy()
    
    #匹配方法的真值
    method=eval(meth)
    print(method)
    res=cv2.matchTemplate(img,template,method)
    min_val,max_val,min_loc,max_loc=cv2.minMaxLoc(res)
    
    #如果是平方差匹配到TM_SQDIFF或归一化平方差匹配到TM_SQDIFF_NORMED,取最小值
    if method in [cv2.TM_SQDIFF,cv2.TM_SQDIFF_NORMED]:
        top_left=min_loc
    else:
        top_left=max_loc
    bottom_right=(top_left[0]+w,top_left[1]+h)
    
    #画矩形
    cv2.rectangle(img2,top_left,bottom_right,255,20)
    
    plt.subplot(121),plt.imshow(res,cmap='gray')
    plt.xticks([]),plt.yticks([])#隐藏坐标轴
    plt.subplot(122),plt.imshow(img2,cmap='gray')
    plt.xticks([]),plt.yticks([])
    plt.suptitle(meth)
    plt.show()

image-20220905082024354

image-20220905082039839

image-20220905082053951

image-20220905082111304

image-20220905082127507

image-20220905082135295

#匹配多个对象
img_rgb=cv2.imread('maliao.jpg')
img_gray=cv2.cvtColor(img_rgb,cv2.COLOR_BGR2GRAY)
template=cv2.imread('maliao_coin.jpg',0)
h,w=template.shape[:2]

res=cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)
#取匹配度大于80%的坐标
threshold=0.8
loc=np.where(res>=threshold)
for pt in zip(*loc[::-1]):#*表示可选参数
    bottom_right=(pt[0]+w,pt[1]+h)
    cv2.rectangle(img_rgb,pt,bottom_right,(0,0,255),2)

cv2.imshow('img_rgb',img_rgb)
cv2.waitKey(0)

image-20220905082303432

2.9 直方图

2.9.1 直方图定义

cv2.calcHist(images,channels,mask,histSize,ranges)

参数说明
images原图像图像格式为uint8或float32.当传入函数时应用中括号[]括,例如[img]。
channels同样用中括号来括它会告知函数我们统幅图像的直方图。如果入图像是灰度图它的值就是[0],如果是彩色图像的传入的参数可以是[0][1][2],它们分别对应着BGR。
mask掩膜图像。统整幅图像的直方图就把它为None。如果你想同图像某一分的直方图的,你就制作一个掩膜图像并使用它。
histSizeBIN的数目。也应用种括号来括。
ranges像素值的范围为[0,256]。
import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
#使用%matplotlib命令可以将matplotlib的图表直接嵌入到Notebook之中

def cv_show(name,img):
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
img=cv2.imread('girl1.jpg',0)#0表示灰度图
hist=cv2.calcHist([img],[0],None,[256],[0,256])
hist.shape
#(256, 1)

#ravel()将多维数据展平为一维数据
plt.hist(img.ravel(),256)
plt.show()

image-20220905082608863

img=cv2.imread('girl1.jpg')
color=('b','g','r')
for i,col in enumerate(color):
    histr=cv2.calcHist([img],[i],None,[256],[0,256])
    plt.plot(histr,color=col)
    plt.xlim([0,256])

image-20220905082626413

#创建mask掩码
mask=np.zeros(img.shape[:2],np.uint8)
mask[100:300,100:400]=255
cv_show('mask',mask)

img=cv2.imread('cat.jpg',0)
plt.hist(img.ravel(),256)
plt.show()

image-20220905082650640

#均衡化函数
equ=cv2.equalizeHist(img)
plt.hist(equ.ravel(),256)
plt.show()

image-20220905082704969

#均衡化之后的图像
res=np.hstack((img,equ))
cv_show('res',res)

image-20220905084005988

2.9.3 直方图均衡化

cv2.createCLAHE(clipLimit,tileGridSize)

参数说明
clipLimit裁剪限制,此值与对比度受限相对应,对比度限制这个参数是用每块的直方图的每个bins的数和整图的平均灰度分布数的比值来限制的。 裁剪则是将每块图像直方图中超过ClipLimit的bins多出的灰度像素数去除超出部分,然后将所有bins超出的像素数累加后平均分配到所有bins。
tileGridSize图像被分成称为“tiles”(瓷砖、地砖、小方地毯、片状材料、块状材料)的小块,在OpenCV中,tilesGridSize默认为8x8 ,即整个图像被划分为8纵8横共64块。然后对每一个块进行直方图均衡处理。
cat=cv2.createCLAHE(clipLimit=2.0,tileGridSize=(8,8))

res_cat=cat.apply(img)
res=np.hstack((img,equ,res_cat))
cv_show('res',res)

image-20220905084053250

2.10 傅里叶

2.10.1 傅里叶概述

傅里叶变换

我们生活在时间的世界中,早上7:00起来吃早饭,8:00去挤地铁,9:00开始上班,,,以时间为参照就是时域分析。

但是我们在频域中一切都是静止的。

傅里叶变换的作用

  • 高频:变化剧烈的灰度分量,例如边界。
  • 低频:变化缓慢的灰度分量,例如一片大海。

滤波

  • 低通滤波器:只保留低频,会使图像模糊。

  • 高通滤波器:只保留高频,会使图像细节增强。

  • opencv中主要是以cv2.dft()和cv2.idft(),输入图像需要先转换成np.float32格式。

  • 得到的结果中频率为0的部分会在左上角,通常要转换到中心位置,可以通过shift变换来实现。

  • cv2.dft()返回的结果是双通道的(实部,虚部),通常还需要转换成图像格式才可能展示(0,255)

2.10.2 代码实现

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

cv2.dft(原始图像,转换标识)

这里的原始图像必须是np.float32格式。所以,我们首先需要使用cv2.float32()函数将图像转换。

而转换标识的值通常为cv2.DFT_COMPLEX_OUTPUT,用来输出一个复数阵列。

cv2.magnitude(参数1,参数2)

参数1:浮点型x坐标值,也就是实部

参数2:浮点型y坐标值,也就是虚部,它必须和参数1具有相同的大小(size)

得到频谱图像的幅度之后,还需要将幅度映射到灰度空间[0,255]内,使其以灰度图像显示出来。与前篇博文一样,使用20*np.log(cv2.magnitude())。

img=cv2.imread('dog.jpg',0)

img_float32=np.float32(img)

dft=cv2.dft(img_float32,flags=cv2.DFT_COMPLEX_OUTPUT)
dft_shift=np.fft.fftshift(dft)
#得到灰度图能表示的形式
magnitude_sepctrum=20*np.log(cv2.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))

plt.subplot(121),plt.imshow(img,cmap='gray')
plt.title('Input Image'),plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_sepctrum,cmap='gray')
plt.title('Magnitude Spectrum'),plt.xticks([]),plt.yticks([])
plt.show()

image-20220905085506943

img=cv2.imread('dog.jpg',0)

img_float32=np.float32(img)

dft=cv2.dft(img_float32,flags=cv2.DFT_COMPLEX_OUTPUT)
dft_shift=np.fft.fftshift(dft)

rows,cols=img.shape
crow,ccol=int(rows/2),int(cols/2)    #中心位置

#低通滤波
mask=np.zeros((rows,cols,2),np.uint8)
mask[crow-30:crow+30,ccol-30:ccol+30]=1

#IDFT
fshift=dft_shift*mask
f_ishift=np.fft.ifftshift(fshift)
img_back=cv2.idft(f_ishift)
img_back=cv2.magnitude(img_back[:,:,0],img_back[:,:,1])

plt.subplot(121),plt.imshow(img,cmap='gray')
plt.title('Input Image'),plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(img_back,cmap='gray')
plt.title('Result'),plt.xticks([]),plt.yticks([])
plt.show()

image-20220905085533698

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

要什么自行车儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值