opencv学习笔记

目录

1、cap = cv2.imread(filename, flags)

2、cv2.imshow(str,imge)

3、cv2.namedWindow(window_name, flag)

4、cv2.waitKey(k)

5、cv2.destroyAllWindows()

6、cv2.imwrite(filename, img, paras)

7、cap = cv2.VideoCapture(0)

8、ret, frame = cap.read()

9、Video_write=cv2.VideoWriter(filename, fourcc, franesize(), iscolor)

10、frame = cv2.flip(frame, flags)

11、dst = cv2.add(scr1, scr2, dst, mask, dtype)

12、dst = cv2.addWeighted(img1, a , img2, b , c)

13、dst = cv2.bitwise_and(img1, img2, dst, mask)

14、dst = cv2.cvtColor(img, flags)

15、ret, dst = cv2.threshold(src, thresh, maxval, type)

16、dst = cv2.warpAffine(src, M, dsize, flags, borderMode, borderValue)

17、M = cv2.getAffineTransform(pts1,pts2)

18、M = getRotationMatrix2D(center, -45, 1)

19、dst = cv2.resize(img, (dsize), double fx, double fy, interpolation)

20、cv2.setMouseCallback(winname, onMouse, userdata=0)

21、cv2.circle(img, center, radius, color(B,G,R), thickness, linetype, shift)

22、cv2.line(img, pt1, pt2, color, thickness)

23、cv2.polylines(img, pts, isclosed, color, thickness, linetype, shift)

24、cv2.fillPoly(img, pts, color, linetype, shift)

25、M = cv2.getPerspectiveTransform(pts1, pts2)

26、dst = cv2.warpPerspective(src, M, dsize, flags, borderMode, borderValue)

27、mag, ang = cv2.cartToPolar(x, y, anangleInDegrees)

28、cv2.logPolar(scr, center, M, flags)

29、cv2.transpose(img)

30、dst = cv2.rotate(img, rotatcode)

31、dst = cv2.warpPolar(img, dsize, center, maxRadius, flags)

图像增强

直方图均衡化

32、plt.hist(...)

33、cv2.calcHist( [img],[flag],mask,[histSize],[ranges] )

34、cv2.equalizeHist(img)

35、cv2.createCLAHE(clipLimit,tileGridSize)

直方图规定化:

36、cv2.LUT(img,map)

非锐化掩膜和高频提升滤波

基于同态滤波的增强

图像平滑

图像中的噪声

37、np.random.normal(loc,scale,size)

38、np.clip(a,a_min,a_max)

空间域平滑滤波

39、cv2.bulr(img,ksize)

40、cv2.GaussianBlur(img,ksize,sigmaX,sigmaY,borderType)

41、cv2.medianBlur(img,ksize)

42、cv2.bilateralFilter(img,d,sigmgColor,sigmaSpace,borderType)

频域平滑滤波

43、cv2.createTrackbar(trackbarname,winname,value,maxValue,function)

44、cv2.getTrackbarPos(trackbarname,winname)

45、cv2.resizeWindow(winname,width,height)

46、cv2.getOptimalDFTSize(value)

47、cv2.dft(img,flag)

48、np.fft.fftshift(img)

49、cv2.magnitude(inputArray_x,inputArray_y)

50、cv2.normalize(img,dst,0,255,flag)

51、cv2.split(img,mv)

52、cv2.merge(mv,dst)

图像锐化

图像边缘分析

算子检测边缘

53、cv2.filter2D(img,ddepth,kernel,anchor,delta,borderType)

54、cv2.convertScalerAbs(img)

55、cv2.Sobel(img,ddepth,dx,dy,ksize)

56、cv2.Laplacion(img,ddepth,ksize,scale,delta,borderType)

57、cv2.Ganny(img,threshold1,threshold2,apertureSize)

频域高通滤波实现图像锐化


1、cap = cv2.imread(filename, flags)

(返回图片的像素矩阵,Numpy.uint8类型)
cap.shape:图片长、宽、通道。
cap.size:图片的像素数目,长*宽*通道
cap.dtype:图片的数据类型
读出来的格式是BGR。
filepath:读入imge的完整路径
flags:标志位,{cv2.IMREAD_COLOR,cv2.IMREAD_GRAYSCALE,cv2.IMREAD_UNCHANGED}
cv2.IMREAD_COLOR:默认参数,读入一副彩色图片,忽略alpha通道,可用1作为实参替代
cv2.IMREAD_GRAYSCALE:读入灰度图片,可用0作为实参替代
cv2.IMREAD_UNCHANGED:顾名思义,读入完整图片,包括alpha通道,可用-1作为实参替代
PS:alpha通道,又称A通道,是一个8位的灰度通道,该通道用256级灰度来记录图像中的透明度复信息,定义透明、不透明和半透明区域,其中黑表示全透明,白表示不透明,灰表示半透明

2、cv2.imshow(str,imge)

(没有返回值)
str:输出的窗口名称,该窗口和图像的原始大小自适应(自动调整到原始尺寸)且不可调节。它是一个字符串类型。第二个参数是我们的图像。可以创建任意数量的窗口,但必须使用不同的窗口名称。 
imge:所展示图片的像素值矩阵。即所读的图片

3、cv2.namedWindow(window_name, flag)

(没有返回值)
window_name:将显示图像/视频的窗口的名称。

flag:表示窗口大小是自动设置还是可调整。WINDOW_NORMAL :允许手动更改窗口大小、WINDOW_AUTOSIZE(Default) :自动 设置窗口大小、WINDOW_FULLSCREEN :将窗口大小更改为全屏。

4、cv2.waitKey(k)

(返回键盘按键值)
k:在时间k(单位ms)内,等待用户按键,返回按键的值,如果没有触发事件,则跳出等待。默认k=0,则无限等待按键。

5、cv2.destroyAllWindows()

(无返回值)
删除窗口的函数,()里不指定任何参数,则删除所有窗口,删除特定的窗口,往()输入特定的窗口值。

6、cv2.imwrite(filename, img, paras)

(返回true或false)
filename:要保存的文件的路径和名称,包括文件扩展名。
img:要保存的 OpenCV 图像。
paras:不同编码格式的参数,可选项:
        cv2.CV_IMWRITE_JPEG_QUALITY:设置 .jpeg/.jpg 格式的图片质量,取值为 0-100(默认值 95),数值越大则图片质量越高;
        cv2.CV_IMWRITE_WEBP_QUALITY:设置 .webp 格式的图片质量,取值为 0-100;
        cv2.CV_IMWRITE_PNG_COMPRESSION:设置 .png 格式图片的压缩比,取值为 0-9(默认值 3),数值越大则压缩比越大。

import cv2                      #导入cv2模块
import os

img = cv2.imread("E:/.../lena.jpg")  #读取lena图像
print(img)   #图像的像素
print("图像的形状是:", img.shape)        #获取图像的行数(高度)、列数(宽度)、通道数
print("图像的像素数目为:", img.size)     #获取图像的像素数目
print("图像的数据类型为:", img.dtype)    #获得图像的数据类型


cv2.namedWindow("Image")          #创建一个名为img的窗口
cv2.imshow("Image", img)            #显示读入的图像
cv2.imwrite("C:/.../lena2.jpg", img)
cv2.waitKey()     #等待键盘输入,默认无限等待
cv2.destroyAllWindows()

path_dir = "E:/.../chapter_2_Pics"           # 设置路径,读取文件夹中的所有图像
for filename in os.listdir(path_dir):   #遍历文件夹中的图片
    img = cv2.imread(path_dir + "/" + filename)
    cv2.imshow(filename, img)  #显示图片
    cv2.waitKey()
    cv2.imwrite("C:/..." + "/" + filename, img)  #保存图片

cv2.destroyAllWindows()             #释放所有窗口

7、cap = cv2.VideoCapture(0)

参数0表示默认为笔记本的内置第一个摄像头,如果需要读取已有的视频则参数改为视频所在路径,例如:cap=cv2.VideoCapture(‘E:/.../video.mp4’)
cv2.VideoCapture.get(3)    CV_CAP_PROP_FRAME_WIDTH 在视频流的帧的宽度
cv2.VideoCapture.get(4)    CV_CAP_PROP_FRAME_HEIGHT 在视频流的帧的高度
cv2.VideoCapture.get(5)    CV_CAP_PROP_FPS 帧速率
链接:https://blog.csdn.net/sazass/article/details/105559536
cap.release():停止捕捉视频。

8、ret, frame = cap.read()

按帧读取视频,返回值ret是布尔型,正确读取则返回True,读取失败或读取视频结尾则会返回False;frame为视频的每一帧的图像。

9、Video_write=cv2.VideoWriter(filename, fourcc, franesize(), iscolor)

filename 是要保存的文件的路径;fourcc 指定编码器;fps 要保存的视频的帧率;frameSize 要保存的文件的画面尺寸;isColor 指示是黑白画面还是彩色的画面。
fourcc编码器:https://www.cnblogs.com/philothypeipei/p/11398504.html

10、frame = cv2.flip(frame, flags)

frame:需要操作的图像
falgs:翻转方式;1(水平翻转);0(垂直翻转);-1(水平垂直翻转)。

import cv2
import time

cap = cv2.VideoCapture(0)  #获取摄像头
# 获取视频码率和尺寸
fps = cap.get(cv2.CAP_PROP_FPS)
size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
print(fps)
print(size)

# 写入视频帧; cv2.VideoWriter(路径,编码器,帧率,尺寸)
# 编码器:I420,PIM1,XVID,THEO,FLV1
video_writer = cv2.VideoWriter('E:/.../My_video1.avi', cv2.VideoWriter_fourcc('X', 'V', 'I', 'D'), fps, size)

while 1:
    # 读取视频图像,ret为bool值表示是否读取到图片,frame为读取到的图片帧
    ret, frame = cap.read()
    # 图像水平翻转,翻转成镜像的,1水平,0垂直,-1水平垂直
    frame = cv2.flip(frame, 1)
    # 显示视频
    cv2.imshow("capture", frame)
    # 写入视频
    video_writer.write(frame)
    # 按Q键退出
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()  #释放
cv2.destroyAllWindows()

path = 'E:/.../My_video1.avi' #获取视频文件
videoCapture = cv2.VideoCapture(path)  #读取视频

#获取视频码率和尺寸
fps = videoCapture.get(cv2.CAP_PROP_FPS)
size = (int(videoCapture.get(cv2.CAP_PROP_FRAME_WIDTH)), int(videoCapture.get(cv2.CAP_PROP_FRAME_HEIGHT)))

fnums = videoCapture.get(cv2.CAP_PROP_FRAME_COUNT)

# 写入视频帧
video_writer = cv2.VideoWriter('E:/.../My_video2.avi', cv2.VideoWriter_fourcc('X', 'V', 'I', 'D'), fps, size)

# 读取视频帧
success, frame = videoCapture.read()
a = time.time()
while success:
    cv2.imshow('Windows', frame)  # 显示
    cv2.waitKey(int(600/fps))    #延迟
    video_writer.write(frame)
    success, frame = videoCapture.read()  #获取下一帧
b = time.time()
print(b-a)
videoCapture.release()
cv2.destroyAllWindows() 

11、dst = cv2.add(scr1, scr2, dst, mask, dtype)

(cv2.subtract()、cv2.divide()、cv2.mutiply()参数相同)
scr1, scr2:进行加法运算的图像,或一张图像与一个 numpy array 标量
dst:输出的图像,可选项,默认值为 None
mask:掩模图像,8位灰度格式;掩模图像数值为 0 的像素,输出图像对应像素的各通道值也为 0。可选项,默认值为 None
dtype:图像数组的深度,即每个像素值的位数,可选项
返回值:dst,运算结果图像,ndarray 多维数组

函数 cv2.add() 对两张相同大小和类型的图像进行加法运算,或对一张图像与一个标量进行加法运算。
两张图像相加时,将两张图像相同位置像素的各通道值或灰度值分别相加,可以理解为一种图像叠加方式;对一张图像与一个标量相加时,则将图像所有像素的各通道值分别与标量的各通道值相加。
注意:
OpenCV 加法和 numpy 加法之间有区别:cv2.add() 是饱和运算(相加后如大于 255 则结果为 255),而 Numpy 加法是模运算,Numpy减法结果加上256再取模;cv2.subtract()减法运算最低为0;cv2.divide()点除,像素点相除,四舍五入;cv2.mutiply()点乘,各像素点相乘,最高255。
使用 cv2.add() 函数对两张图片相加时,图片的大小和类型(通道数)必须相同。
使用 cv2.add() 函数对一张图像与一个标量相加,标量是指一个 1x3 的 numpy 数组,相加后图像整体发白。

12、dst = cv2.addWeighted(img1, a , img2, b , c)

实现图像的加权和(混合、融合),给两张图片设置透明度融合到一起。
可以将上式理解为“结果图像rst=图像img1×系数a+图像img2×系数b+亮度调节量c”。
注意:img1和img2尺寸相同,文件类型必须相同,a,b,c之间没有必然关系,不存在a+b+c要等与1,c一定要写,可以写0,即不调节亮度。

import numpy as np
import cv2

#定义两个随机的4×4矩阵,范围在[0,255]之间
img1 = np.random.randint(0, 256, size=[4, 4], dtype=np.uint8)
img2 = np.random.randint(0, 256, size=[4, 4], dtype=np.uint8)
print("img1=\n", img1)
print("img2=\n", img2)
img_add = cv2.add(img1, img2)   #cv2加法,最高不过255
img_sub = cv2.subtract(img1, img2)  ##cv2减法,最低不过0
img_divide = cv2.divide(img1, img2) #使用divide函数进行点除,各位置相除,四舍五入保留整数
img_result = cv2.multiply(img1, img2)  #使用multiply函数进行点乘,最高不过255
print("img1+img2=\n", img1+img2)  #数学加法,对256取模
print("img1-img2=\n", img1-img2)  #数学减法,加上256再取模
print("cv2.add(img1,img2)\n", img_add)
print("cv2.subtract(img1,img2)\n", img_sub)

#读取两幅图像
img1 = cv2.imread('E:/.../grassland.png')
img2 = cv2.imread('E:/.../sun1.png')

#使用cv2.add()函数实现图像的加法运算
img3 = cv2.add(img1, img2)

#使用数学方法直接对对应像素相加
img4 = img1+img2

cv2.imshow('Img1', img1)
cv2.imshow('Img2', img2)
cv2.imshow('add(Img1,Img2)', img3)
cv2.imshow('Img1+Img2', img4)

ret = cv2.addWeighted(img1, 0.7, img2, 0.5, 0)
cv2.imshow("cv2.addWeight", ret)

#使用cv2.subtract()函数实现图像的减法运算
img3 = cv2.subtract(img1, img2)
#使用数学计算方法对图像相减
img4 = img1-img2
cv2.imshow('cv2.subtract(Img1,Img2)', img3)
cv2.imshow('Img1-Img2', img4)

img = cv2.imread('E:/.../lena.jpg') #读取图像
 #创建长宽为200的图片,三通道(BGR),像素大小为8位无符号整数
data = 2*np.ones([200, 200, 3], np.uint8)

#使用multiply()函数进行矩阵点乘运算
result1 = cv2.multiply(img, data)

#使用divide()函数进行矩阵点除乘运算
result2 = cv2.divide(img, data)

cv2.imshow('r1', result1)
cv2.imshow('r2', result2)

cv2.waitKey()
cv2.destroyAllWindows()

13、dst = cv2.bitwise_and(img1, img2, dst, mask)

(cv2.bitwise_or()、cv2.bitwise_not、cv2.bitwise_xor()   )
与、或、非、异或运算,各像素点相与(或,非,异或),可以构造掩模图像,然后对原图像操作(删、取...)。
img1、img2:图像或者标量
dst:可选输出变量,如果需要使用非None则要先定义,且其大小与输入变量相同
mask:图像掩膜,可选参数,为8位单通道的灰度图像,用于指定要更改的输出图像数组的元素,即输出图像像素只有mask对应位置元素不为0的部分才输出,否则该位置像素的所有通道分量都设置为0

import cv2
import numpy as np

img1=cv2.imread("E:/.../lena.jpg")       #读取图像
cv2.imshow("img1", img1)
img2 = np.zeros(img1.shape, dtype=np.uint8)  #构造掩模图像
img2[50:150,50:150] = 255
cv2.imshow("img2", img2)

result_or = cv2.bitwise_or(img1, img2)          #进行按位或,删掉掩膜内的图像
result_and = cv2.bitwise_and(img1, img2)      #进行按位与,取出掩膜内的图像
result_not = cv2.bitwise_not(img1)    #进行按位非操作对图像取反,每个数的每一位取反
result_xor = cv2.bitwise_xor(img1, img2)      #进行按位异或操作
cv2.imshow("or", result_or)
cv2.imshow("and", result_and)
cv2.imshow("not", result_not)
cv2.imshow("xor", result_xor)
cv2.waitKey()
cv2.destroyAllWindows()

14、dst = cv2.cvtColor(img, flags)

颜色空间转换函数,img:需要转换的图片;flags:转换的格式,cv2.COLOR_BGR2RGB:将BGR转化成RGB;cv2.COLOR_BGR2GRAY:将BGR转化成灰度图片;cv2.COLOR_BGR2HSV:转化为HSV空间;cv2.COLOR_BGR2YCrCb:变换为YCrCb空间;cv2.COLOR_BGR2HSL:变化为HSL空间;cv2.COLOR_BGR2XYZ:变化为XYZ空间;cv2.COLOR_BGR2LAB:转化为LAB空间;cv2.COLOR_BGR2YUV:转化为YUV空间。
 

import cv2 
import matplotlib.pyplot as plt

#载入原图
img = cv2.imread('E:/.../lena.jpg')
#利用plot函数画出图像并放置在一个窗口中显示
plt.subplot(3, 3, 1)
plt.imshow(img)
plt.axis('off')
plt.title('BGR')

#BGR变换RGB
img_RGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.subplot(3, 3, 2)
plt.imshow(img_RGB)
plt.axis('off')
plt.title('RGB')

#原图变换灰度图
img_GRAY = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
plt.subplot(3, 3, 3)
plt.imshow(img_GRAY)
plt.axis('off')
plt.title('GRAY')

#变换HSV空间
img_HSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
plt.subplot(3, 3, 4)
plt.imshow(img_HSV)
plt.axis('off')
plt.title('HSV')

#变换YCrCb空间
img_YcrCb = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)
plt.subplot(3, 3, 5)
plt.imshow(img_YcrCb)
plt.axis('off')
plt.title('YcrCb')

#变换HLS空间
img_HLS = cv2.cvtColor(img, cv2.COLOR_BGR2HLS)
plt.subplot(3, 3, 6)
plt.imshow(img_HLS)
plt.axis('off')
plt.title('HLS')

#变换XYZ空间
img_XYZ = cv2.cvtColor(img, cv2.COLOR_BGR2XYZ)
plt.subplot(3, 3, 7)
plt.imshow(img_XYZ)
plt.axis('off')
plt.title('XYZ')

#变换LAB空间
img_LAB = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
plt.subplot(3, 3, 8)
plt.imshow(img_LAB)
plt.axis('off')
plt.title('LAB')

#变换YUV空间
img_YUV = cv2.cvtColor(img, cv2.COLOR_BGR2YUV)
plt.subplot(3, 3, 9)
plt.imshow(img_YUV)
plt.axis('off')
plt.title('YUV')
plt.show()

15、ret, dst = cv2.threshold(src, thresh, maxval, type)

阈值函数:根据设定的值处理图像的灰度值。
返回值ret是布尔值,dst为处理后的图像。
src是灰度图像
thresh是起始阈值
maxval是最大值
type是定义如何处理数据与阈值的关系:
另外的取值:cv2.THRESH_OTSU、cv2.THRESH_TRIANGLE、cv2.THRESH_MASK

import cv2
import numpy as np

#Load two images
img1 = cv2.imread('E:/...s/grassland.png')
img2 = cv2.imread('E:/.../opencv-logo-white.png')

#I want to put logo on top-left corner, So I create a ROI
rows1, cols1, channels1 = img1.shape
rows, cols, channels = img2.shape
roi = img1[0:rows, (cols1-cols):cols1]  #右上角

#Now create a mask of logo and create its invers mask also
#cv2.COLOR_BGR2GRAY:BGR转化为GRAY灰度图片;COLOR_BGR2RGB:BGR转化为RGB彩色图片
img2gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)   #彩色图片灰度化
#cv2.threshold(图片,阈值,max值,type),type=cv2.THRESH_BINARY表示灰度图片中值大于(阈值)的都置为max,小于(阈值)的置为0,这里把图片黑白化
ret, mask = cv2.threshold(img2gray, 240, 255, cv2.THRESH_BINARY)   #灰度图片黑白化
# mask 背景依然是白色,彩色logo是黑色
mask_inv = cv2.bitwise_not(mask)  #把logo置为白色为255,背景置为黑色为0
#Now black-out the area of logo in ROI
img1_bg = cv2.bitwise_and(roi, roi, mask=mask)  #输出图像像素只有mask位置不为零才输出,其余置为0,即把roi对应mask白色的地方输出,对应黑色的地方置为0,此时把黑色logo印在roi上

#背景变成白,2背景部分进行操作,logo部分变黑,为0,这部分的值变为0
#Put logo in ROI and modify the main image
#Take only region of logo from logo image.
img2_fg = cv2.bitwise_and(img2, img2, mask=mask_inv)  #把img2对应mask_inv上白色的地方输出,即把彩色logo印下来

dst = cv2.add(img1_bg, img2_fg)   #把两个图片实现图像加法合成到一起
img1[0:rows, (cols1-cols):cols1] = dst  #把合成好的图片替换到原图像上

cv2.imshow('Result', img1)
cv2.waitKey(0)
cv2.destroyAllWindows()

16、dst = cv2.warpAffine(src, M, dsize, flags, borderMode, borderValue)

src - 输入图像。
M - 变换矩阵。
dsize - 输出图像的大小。
flags - 插值方法的组合(int 类型!)
borderMode - 边界像素模式(int 类型!)
borderValue - 边界填充值; 默认情况下,它为0(黑色)。
M作为仿射变换矩阵,一般反映平移或旋转的关系,为2×3的变换矩阵。
图像像素坐标变换规则如下图所示:

仿射变换矩阵可以实现简单的平移、旋转和扭曲。
flages表示插值方式,默认为 flags=cv2.INTER_LINEAR,表示线性插值,此外还有:cv2.INTER_NEAREST(最近邻插值);cv2.INTER_AREA (区域插值);cv2.INTER_CUBIC(三次样条插值);cv2.INTER_LANCZOS4(Lanczos插值)。

M = np.float32([[1, 0, 50], [0, 1, 25]])

dst = cv2.warpAffine(img, M, (2*cols, 2*rows))

dst1 = cv2.warpAffine(img, M, (2*cols, 2*rows),borderValue=(255, 255, 255))

17、M = cv2.getAffineTransform(pts1,pts2)

仿射变换,指一个向量空间进行线性变换+平移变成另外一个向量空间,它需要一个变换矩阵,而由于仿射变换较为复杂,一般很难找出这个矩阵,于是opencv提供了cv2.getAffineTransform()
cv2.getAffineTransForm()通过找原图像中三个点的坐标和变换图像的相应三个点坐标,创建一个2X3的矩阵(返回值)。最后这个矩阵会被传给函数cv2.warpAffine()


plt.subplot(121):把图像窗口分为一行二列,当前位置为1。
plt.imshow(img):处理图像,不显示;https://blog.csdn.net/youcans/article/details/121169102
plt.title("str"):设置图像标题。
plt.show():显示窗口

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

img = cv2.imread('E:/.../a.jpg')
rows, cols, ch = img.shape

pts1 = np.float32([[50, 50], [200, 50], [50, 200]])
pts2 = np.float32([[10, 100], [200, 50], [100, 250]])

M = cv2.getAffineTransform(pts1, pts2)

dst = cv2.warpAffine(img, M, (cols, rows))

plt.subplot(121), plt.imshow(img), plt.title('Input')
plt.subplot(122), plt.imshow(dst), plt.title('Output')
plt.show()

很明显图像向左倾斜

18、M = getRotationMatrix2D(center, -45, 1)

获得仿射变换矩阵,center为旋转中心(元组),默认为(0,0),-45表示顺时针旋转45度,1表示等比缩放得比例。
原理:1、先将旋转中心平移到远点;2、旋转;3、平移回原来的位置。
大佬推导:https://blog.csdn.net/ooooocj/article/details/112491183
直接用函数:

M = cv2.getRotationMatrix2D((cols/2, rows/2), 45, 1)

dst = cv2.warpAffine(img, M, (cols, rows), borderValue=(255, 255, 255))

 推导法:

import cv2
import numpy as np

img = cv2.imread("E:/.../lena.jpg", cv2.IMREAD_COLOR)
h, w, c = img.shape
M = np.zeros((2, 3), dtype=np.float32)
alpha = np.cos(np.pi / 4.0)
beta = np.sin(np.pi / 4.0)

# 初始旋转矩阵
M[0, 0] = alpha
M[1, 1] = alpha
M[0, 1] = beta
M[1, 0] = -beta
cx = w / 2
cy = h / 2
tx = (1-alpha)*cx - beta*cy
ty = beta*cx + (1-alpha)*cy
M[0, 2] = tx
M[1, 2] = ty

# 更改为全尺寸
bound_w = int(h * np.abs(beta) + w * np.abs(alpha))
bound_h = int(h * np.abs(alpha) + w * np.abs(beta))

# 添加中心位置迁移
M[0, 2] += bound_w / 2 - cx
M[1, 2] += bound_h / 2 - cy
dst = cv2.warpAffine(img, M, (bound_w, bound_h))
cv2.imshow('Origin image', img)
cv2.imshow("rotate without cropping", dst)

cv2.waitKey(0)
cv2.destroyAllWindows()

19、dst = cv2.resize(img, (dsize), double fx, double fy, interpolation)

对图片进行缩放
scr:原始图像
dsize:输出图像的尺寸(元组方式)
fx:沿水平轴缩放的比例因子,fy:沿垂直轴缩放的比例因子
interpolation:插值方法,有以下5种

注意:有dsize则不需fx和fy,但必须有dsize,可置为None。

# 方法一:通过设置缩放比例,来对图像进行放大或缩小
dst1 = cv2.resize(img, None, fx=1.2, fy=1.2, interpolation=cv2.INTER_CUBIC)

# 方法二:直接设置图像的大小,不需要缩放因子
height, width = 160, 160
dst2 = cv2.resize(img, (height, width), interpolation=cv2.INTER_LANCZOS4)

 

20、cv2.setMouseCallback(winname, onMouse, userdata=0)

(鼠标回调函数)
winname: 自定义的窗口名
onMouse:鼠标事件的回调函数(在发生鼠标事件时执行)
userdata:传递给回调函数的可选参数(param)

onMouse函数(自定义函数):
onMouse 是鼠标事件回调函数的默认原型,可自定义其函数名和函数内容,参数一般默认为
        onMouse(event, x, y, flags, param)
        event:cv2_EVENT_* (MouseEventTypes)类型的变量,为当前发生的鼠标事件类型
        x和y: 发生鼠标事件时鼠标在图像位置的x,y坐标
        flags:  cv2_EVENT_FLAG_* (MouseEventFlags)类型的变量
        param:自定义的传递给 setMouseCallback 函数调用的参数(默认为0)

MouseEventTypes:
        EVENT_MOUSEMOVE (0)            #滑动
        EVENT_LBUTTONDOWN (1)        #左键点击
        EVENT_RBUTTONDOWN (2)       #右键点击
        EVENT_MBUTTONDOWN (3)      #中键点击
        EVENT_LBUTTONUP (4)              #左键放开
        EVENT_RBUTTONUP (5)             #右键放开
        EVENT_MBUTTONUP (6)             #中键放开
        EVENT_LBUTTONDBLCLK (7)     #左键双击
        EVENT_RBUTTONDBLCLK (8)    #右键双击
        EVENT_MBUTTONDBLCLK (9)   #中键双击
MouseEventFlags:
        EVENT_FLAG_LBUTTON (1)       #左键拖曳
        EVENT_FLAG_RBUTTON (2)      #右键拖曳
        EVENT_FLAG_MBUTTON (4)      #中键拖曳
        EVENT_FLAG_CTRLKEY (8 (8~15))       #按 Ctrl 不放
        EVENT_FLAG_SHIFTKEY (16 (16~31))      #按 Shift 不放
        EVENT_FLAG_ALTKEY (32 (32~39))          #按 Alt 不放

21、cv2.circle(img, center, radius, color(B,G,R), thickness, linetype, shift)

(画圆函数)
img:输入的图片
center:圆心位置
radius:圆的半径
color:圆的颜色,如(255,0,0)表示蓝色
thickness:圆形轮廓的粗细(如果为正)。负数表示绘制实心圆。
lineType: 圆边界的类型。
shift:中心坐标和半径值中的小数位数。

22、cv2.line(img, pt1, pt2, color, thickness)

(画直线函数)
img:要划的线所在的图像;
pt1:直线起点
pt2:直线终点(坐标分别为宽、高,opencv中图像的坐标原点在左上角)
color:直线的颜色,BGR模式,如(255,0,0)表示蓝色
thickness:线条粗细,默认是1.如果为负数,那么整个图形就会被填充。

23、cv2.polylines(img, pts, isclosed, color, thickness, linetype, shift)

(绘制多边形曲线或多线段)
img:多边形的图像
pts:包含多边形上点的数组
isClosed:标志,决定所绘制的多边形是否闭合。若为 True ,则画若干个闭合多边形;若为 False ,则画一条连接所有点的折线
color:多边形颜色,(B,G,R)颜色
thickness:多边形线的粗细
lineType:多边形线的类型
shift:坐标精确到小数点后第几位

24、cv2.fillPoly(img, pts, color, linetype, shift)

(绘制一个或多个填充的多边形区域函数)
img:多边形的图像
pts:包含多边形上点的数组
color:多边形颜色,(B,G,R)颜色
lineType:多边形线的类型
shift:坐标精确到小数点后第几位

import cv2
import numpy as np


def On_Mouse(event, x, y, flags, param):
    global img, point1, point2, count, pointsMax
    global lsPointsChoose, tpPointsChoose  # 存入选择的点
    global pointsCount  # 对鼠标按下的点计数
    global img2, ROI_bymouse_flag
    img2 = img.copy()  # 保证每次都重新在原图画

    if event == cv2.EVENT_LBUTTONDOWN:  # 左键点击
        pointsCount = pointsCount + 1
        print('pointsCount:', pointsCount)
        point1 = (x, y)
        print(x, y)
        cv2.circle(img2, point1, 5, (0, 255, 0), 2)  # 画出点击的点

        # 将选取的点保存到list列表里
        lsPointsChoose.append([x, y])  # 用于转化为darry提取多边形ROI
        tpPointsChoose.append((x, y))  # 用于画点
        # 将鼠标选的点用直线连起来
        print(len(tpPointsChoose))
        for i in range(len(tpPointsChoose) - 1):
            print('i', i)
            cv2.line(img2, tpPointsChoose[i], tpPointsChoose[i + 1], (0, 0, 255), 2)

        cv2.imshow('src', img2)

    # ----右键点击,清除轨迹-------------
    if event == cv2.EVENT_RBUTTONDOWN:
        print("right-mouse")
        pointsCount = 0
        tpPointsChoose = []
        lsPointsChoose = []
        print(len(tpPointsChoose))
        for i in range(len(tpPointsChoose) - 1):
            print('i', i)
            cv2.line(img2, tpPointsChoose[i], tpPointsChoose[i + 1], (0, 0, 255), 2)
        cv2.imshow('src', img2)

    # ----双击鼠标,结束选取,绘制感兴趣区域------
    if event == cv2.EVENT_LBUTTONDBLCLK:
        ROI_byMouse()
        ROI_bymouse_flag = 1
        lsPointsChoose = []

def ROI_byMouse():
    global src, ROI, ROI_flag, mask2
    mask = np.zeros(img.shape, np.uint8)
    pts = np.array([lsPointsChoose], np.int32)  # pts是多边形的顶点列表
    pts = pts.reshape((-1, 1, 2)) #-1表示这一维的长度是根据后面的维度计算出来的,只画出四边形的点   相当于把一个点(第二个参数)作为一个四边形画
    # OpenCV中需要先将多边形的顶点坐标变成顶点数×1×2维的矩阵,再来绘制
    mask = cv2.polylines(mask, [pts], True, (255, 255, 255))  # 画多边形
    mask2 = cv2.fillPoly(mask, [pts], (255, 255, 255))  # 填充多边形
    cv2.imshow('mask', mask2)
    # 掩模图像与原图像进行“位与”操作
    ROI = cv2.bitwise_and(mask2, img)
    cv2.imshow('ROI', ROI)


if __name__ == '__main__':
    # 选择点设置
    lsPointsChoose = []
    tpPointsChoose = []
    pointsCount = 0
    count = 0
    pointsMax = 6

    img = cv2.imread('E:/.../lena.jpg')
    ROI = img.copy()
    cv2.namedWindow('src')
    cv2.setMouseCallback('src', On_Mouse, 5)
    cv2.imshow('src', img)
    cv2.waitKey(0)

cv2.destroyAllWindows()

 

25、M = cv2.getPerspectiveTransform(pts1, pts2)

(得到透析变换矩阵)
pts1:原图像中待测矩形的四点坐标
pts2:目标图像中矩形的四点坐标
透析变换矩阵由来:https://blog.csdn.net/qq_52309640/article/details/120868590

26、dst = cv2.warpPerspective(src, M, dsize, flags, borderMode, borderValue)

(透析变换函数)
src:输入图像
M:变换矩阵
dsize:目标图像shape
flags:插值方式,interpolation方法INTER_LINEAR或INTER_NEAREST
borderMode:边界补偿方式,BORDER_CONSTANTorBORDER_REPLICATE
borderValue:边界补偿大小,常值,默认为0

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

img = cv2.imread('E:/.../lena.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
rows, cols, ch = img.shape
# 选择合适数据点
pts1 = np.float32([[50, 60], [560, 50], [30, 580], [590, 590]])
pts2 = np.float32([[0, 0], [600, 0], [0, 600], [600, 600]])
# 创建M透视变换矩阵
M = cv2.getPerspectiveTransform(pts1, pts2)
print("M=", M)
# 透视变换
dst = cv2.warpPerspective(img, M, (640, 400))
# 显示输入输出图像
plt.subplot(121), plt.imshow(img), plt.title('Input')
plt.subplot(122), plt.imshow(dst), plt.title('Output')
plt.show()

27、mag, ang = cv2.cartToPolar(x, y, anangleInDegrees)

(直角坐标转极坐标)
(mag, ang = cv2.ploarToCart(x, y, anangleInDegrees):极坐标转直角坐标)

import math
import cv2
import numpy as np

x, y = 3, 5
print('直角坐标 x=', x, '\n直角坐标 y=', y)
# math库函数计算
center = [0, 0]  #中心点
r = math.sqrt(math.pow(x-center[0], 2)+math.pow(y-center[1], 2))
theta = math.atan2(y-center[1], x-center[0])/math.pi*180  #转换为角度
print('math库函数 r=', r)
print('math库函数 theta=', theta)

# opencv也提供了极坐标变换的函数
x1 = np.array(x, np.float32)
y1 = np.array(y, np.float32)
# 变换中心为原点,若想为(2,3)需x1-2,y1-3
r1, theta1 = cv2.cartToPolar(x1, y1, angleInDegrees=True)
#当angleInDegrees是True时,返回值为angle角度,否则为弧度
print('OpenCV库函数 r=', r1)
print('OpenCV库函数 thetar=', theta1)

#反变换,即将极坐标变为笛卡尔坐标。(r,theta)变换为(x,y)
x1, y1 = cv2.polarToCart(r1, theta1, angleInDegrees=True)
print('极坐标变为直角坐标 x=', np.round(x1[0]))
print('极坐标变为直角坐标 y=', np.round(y1[0]))

 


28、cv2.logPolar(scr, center, M, flags)

(笛卡尔坐标系转对数极坐标系,坐标变换)
(cv2.linearPolar(scr, center, M, flags):笛卡尔坐标系转极坐标系)



cv.WARP_FILL_OUTLIERS:填充所有输出图像的像素,如果部分像素落在输入图像的边界外,那么他们的值设定为fillval
cv2.INTER_LINEAR:最近邻插值,在插值的时候,会把最近元素的值当作新像素的值,这样插值之后的所有像素值是原图的子集
math.hypot(a1, a2...an):返回所有参数的平方和的平方根;math.log:以e为底 

29、cv2.transpose(img)

(图像转置函数)
img:需要转置的图像
返回转置完成的图像

import cv2
import math

img = cv2.imread('E:/.../clock.jpg')
h, w = img.shape[0:2]
maxRadius = math.hypot(w/2, h/2)   #返回所有参数的平方和的平方根
m = w / math.log(maxRadius) #以e为底数
log_polar = cv2.logPolar(img, (w/2, h/2), m, cv2.WARP_FILL_OUTLIERS + cv2.INTER_LINEAR)
linear_polar = cv2.linearPolar(img, (w/2, h/2), m, cv2.WARP_FILL_OUTLIERS + cv2.INTER_LINEAR)
log_dst = cv2.transpose(log_polar)  #图像转置
log_dst = cv2.flip(log_dst, 0)       #图像垂直镜像
lin_dst = cv2.transpose(linear_polar)  #图像转置
lin_dst = cv2.flip(lin_dst, 0)          #图像垂直镜像

cv2.imshow("Original", img)
cv2.imshow("Log_polar", log_dst)
cv2.imshow("Linear_polar", lin_dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

30、dst = cv2.rotate(img, rotatcode)

(图像旋转,直角旋转:90,180,270),矩阵转置实现,速度快。
img:变换操作的输入图像
rotatecode:枚举,指定旋转角度。
        cv2.ROTATE_90_CLOCKWISE:顺时针旋转 90 度
        cv2.ROTATE_180: 旋转 180 度
        cv2.ROTATE_90_COUNTERCLOCKWISE:逆时针旋转 90 度
dst:返回值,变换操作的输出图像,ndarray 多维数组

31、dst = cv2.warpPolar(img, dsize, center, maxRadius, flags)

(图像或矩阵从直角坐标系(笛卡尔坐标系)转换到极坐标,图像的极坐标变换函数)
img:源图像
dst:输出图像,它和源图像具有相同的数据类型和通道数,尺寸不一定相同
dsize: 目标图像尺寸
center:极坐标变换时,原点坐标(变换中心)
maxRadius:要变换的圆形的半径,也是反向变换的圆的半径
flags:插值方法+映射模式(用 "+" 或 "|" 连接)
        常见的插值方法:
        
        映射模式:
        WARP_POLAR_LINEAR:线性极坐标映射
        WARP_POLAR_LOG:半对数极坐标映射
        WARP_INVERSE_MAP:反向映射

import argparse
import copy
import cv2

parser = argparse.ArgumentParser()
parser.add_argument("--width", help='capture width', type=int, default=960)
parser.add_argument("--height", help='capture height', type=int, default=540)
args = parser.parse_args()

cap_width = args.width
cap_height = args.height
print(cap_height, cap_width)
cap = cv2.VideoCapture('E:/.../clock.mp4')
cap.set(cv2.CAP_PROP_FRAME_WIDTH, cap_width)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, cap_height)

while True:
    ret, frame = cap.read()
    if not ret:
       print('cap.read() error')
       break
    rotate_frame = cv2.rotate(frame, cv2.ROTATE_90_CLOCKWISE)
    lin_polar_image = cv2.warpPolar(rotate_frame, (150, 500), (270, 480), 220, cv2.INTER_CUBIC + cv2.WARP_FILL_OUTLIERS + cv2.WARP_POLAR_LINEAR)
    lin_polar_crop_image = copy.deepcopy(lin_polar_image[0:500, 15:135])
    lin_polar_crop_image = lin_polar_crop_image.transpose(1, 0, 2)[::-1]
    # lin_polar_image = cv2.rotate(lin_polar_image, cv2.ROTATE_90_COUNTERCLOCKWISE)
    cv2.imshow('ORIGINAL', frame)
    cv2.imshow('POLAR', lin_polar_crop_image)
    key = cv2.waitKey(50)
    if key == 27:  #按下Esc键,停止运行
        break

cap.release()
cv2.destroyAllWindows()  

图像增强

主要目的是为了改善图像的质量以及增强感兴趣部分,改善图像的视觉效果。如光线较暗的图像需要增强图像的亮度,通过检测高速路上的白线实现汽车自动驾驶等。

直方图均衡化

直方图:一幅灰度图像,反映了不同灰度级(像素值)出现的统计情况。

       直方图均衡化:通过改变图像的直方图来改变图像中各像素的灰度,主要用于增强动态范围偏小的图像的对比度。原始图像由于其灰度分布可能集中在较窄的区间,造成图像不够清晰。例如,过曝光图像的灰度级集中在高亮度范围内,而曝光不足将使图像灰度级集中在低亮度范围内。采用直方图均衡化,可以把原始图像的直方图变换为均匀分布(均衡)的形式,这样就增加了像素之间灰度值差别的动态范围,从而达到增强图像整体对比度的效果。
换言之,直方图均衡化的基本原理是:对在图像中像素个数多的灰度值(即对画面起主要作用的灰度值)进行展宽,而对像素个数少的灰度值(即对画面不起主要作用的灰度值)进行合并,从而增大对比度,使图像清晰,达到增强的目的。
*局部直方图均衡化(子块重叠,子块不重叠,子块部分重叠)
均衡化步骤:

 



32、plt.hist(...)

(matplotlib绘制直方图的函数)
https://blog.csdn.net/weixin_46707493/article/details/119832774
img.ravel()函数将图像数组img拉成一维数组

33、cv2.calcHist( [img],[flag],mask,[histSize],[ranges] )

(opencv统计直方图函数)
img:原图像,传入时用中括号[]括起来
flag:统计的类型,如果是灰度图只用[0]表示,如果是彩色图像则可以是[0],[1],[2]分别表示B,G,R。
mask:掩模图象,统计整个图像则置为None,想统计某一份的直方图可以用一个掩模图象并使用它。
histSize:直方图中柱子的数目。
ranges:像素值的范围,[0,255]。

import cv2 
from matplotlib import pyplot as plt

img = cv2.imread('E:/.../lena.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])
plt.show()

34、cv2.equalizeHist(img)

(直方图均衡化函数)
img:传入的图像

img = cv2.imread('E:/.../pout.tif')
img_Gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
equ = cv2.equalizeHist(img_Gray)

plt.figure("原始灰度直方图")
plt.title('Origin')
plt.hist(img_Gray.ravel(), 256)

plt.figure("均衡化直方图")
plt.title('Equalization')
plt.hist(equ.ravel(), 256)
plt.show()

cv2.imshow("Gray", img_Gray)
cv2.imshow("EqualizeHist", equ)
cv2.waitKey(0)
cv2.destroyAllWindows()



//直方图均衡化自定义
import cv2
import numpy as np
import matplotlib.pyplot as plt

def Origin_histogram(img):
    # 统计图像各灰度级的值和像素个数
    histogram = {}
    for i in range(img.shape[0]):
        for j in range(img.shape[1]):
            k = img[i][j]
            if k in histogram:
                histogram[k] += 1
            else:
                histogram[k] = 1

    # sorted_histogram = {}  # 建立排好序的映射表
    # sorted_list = sorted(histogram)  # 根据灰度值进行从低至高的排序
    # for j in range(len(sorted_list)):
    #     sorted_histogram[sorted_list[j]] = histogram[sorted_list[j]]
    sorted_histogram = sorted(histogram.items())
    sorted_histogram = dict(sorted_histogram)
    return sorted_histogram

def equalization_histogram(histogram, img):   #直方图均衡化
    pr = {}  # 建立概率分布映射表
    pr1 = {}
    for i in histogram.keys():
        pr[i] = histogram[i] / (img.shape[0] * img.shape[1])
    tmp = 0
    for m in pr.keys():
        tmp += pr[m]
        pr[m] = max(histogram) * tmp
        pr1[m] = 255 * tmp
    new_img = np.zeros(shape=(img.shape[0], img.shape[1]), dtype=np.uint8)
    global new_img1
    new_img1 = np.zeros(shape=(img.shape[0], img.shape[1]), dtype=np.uint8)
    flog = 0
    for k in range(img.shape[0]):
        for l in range(img.shape[1]):
            new_img[k][l] = pr[img[k][l]]
            new_img1[k][l] = pr1[img[k][l]]
    return new_img

def GrayHist(img):     # 计算灰度直方图
    height, width = img.shape[:2]
    grayHist = np.zeros([256], np.uint64)
    for i in range(height):
        for j in range(width):
            grayHist[img[i][j]] += 1
    return grayHist

if __name__ == '__main__':
    img = cv2.imread('E:/.../pout.tif', cv2.IMREAD_GRAYSCALE)
    # 计算原图灰度直方图
    origin_histogram = Origin_histogram(img)
    # 直方图均衡化
    new_img = equalization_histogram(origin_histogram, img)
    origin_grayHist = GrayHist(img)
    equaliza_grayHist = GrayHist(new_img)
    equaliza_grayHist1 = GrayHist(new_img1)
# 绘制灰度直方图
    x = np.arange(256)
    plt.figure(num=1) 
    plt.plot(x, origin_grayHist, 'r', linewidth=1, c='blue')
    plt.title("Origin"), plt.ylabel("number of pixels")
    
    plt.figure(num=2)
    plt.plot(x, equaliza_grayHist, 'r', linewidth=1, c='blue')
    plt.title("Equalization"), plt.ylabel("number of pixels")

    plt.figure(num=3)
    plt.plot(x, equaliza_grayHist, 'r', linewidth=1, c='blue')
    plt.title("Equalization255"), plt.ylabel("number of pixels")
    plt.show()

cv2.imshow("Origin", img)
cv2.imshow("Equalization", new_img)
cv2.imshow("e1", new_img1)
cv2.waitKey(0)
cv2.destroyAllWindows()

35、cv2.createCLAHE(clipLimit,tileGridSize)

(自适应直方图均衡化,局部直方图均衡化函数)
clipLimit:颜色对比度限制阈值(亮暗),默认为8
tileGridSize:局部直方图均衡化领域大小(局部均衡化的矩阵大小),默认为(8,8)
避免因为全局直方图均衡化而损失细节,自适应直方图均衡化能有效的保持细节的损失。
两位博主的解释:
https://blog.csdn.net/juzicode00/article/details/121663922
https://blog.csdn.net/youcans/article/details/121691770

直方图规定化:

规定化:通过建立一个灰度映射函数,将原灰度直方图改成所希望的特点形状的直方图,满足特定的增强效果,即有针对性的增强某个灰度范围内的图像。
步骤:

 

 


没有看懂可以看:https://blog.csdn.net/qq_46126258/article/details/120845156

36、cv2.LUT(img,map)

(根据map的映射关系,对img图像处理得到映射后的图像,用于直方图规定化)
img:输入矩阵,类型为np.uint8
map:映射关系(查找表),如果输入img是多通道的,例如是BGR三通道的图像,而查表是单通道的,则此时B、G、R三个通道使用的是同一个查找表。
处理规则:map(img[I])->dst[I]

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

#  定义计算直方图累积概率函数
def histCalculate(src):
    row, col = np.shape(src)
    hist = np.zeros(256, dtype=np.float32)
    cumhist = np.zeros(256, dtype=np.float32)
    cumProbhist = np.zeros(256, dtype=np.float32)  
# 累积概率直方图,即Y轴归一化
    for i in range(row):
        for j in range(col):
            hist[src[i][j]] += 1

    cumhist[0] = hist[0]
    for i in range(1, 256):
        cumhist[i] = cumhist[i-1] + hist[i]
    cumProbhist = cumhist/(row*col) 
    return cumProbhist

# 定义实现直方图规定化函数
def histSpecification(specImg, refeImg):  
    spechist = histCalculate(specImg)  # 计算待匹配直方图
    refehist = histCalculate(refeImg)   # 计算参考直方图
    corspdValue = np.zeros(256, dtype=np.uint8)  # correspond value
    # 直方图规定化(单映射)
    for i in range(256):
        diff = np.abs(spechist[i] - refehist[i])
        matchValue = i
        for j in range(256):
            if np.abs(spechist[i] - refehist[j]) < diff:
                diff = np.abs(spechist[i] - refehist[j])
                matchValue = j
        corspdValue[i] = matchValue
    #根据映射关系修改灰度值
    global outputimg1
    outputimg1 = np.zeros((img.shape[0], img.shape[1]), dtype=np.uint8)
    for i in range(img.shape[0]):
        for j in range(img.shape[1]):
            outputimg1[i][j] = corspdValue[img[i][j]]
    #通过函数和建立的映射关系修改灰度值
    outputImg = cv2.LUT(specImg, corspdValue)
    return outputImg


# 读入原图像
img = cv2.imread('E:/.../office_2.jpg', 0)

# 读入参考图像
img1 = cv2.imread('E:/.../lena.jpg', 0)
cv2.imshow('Input image', img)
cv2.imshow('Reference image', img1)
imgOutput = histSpecification(img, img1)
flog = 0
for i in range(img.shape[0]):
    for j in range(img.shape[1]):
        if outputimg1[i][j] != imgOutput[i][j]:
            flog += 1
print(flog)
cv2.imshow('Output image', imgOutput)
cv2.imshow("11", outputimg1)
cv2.waitKey(0)
cv2.destroyAllWindows()

plt.figure(1), plt.title("begin"), plt.hist(img.ravel(), 256)
plt.figure(2), plt.title('end'), plt.hist(img1.ravel(), 256)
plt.figure(3), plt.title('begin->end'), plt.hist(imgOutput.ravel(), 256)
plt.show()

 

非锐化掩膜和高频提升滤波

非锐化掩膜处理后的图像,对细节增强更明显。
高频提升滤波处理后的图像,原图中所有边缘、细节、和灰度跳变点都作为黑背景中高灰度部分突出显示。
原理:将原图像进行高斯平滑滤波得到模糊图像,从原图像中减去模糊图像产生的插值图像一般保留了边缘信息,称为模板m(x,y),模板乘上一个修正因子,再与原图求和得到滤波后图像g(x,y),达到提高高频成分,增强细节的目的。
流程:
1、
平滑原图像:f高斯变换得到x;
2、从原图像中减去模糊图像,产生的差值图像称为模板m=f-x;
3、将模板加到原图像中:

##【5.8】对图像使用非锐化掩膜和高频提升滤波,观察两者的区别。

import cv2
import numpy as np

def fun_uh(img, k):
    imgBlur = cv2.GaussianBlur(img, (3, 3), 0)
    imgMask = img - imgBlur
    res = img + np.uint8(k * imgMask)
    return res

img = cv2.imread('E:/.../lenasp.jpg',0)
# 非锐化掩膜,系数k=1
mask_img = fun_uh(img, 1)
# 高频提升滤波,系数k=3
high_img = fun_uh(img, 3) 

cv2.imshow('Origin', img)
cv2.imshow("Unsharp mask image", mask_img)  #非锐化掩膜
cv2.imshow("High frequency", high_img)      #高频提升滤波
cv2.waitKey(0)
cv2.destroyAllWindows()

基于同态滤波的增强

同态滤波(处理照度明暗不均):是把频率滤波和空域灰度变换结合起来的一种图像处理方法,它根据图像的照度-反射率模型作为频域处理的基础,利用压缩亮度范围i(x,y)和增强对比度(反射分量)r(x,y)来改善图像的质量。
一幅图像可看成由两部分组成,即f(x,y)=i(x,y)+r(x,y)

同态滤波过程,分为以下5个基本步骤:
1、原图做对数变换,得到如下两个加性分量,即

2、对图像做傅里叶变换,得到其对应的频域表示为:

3、设计一个(高通)频域滤波器H(u,v),进行对数图像的频域滤波。

4、傅里叶反变换,返回空域对数图像。

5、求指数,得同态滤波结果。

综上,同态滤波的基本步骤如图所示:

##【例6.11】对一幅图像进行同态滤波,观察效果。

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

def homomorphic_filter(src, d0=10, r1=0.5, rh=2, c=4, h=2.0, l=0.5):
    gray = src.copy()
    if len(src.shape) > 2:
        gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
    gray = np.float64(gray)
    gray = np.log(1e-5 + gray)  #取对数

    rows, cols = gray.shape
    gray_fft = np.fft.fft2(gray)   #傅里叶变换
    gray_fftshift = np.fft.fftshift(gray_fft)    #中心化

    M, N = np.meshgrid(np.arange(-cols // 2, cols // 2), np.arange(-rows//2, rows//2))
    D = np.sqrt(M ** 2 + N ** 2)
    Z = (rh - r1) * (1 - np.exp(-c * (D ** 2 / d0 ** 2))) + r1   #H(u,v)滤波函数

    image_filtering_fftshift = Z * gray_fftshift
    image_filtering_fftshift = (h - l) * image_filtering_fftshift + l
    image_filtering_ifftshift = np.fft.ifftshift(image_filtering_fftshift)

    image_filtering_ifft = np.fft.ifft2(image_filtering_ifftshift)  #傅里叶反变换
    image_filtering = np.real(image_filtering_ifft)

    image_filtering = np.exp(image_filtering) - 1  # 指数变换还原
    image_filtering = np.uint8(np.clip(image_filtering, 0, 255))
    return image_filtering

if __name__ == "__main__":
    image = cv2.imread("E:/.../lena.jpg", 0)
    image_homomorphic_filter = homomorphic_filter(image)
    plt.subplot(221), plt.axis('off')
    plt.imshow(image, 'gray'), plt.title("Origin image")
    plt.subplot(222), plt.imshow(image_homomorphic_filter, 'gray')
    plt.title("Homomorphic image"), plt.axis('off')
    plt.show()

图像平滑

在图像的获取、传输和储存过程中常常会受到各种噪声的干扰和影响,使图像质量下降,为了获取高质量的数字图像,有必要对图像进行消除噪声处理,并且尽可能地保存原始信息的完整性。图像平滑方法大致分为两大类:空域法和频域法。空域法主要借助模板运算,在像素点领域内,利用噪声像素点特性进行滤波;频域法是指对图像进行正交变换,利用噪声对应高频信息的特点进行滤波。

图像中的噪声

什么是噪声:噪声在图像上常表现为一引起较强视觉效果的孤立像素点或像素块。一般,噪声信号与要研究的对象不相关,它以无用的信息形式出现,扰乱图像的可观测信息。
通俗的说就是噪声让图像不清楚
高斯噪声:噪声的概率密度函数服从高斯分布(正态分布)
添加高斯噪声:生成一个以正态分布为基础的噪声矩阵,加在图像矩阵上形成噪声图像。

def gasuss_noise(image, mean=0, var=0.01):
    #高斯噪声函数,mean:均值;var:方差
    image = np.array(image / 255, dtype=float)
    noise = np.random.normal(mean, var ** 0.5, image.shape)

    img_noise = image + noise

    if img_noise.min() < 0:
        low_clip = -1.
    else:
        low_clip = 0.
    
    img_noise = np.clip(img_noise, low_clip, 1.0)
    img_noise = np.uint8(img_noise * 255)
    return img_noise

37、np.random.normal(loc,scale,size)

(返回以正态分布为概率的size个随机数,np.random.random()随机返回[0,1]的浮点数)
loc:正态分布的均值,对应着这个分布的中心,函数的对称轴。
scale:正态分布的标准差,对应分布的宽度,scale越大,曲线越矮胖。
size:返回的数组大小。

38、np.clip(a,a_min,a_max)

(限定数组a中元素的范围,小于a_min则为a_min,大于a_max则为a_max)
a:输入的数组
a_min:限定的最小值,也可以是数组,如果为数组,则shape必须和a相同(比较时一一比较)
a_max:限定的最大值,同a_min

椒盐噪声:又称脉冲噪声,它是一种随机出现的白点(盐)或者黑点(椒)。
添加椒盐噪声:给定一个prob噪声比例,一般是通过计算添加黑白
点的数目来添加椒盐噪声(add_node=h*w*(1-prob)),通过随机生成函数生成坐标进行添加。但在这里是遍历每个像素点,通过随机生成数和prob的大小来添加噪声

def sp_noise(image, prob):
    # 椒盐噪声,image:原图像;prob:噪声比例;img_noise:加噪图像
    img_noise = np.zeros(img.shape, np.uint8)
    thres = 1 - prob
    cnt = 0
    for i in range(img.shape[0]):
        for j in range(img.shape[1]):
            rNum = np.random.random() 
            if rNum < prob:   # 添加椒噪声
                img_noise[i][j] = 0
            elif rNum > thres:   # 添加盐噪声
                img_noise[i][j] = 255
            else:
                img_noise[i][j] = image[i][j]
                cnt += 1
    return img_noise


泊松噪声:符合泊松分布的噪声模型,泊松分布适合于描述单位时间内随机事件发生的次数的概率分布
加性噪声:一般指热噪声、散弹噪声等,它们与信号的关系是相加,加性噪声与预想信号无关,不管有没有信号,该类噪声是一直存在的。一般通信中把加性随机性看成是系统的背景噪声。

乘性噪声:一般由信道不理想引起,它们与信号的关系是相乘,乘性噪声与图像信号相关,往往随图像信号的变化而变化,即信号在它在,信号不在他也就不在。可以分为两张情况:一种是某像素点的噪声只与该点的图像信号有关,另一种是与该点及其领域的图像信号有关,乘性随机性看成系统的时变性(如衰落或者多普勒)或者非线性所造成的。

 

空间域平滑滤波

空间域平滑滤波的操作对象为图像的像素灰度值。空域滤波主要指的是基于图像空间的领域模板运算,也就是说滤波处理要考虑到图像中处理像素点与其周边领域像素之间的联系。

1、均值滤波:又称领域平均法,是线性平滑滤波,是图像空间域平滑处理最基本的方法之一,基本思想是以某一像素为中心,在它的周围选择一领域,将领域内所有点的均值(灰度值相加求平均)来代替原来的像素值,通过降低噪声点与周围像素点的差值以去除噪声点。
常用的简单均值模板为:

import cv2
img = cv2.imread("E:/.../lenasp.jpg")    #读入带有椒盐噪声的图像
# 定义不同大小的卷积核
img1 = cv2.blur(img, (3, 3))       #卷积核为3x3,实现均值滤波
img2 = cv2.blur(img, (7, 7))       #卷积核为7x7,实现均值滤波
img3 = cv2.blur(img, (15, 15))     #卷积核为15x15,实现均值滤波
cv2.imshow("Origin image", img)   #显示原始图像
# 显示滤波后的图像
cv2.imshow("N=3 image", img1)
cv2.imshow("N=7 image", img2)
cv2.imshow("N=15 image", img3)
cv2.waitKey()
cv2.destroyAllWindows()

39、cv2.bulr(img,ksize)

(均值滤波函数)
img:输入图像
ksize:核大小,大于1的奇数矩阵(3×3,5×5等)。

2、高斯滤波:线性平滑滤波高斯滤波的基本原理是以某一像素为中心,在它的周围选择一个局部领域,把领域内像素的灰度按照高斯正态分布曲线进行统计,分配相应的权值系数,然后将领域内所有点的加权平均值来代替原来的像素值,通过降低噪声点与周围像素点的差值以去除噪声点。
通过来得到高斯矩阵
以c++代码为例子:

r=1 //高斯半径 

#define N=4  //矩阵大小为9 × 9 
#define pi acos(-1.0)
typedef double A=1/(2*pi*r*r)

double a=[N*2+1][N*2+1];
for(int i=-N;i<=N;i++){
	for(int j=-N;j<=N;j++){
		a[i+N][j+N]=A*exp((-1)*(i*i+j*j)/(2*r*r));
	}
}
 

import cv2
img = cv2.imread("E:/.../lenasp.jpg")    #读入带有椒盐噪声的图像
# 高斯滤波
image3 = cv2.GaussianBlur(img, (3, 3), 0, 0)     #卷积核为3x3
image7 = cv2.GaussianBlur(img, (7, 7), 0, 0)     #卷积核为7x7
image15 = cv2.GaussianBlur(img, (15, 15), 0, 0)  #卷积核为15x15

cv2.imshow("Origin image", img)   #显示原图
cv2.imshow("3 Gauss image", image3)  #显示3x3滤波后的图像
cv2.imshow("7 Gauss image", image7)  #显示7x7滤波后的图像
cv2.imshow("15 Gauss image",  image15) #显示15x15滤波后的图像
cv2.waitKey()
cv2.destroyAllWindows()

40、cv2.GaussianBlur(img,ksize,sigmaX,sigmaY,borderType)

(高斯滤波函数)
img:输入图像
ksize:核大小
sigmaX:(必选参数)卷积核在x轴上的标准差,控制权重比例
sigmaY:卷积核在y轴上的标准差,如果该值为0,则只采用sigmaX的值,如果两个都是0,则通过kszie.width和ksize.height计算的到:sigmaX=0.3 * [ (ksize.width-1) * 0.5 + 1 ] + 0.8;sigmaY=0.3 * [ (ksize.height-1) * 0.5 + 1 ] + 0.8
borderType:边界处理方式。

3、中值滤波:图像中,噪声的出现,使该点像素比周围像素暗(亮)许多,若把其周围的像素值排序,噪声点的值必然位于序列的前(后)端。序列的中值一般未受到噪声污染,所以可以用中值取代原像素点的值来滤除噪声。

 

import cv2
img = cv2.imread("E:/.../lenasp.jpg") #读入带有椒盐噪声的图像

image3 = cv2.medianBlur(img, 3)    #卷积核为3*3的中值滤波
image7 = cv2.medianBlur(img, 7)    #卷积核为7*7的中值滤波
image15 = cv2.medianBlur(img, 15)  #卷积核为15*15的中值滤波

cv2.imshow("Origin image", img)         #显示原始图像
cv2.imshow("N=3 median image", image3)  #显示3*3滤波后的图像
cv2.imshow("N=7 median image", image3)  #显示7*7滤波后的图像
cv2.imshow("N=15 median image", image3)  #显示15*15滤波后的图像
cv2.waitKey()
cv2.destroyAllWindows()

 

41、cv2.medianBlur(img,ksize)

(中值滤波函数)
img:输入图像
ksize:核大小,矩阵

4、双边滤波:(非线性平滑滤波方法)高斯滤波平滑由于仅考虑了位置对中心像素的影响,会较明显地模糊边缘,为了能够在消除噪声的同时很好的保留边缘,双边滤波是一种非常有效的方法。具有非迭代、局部和简单等特性。“双边”意味着平滑滤波时不仅考虑领域内像素的空间近邻性,而且要考虑领域内像素的灰度相似性。

 对于这几个公式我觉得可以看这里(牛牛牛):
https://blog.csdn.net/qq_43144313/article/details/121874933

import cv2
img = cv2.imread("E:/.../lenasp.jpg") #读入带有椒盐噪声的图像

image1 = cv2.bilateralFilter(img, 30, 50, 100)   #滤波半径30
image2 = cv2.bilateralFilter(img, 70, 50, 100)   #滤波半径70
image3 = cv2.bilateralFilter(img, 150, 50, 100)  #滤波半径150

cv2.imshow("Origin image", img) #带有椒盐噪声的图像
cv2.imshow("BF1 image", image1) #滤波半径30滤波后的图像
cv2.imshow("BF2 image", image2) #滤波半径70滤波后的图像
cv2.imshow("BF3 image", image3) #滤波半径150滤波后的图像
cv2.waitKey()
cv2.destroyAllWindows()

42、cv2.bilateralFilter(img,d,sigmgColor,sigmaSpace,borderType)

(双边滤波函数)
img:输入图像
d:过滤时每个像素领域的半径
sigmgColor:该值决定了周围哪些像素点能够参与到滤波中来。与当前像素点的像素值差值小于 sigmaColor 的像素点,能够参与到当前的滤波中。该值越大,就说明周围有越多的像素点可以参与到运算中。该值为0时,滤波失去意义;该值为255时,指定直径内的所有点都能够参与运算
sigmaSpace:。它的值越大,说明有越多的点能够参与到滤波计算中来。当d>0时,无论sigmaSpace的值如何,d都指定邻域大小;否则,d与 sigmaSpace的值成比例
borderType:处理边界方式,一般不用考虑

import cv2
img = cv2.imread("E:/.../lenasp.jpg") #读入带有椒盐噪声的图像

image1 = cv2.bilateralFilter(img, 30, 50, 100)   #滤波半径30
image2 = cv2.bilateralFilter(img, 70, 50, 100)   #滤波半径70
image3 = cv2.bilateralFilter(img, 150, 50, 100)  #滤波半径150

cv2.imshow("Origin image", img) #带有椒盐噪声的图像
cv2.imshow("B1 image", image1) #滤波半径30滤波后的图像
cv2.imshow("B2 image", image2) #滤波半径70滤波后的图像
cv2.imshow("B3 image", image3) #滤波半径150滤波后的图像
cv2.waitKey()
cv2.destroyAllWindows()

频域平滑滤波

在傅里叶变换域,变换系数反映了某些图像特征。如噪声对应于频率较高的区域,频域平滑滤波正是利用这个特性,通过把图像变换到频域,再通过低通滤波器去除噪声,通过反变换的到平滑后的图像。


f(x,y)为原图像,F(u,v)为傅里叶变换的图像,H(u,v)为滤波器,G(u,v)为滤波后的图像,g(x,y)为反变换后的图像。

常用的低通滤波器有:
1、理想低通滤波器,其传递函数为

 2、巴特沃斯低通滤波器,转移函数为

 3、指数低通滤波,转移函数为

4、梯形低通滤波,转移函数为

 D0,D1为上下限截至频率

43、cv2.createTrackbar(trackbarname,winname,value,maxValue,function)

(创建滑动条窗口函数)
trackbarname:滑动滑块名称(string)
winname:窗口名称(string)
value:滑块的初始值
maxValue:滑块可以移动的最大值
function:回调函数,每次滑动都要通过这个函数

44、cv2.getTrackbarPos(trackbarname,winname)

(得到滑动条当前的数值)
trackbarname:滑动条名称
winname:窗口名称

45、cv2.resizeWindow(winname,width,height)

(创建窗口后设置窗口大小)
winname:窗口名称
width:设置的窗口宽度
height:设置的窗口高度

46、cv2.getOptimalDFTSize(value)

(得到傅里叶最优尺寸大小)

47、cv2.dft(img,flag)

(傅里叶变换函数)
img:输入图像
flag:变换的标识符

cv2.idft(img):傅里叶反变换

48、np.fft.fftshift(img)

(将图像中的低频部分移动到图像的中心)
np.fft.ifftshift:将图像的低频和高频部分移动到图像原来的位置

49、cv2.magnitude(inputArray_x,inputArray_y)

(计算二维矢量的幅值,输出与X有相同的尺寸和类型)
inputArray_x:表示矢量的浮点型X坐标值,也就是实部
inputArray_y:表示矢量的浮点型Y坐标值,也就是虚部
原理:

50、cv2.normalize(img,dst,0,255,flag)

(指定将图片的值放缩到0~255之间)
这里更详细:https://blog.csdn.net/qq_42902997/article/details/122659376

51、cv2.split(img,mv)

(将图像拆分成B/G/R三个通道)
mv:可选参数,指定的拆分通道

52、cv2.merge(mv,dst)

(通道合并函数)
mv:合并的通道
dst:输出图像

例:对一幅图像进行巴特沃斯低通滤波平滑处理


import cv2
import numpy as np


def combine_images(images):  # 滤波后图像与频域图组合在一起
    shapes = np.array([mat.shape for mat in images])
    rows = np.max(shapes[:, 0])
    copy_imgs = [cv2.copyMakeBorder(img, 0, rows - img.shape[0], 0, 0, cv2.BORDER_CONSTANT, (0, 0, 0)) for img in images]
    return np.hstack(copy_imgs)


def fft(img):  # 傅里叶变换
    rows, cols = img.shape[:2]
    nrows = cv2.getOptimalDFTSize(rows)  # 得到傅里叶最优尺寸大小
    ncols = cv2.getOptimalDFTSize(cols)
    nimg = np.zeros((nrows, ncols))
    nimg[:rows, :cols] = img
    fft_mat = cv2.dft(np.float32(nimg), flags=cv2.DFT_COMPLEX_OUTPUT)
    return np.fft.fftshift(fft_mat)


def fft_image(fft_mat):
    log_mat = cv2.log(1 + cv2.magnitude(fft_mat[:, :, 0], fft_mat[:, :, 1]))
    cv2.normalize(log_mat, log_mat, 0, 255, cv2.NORM_MINMAX)
    return np.uint8(np.around(log_mat))


def ifft(fft_mat):  # 逆傅里叶变换
    f_ishift_mat = np.fft.ifftshift(fft_mat)
    img_back = cv2.idft(f_ishift_mat)
    img_back = cv2.magnitude(*cv2.split(img_back))
    cv2.normalize(img_back, img_back, 0, 255, cv2.NORM_MINMAX)
    return np.uint8(np.around(img_back))


def fft_distances(m, n):
    u = np.array([i if i <= m / 2 else m - i for i in range(m)], dtype=np.float32)
    v = np.array([i if i <= m / 2 else m - i for i in range(m)], dtype=np.float32)
    v.shape = n, 1
    ret = np.sqrt(u * u + v * v)
    return np.fft.fftshift(ret)


def BWfilter(rows, cols, d0, n):  # 巴特沃斯低通滤波
    duv = fft_distances(*fft_mat.shape[:2])
    filter_mat = 1 / (1 + np.power(duv/d0, 2 * n))
    filter_mat = cv2.merge((filter_mat, filter_mat))
    return filter_mat


def do_filter(fft_mat, filter_win):
    d0 = cv2.getTrackbarPos('D0', filter_win)
    n = cv2.getTrackbarPos('n', filter_win)
    filter_mat = BWfilter(fft_mat.shape[0], fft_mat.shape[1], d0, n)
    filtered_mat = filter_mat * fft_mat
    img_back = ifft(filtered_mat)
    cv2.imshow(image_win, combine_images([img_back, fft_image(filter_mat)]))


if __name__ == '__main__':
    img = cv2.imread('E:/.../lena.jpg', 0)
    rows, cols = img.shape[:2]
    filter_win = 'Filter Parameters'
    image_win = 'Butterworth Low Pass Filtered Image'
    cv2.namedWindow(filter_win)
    cv2.namedWindow(image_win)
    cv2.createTrackbar('D0', filter_win, 20, min(rows, cols) // 4, do_filter)
    cv2.createTrackbar('n', filter_win, 1, 5, do_filter)
    fft_mat = fft(img)
    do_filter(fft_mat, filter_win)
    cv2.resizeWindow(filter_win, 512, 20)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

 

图像锐化

图像锐化的目的是加强图像中景物的边缘和轮廓,突出图像中的细节或增强被模糊了的细节。

图像边缘分析

边缘定义为图像中亮度突变的区域,图像中的边缘主要有一下3种:细线性边缘突变型边缘渐变型边缘

算子检测边缘

1、Roberts算子(一阶微分):又称为交叉微分算法,它是基于交叉差分的梯度算法,通过局部差分计算检 测边缘线条。

##【例9.1】使用Roberts算子检测图像的边缘

import cv2
import numpy as np

img = cv2.imread("E:/.../lena.jpg")   # 读取图像
#img = cv2.imread("D:\pics\lenasp.jpg")   # 读取带有椒盐噪声的图像
grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 灰度化处理图像
# Roberts算子
kernelx = np.array([[-1, 0], [0, 1]], dtype=int)
kernely = np.array([[0, -1], [1, 0]], dtype=int)
x = cv2.filter2D(grayImage, cv2.CV_16S, kernelx)
y = cv2.filter2D(grayImage, cv2.CV_16S, kernely)
# 转uint8
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
Roberts = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
# 显示图像
cv2.imshow("Original",grayImage)
cv2.imshow("Roberts",Roberts)
cv2.waitKey()
cv2.destroyAllWindows()


2、Sobel算子(一阶微分):引入平均因数,对图像中的随机噪声有一定的平滑作用;相隔两行或两列差分,故边缘两侧的元素得到了增强,边缘显得粗而亮。

##【例9.3】使用Sobel算子检测图像的边缘

import cv2

image = cv2.imread("E:/.../lena.jpg")
#image = cv2.imread("D:\pics\lenasp.jpg")   # 读取带有椒盐噪声的图像
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
#Sobel边缘检测
sobelX = cv2.Sobel(image, cv2.CV_16S, 1, 0)  # 对x求一阶导
sobelY = cv2.Sobel(image, cv2.CV_16S, 0, 1)  # 对y求一阶导
sobelX = cv2.convertScaleAbs(sobelX)      # 转换为uint8
sobelY = cv2.convertScaleAbs(sobelY)      # 转换为uint8
# 两幅图像叠加
sobelCombined = cv2.addWeighted(sobelX, 0.5, sobelY, 0.5, 0)
# 显示图像
cv2.imshow("Original", image)
cv2.imshow("X", sobelX)
cv2.imshow("Y", sobelY)
cv2.imshow("Sobel Combined", sobelCombined)
cv2.waitKey()
cv2.destroyAllWindows()

3、Laplacionsuanz(二阶微分):拉普拉斯算子, n 维欧几里德空间中的一个二阶微分算子,分为四邻域和八邻域,四邻域是对邻域中心像素的四个方向求梯度,八邻域是对八个方向求梯度。

#【例9.4】】使用Laplacian算子检测图像的边缘

import cv2

img = cv2.imread("E:/.../lena.jpg")
#img = cv2.imread("D:\pics\lenasp.jpg")   # 读取带有椒盐噪声的图像
image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 将图像转化为灰度图像

# 拉普拉斯边缘检测,ksize分别为1/3/5
# laplacian = cv2.Laplacian(image, cv2.CV_16S, ksize=1)
laplacian = cv2.Laplacian(image, cv2.CV_16S, ksize=3)
# laplacian = cv2.Laplacian(image, cv2.CV_16S, ksize=5)
laplacian = cv2.convertScaleAbs(laplacian)
# 显示图像
cv2.imshow("Original", image)
cv2.imshow("Laplacian", laplacian)
cv2.waitKey()
cv2.destroyAllWindows()

4、LOG算子:由拉普拉斯算子改进而来。拉普拉斯算子是一个单纯的二阶导数算子,是一个标量,具有线性、位移不变性,其传函在频域空间的原点为0,在实际应用中,一般先要对图像进行平滑滤波,再用拉氏算子进行图像的边缘检测。这就是LoG算子的产生的背景其步骤是先对图形高斯滤波处理,再用拉普拉斯进行边缘检测。

##【例9.5】】先用高斯滤波器平滑图像,再用Laplacian算子检测图像的边缘

import cv2

img = cv2.imread("E:/py/.../lena.jpg")
#img = cv2.imread("D:\pics\lenasp.jpg")   # 读取带有椒盐噪声的图像
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 将图像转化为灰度图像

# 高斯滤波
image = cv2.GaussianBlur(img, (3, 3), 0)
# 拉普拉斯边缘检测
laplacian = cv2.Laplacian(image, cv2.CV_16S, ksize=3)
laplacian = cv2.convertScaleAbs(laplacian)
# 显示图像
cv2.imshow("Original", image)
cv2.imshow("Laplacian", laplacian)
cv2.waitKey()
cv2.destroyAllWindows()

5、Ganny算子:可以认为是边缘检测的最优算法,Ganny采用高斯滤波器对图像做平滑,在平滑后图像的每个像素处计算梯度幅值和方向;利用梯度方向,采用非极大抑制方法细化边缘;再用双阈值算法检测和连接边缘,最终得到细化的边缘图像。
主要步骤为

##【例9.6】】使用Canny算子检测图像的边缘

import cv2

img = cv2.imread("E:/.../lena.jpg")
#img = cv2.imread("D:\pics\lenasp.jpg")   # 读取带有椒盐噪声的图像
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转化为灰度图像
img_gaus = cv2.GaussianBlur(img_gray, (3, 3), 0)         # 高斯滤波

# Canny边缘检测,设置两个阈值分别为100和200
edge_output = cv2.Canny(img_gaus, 100, 200)
dst = cv2.bitwise_and(img, img, mask=edge_output)

cv2.imshow("Original", img)
cv2.imshow("canny", edge_output)
cv2.imshow("Color Edge", dst)
cv2.waitKey()
cv2.destroyAllWindows()

其他算子还有:梯度算子Prewitt算子Scharr算子Kirsch算子

53、cv2.filter2D(img,ddepth,kernel,anchor,delta,borderType)

(自定义卷积核实现卷积操作函数)
img:原始图像。它能够有任意数量的通道,并能对各个通道独立处理。图像深度应该是CV_8U、CV_16U、CV_16S、CV_32F或者CV_64F中的一 种
ddepth:处理结果图像的图像深度,一般使用-1表示与原始图像使用相同的图像深度
kernel:自定义卷积核
,是一个单通道的数组。如果想在处理彩色图像时,让每个通道使用不同的核,则必须将彩色图像分解后使用不同的核完成操作
anchor:锚点,其默认值是(-1,-1),表示当前计算均值的点位于核的中心点位 置。该值使用默认值即可,在特殊情况下可以指定不同的点作为锚点
delta:修正值,它是可选项。如果该值存在,会在基础滤波的结果上加上该值作 为最终的滤波处理结果。
borderType:边界样式,该值决定了以何种情况处理边界,通常使用默认值即可。
该函数常用形式为:
cv2.filter2D(src,ddepth,kernel)

54、cv2.convertScalerAbs(img)

(将像素点进行绝对值运算)

55、cv2.Sobel(img,ddepth,dx,dy,ksize)

(实现Sobel算子边缘检测函数;图像梯度计算函数)
ddepth:图像的深度,CV_8U、CV_16U、CV_16S、CV_32F或者CV_64F
dx、dy:分别表示x方向和y方向(1,0)表示x方向
kszie:可选参数,sobel算子大小,默认为3

56、cv2.Laplacion(img,ddepth,ksize,scale,delta,borderType)

(拉普拉斯锐化函数)
 ksize:卷积核大小,奇数。(其它参数同cv2.filter2D)

57、cv2.Ganny(img,threshold1,threshold2,apertureSize)

(Ganny边缘检测函数)
threshold1:阈值1
threshold2:阈值2
apertureSize:可选参数,sobel算子的大小,默认为3(sobel算子对检测结果的影响:扩大算子,会获得更多的细节,但是也更能提取图像了

频域高通滤波实现图像锐化

图像中的边缘对应于高频分量,所以图像锐化可以采用高通滤波器实现,其步骤和频域平滑滤波实现图像平滑步骤类似,只是将频域滤波器变为高通滤波器。

1、理想高通滤波器

 2、巴特沃斯高通滤波器

 3、指数高通滤波器

 4、梯形滤波器

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

烊@

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

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

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

打赏作者

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

抵扣说明:

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

余额充值