RGB三色:
OpenCV是BGR存储图片,RGB 是大多数其他库(如 Matplotlib、PIL)的默认格式。
R(255,0,0)
G(0,255,0)
B(0,0,255)
import cv2
import numpy as np
import matplotlib.pyplot as plt
image = cv2.imread(r'C:\Users\hi\Desktop\2.png')
plt.figure(figsize=(20, 15))
plt.subplot(2, 2, 1)
plt.imshow(image[:,:,0], cmap='gray')
plt.title('blue')
plt.axis('off')
plt.subplot(2, 2, 2)
plt.imshow(image[:,:,1], cmap='gray')
plt.title('green')
plt.axis('off')
plt.subplot(2, 2, 3)
plt.imshow(image[:,:,2], cmap='gray')
plt.title('red')
plt.axis('off')
plt.subplot(2, 2, 4)
plt.imshow(image)
plt.title('original')
plt.axis('off')
plt.show()
---------------------------------------
实际上的RGB转换成灰度图像是RGB三色的权重值:0.299*R+0.587*G+0.114*B
验证如下:(test是分离三通道,加权后用公式计算的)
import cv2
import numpy as np
import matplotlib.pyplot as plt
image = cv2.imread(r'C:\Users\hi\Desktop\2.png')
b,g,r = cv2.split(image)
gray_manual = 0.299*r+0.587*g+0.114*b;
gray_manual = np.uint8(gray_manual)
plt.figure(figsize=(15, 5))
# 灰度图
plt.subplot(1, 3, 1)
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
plt.imshow(gray,cmap='gray')
plt.title('gray')
plt.axis('off')
# 原图
plt.subplot(1, 3, 2)
plt.imshow(image)
plt.title('original')
plt.axis('off')
#测试
plt.subplot(1, 3, 3)
plt.imshow(gray_manual,cmap='gray')
plt.title('test')
plt.axis('off')
plt.show()
-------------------------------------------------------------------
crop裁剪:
裁剪区域判断可以看图像的属性去微调:
[200:500,400:800]指的是宽200到500,和长400到800这个区域。
import cv2
import numpy as np
import matplotlib.pyplot as plt
image = cv2.imread(r'C:\Users\hi\Desktop\2.png')
image_crop = image[200:500,400:800]
plt.figure(figsize=(10, 5))
# 裁剪
plt.subplot(1, 2, 1)
plt.imshow(image_crop)
plt.title('crop')
plt.axis('off')
# 原图
plt.subplot(1, 2, 2)
plt.imshow(image)
plt.title('original')
plt.axis('off')
plt.show()
---------------------------------------------------------------
绘制功能:
import cv2
import numpy as np
import matplotlib.pyplot as plt
image = cv2.imread(r'C:\Users\hi\Desktop\2.png')
image_crop = image[200:500,450:750]
cv2.circle(image_crop,(150,150),30,(0,0,255),7)
cv2.putText(image_crop,"CV",(130,150),0,1,(0,0,0),2,1)
cv2.imshow("image",image_crop)
cv2.waitKey()
-------------------------------------------------------------------------------------
滤波去噪:
快速模糊平滑 → 均值滤波
去噪+保留细节 → 高斯滤波
采用均值、高斯滤波去噪:均值和高斯滤波不改变图像尺寸
卷积核(滤波核)在图像上滑动,对每个像素点及其邻域进行加权计算。
- 中心像素:卷积核覆盖区域的加权平均值会直接影响该像素的新值。
- 边缘像素:当卷积核靠近图像边界时,邻域部分超出图像范围,此时需通过填充策略处理越界区域。
比如:生成一张带了高斯噪声的图像,保存到本地
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取图像(BGR格式)
img = cv2.imread(r'C:\Users\hi\Desktop\2.png')
# 生成高斯噪声
# 参数说明:
# (1) 噪声矩阵形状与图像一致
# (2) 均值 mean=0
# (3) 标准差 sigma=25(根据需求调整)
noise = np.random.normal(loc=0, scale=55, size=img.shape).astype(np.float32)
# 将噪声叠加到图像上
noisy_img = img.astype(np.float32) + noise
# 限制像素值范围 [0, 255] 并转换为 uint8
noisy_img = np.clip(noisy_img, 0, 255).astype(np.uint8)
cv2.imwrite(r'C:\Users\hi\Desktop\6.png',noisy_img)
滤波处理:
import cv2
import matplotlib.pyplot as plt
# 读取图像
img = cv2.imread(r'C:\Users\hi\Desktop\6.png')
# 均值滤波
blur_mean = cv2.blur(img, (5, 5))
# 高斯滤波
blur_gaussian = cv2.GaussianBlur(img, (7, 7), sigmaX=0)
cv2.imwrite(r'C:\Users\hi\Desktop\7.png',blur_gaussian)
# 显示结果
plt.figure(figsize=(18, 9))
#plt.subplot(121), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title("Original")
plt.subplot(121), plt.imshow(cv2.cvtColor(blur_mean, cv2.COLOR_BGR2RGB)), plt.title("Mean Filter")
plt.subplot(122), plt.imshow(cv2.cvtColor(blur_gaussian, cv2.COLOR_BGR2RGB)), plt.title("Gaussian Filter")
plt.show()
-------------------------------------------------------------------------------------
特征提取:提取图像的转角,然后用圆圈标记出来(500是最大数量,0.05是阈值,调节阈值筛选想要的转角)
import cv2
import numpy as np
import matplotlib.pyplot as plt
image = cv2.imread(r'C:\Users\hi\Desktop\2.png')
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
corners = cv2.goodFeaturesToTrack(gray,500,0.05,10)
for corner in corners:
x,y = corner.ravel()
cv2.circle(image,(int(x),int(y)),3,(255,0,255),-1)
cv2.imshow("corners",image)
cv2.waitKey()
--------------------------------------------------------------------------------
模板匹配:
图像是用画图工具自己做的。
visionpro的模板匹配更加准确一些。
import cv2
import numpy as np
import matplotlib.pyplot as plt
image = cv2.imread(r'C:\Users\hi\Desktop\3.png')
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
template = gray[110:190,20:130]
num = 0
#cv2.rectangle(image,(110,20),(190,120),(0,255,0),2)
match = cv2.matchTemplate(gray,template,cv2.TM_CCOEFF_NORMED)
locations = np.where(match >= 0.9)#0.9为阈值
h,w = template.shape[0:2]
for p in zip(*locations[::-1]):
x1,y1 = p[0],p[1]
x2,y2 = x1+w,y1+h
cv2.rectangle(image,(x1,y1),(x2,y2),(0,255,0),1)
num+=1
cv2.putText(image,"nums:"+str(num),(10,50),0,1,(0,0,0),1,1)
cv2.imshow("image",image)
cv2.waitKey()
----------------------------------------------------------------------------
边缘检测:
一阶导数在灰度突变处(如边缘)会呈现较大的值。
梯度方向:梯度向量 ∇f=(∂x/∂f,∂y/∂f) 的方向指向亮度变化最快的方向。
图像梯度算法:边缘通常是灰度值变化剧烈的区域,梯度算法可以用来提取边缘
一阶看的是变化率,提取的是粗略的边缘,使用算子有Sobel.
二阶看的是变化的加速度,提取的是精确的边缘,但是非常容易受到噪声影响,有噪声就需要对噪声进行处理,使用算子有Canny(分段函数式取值,有过渡区间)和Laplacian(直接粗暴,没有过渡区间),Canny更加抗噪声。
Sobel和Canny对比如下:
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取图像
image = cv2.imread(r'C:\Users\12581\Desktop\color_flowers.bmp', cv2.IMREAD_GRAYSCALE)
# 应用Canny边缘检测
# 参数1: 最小阈值,参数2: 最大阈值
edges = cv2.Canny(image, 100, 200)
# 显示原图和边缘检测结果
plt.figure(figsize=(10, 5))
# 原图
plt.subplot(1, 2, 1)
plt.imshow(image, cmap='gray')
plt.title('Original Image')
plt.axis('off')
# 边缘图
plt.subplot(1, 2, 2)
plt.imshow(edges, cmap='gray')
plt.title('Canny Edge Detection')
plt.axis('off')
plt.show()
Sobel:边缘非常粗糙
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取图像
image = cv2.imread(r'C:\Users\12581\Desktop\color_flowers.bmp', cv2.IMREAD_GRAYSCALE)
# 应用Canny边缘检测
# 参数1: 最小阈值,参数2: 最大阈值
edges = cv2.Canny(image, 100, 200)
# 显示原图和边缘检测结果
plt.figure(figsize=(10, 5))
# 原图
plt.subplot(1, 2, 1)
plt.imshow(image, cmap='gray')
plt.title('Original Image')
plt.axis('off')
# 边缘图
plt.subplot(1, 2, 2)
plt.imshow(edges, cmap='gray')
plt.title('Canny Edge Detection')
plt.axis('off')
plt.show()
Canny: 边缘准确
----------------------------------------------------------------------------
二值化:
(0-255)灰度图像变成(0-1)二值图像
OpenCV对比与Visionpro还是有强大的地方的,它的二值化可以分区域来设置不同的阈值。
比如这张图片,明暗分布不均匀:
Visionpro效果:
OpenCV:
import cv2
import numpy as np
import matplotlib.pyplot as plt
gray = cv2.imread(r'C:\Users\hi\Desktop\4.jpg',cv2.IMREAD_GRAYSCALE)
ret,binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
binary_adaptive = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,151,7)
cv2.imshow("image1",binary)
cv2.imshow("image2",binary_adaptive)
cv2.waitKey()
OTSU阈值算法:也叫大津法(专门用在cv2.threshold(),不需要调整参数,适合场景是光照均匀的图片,不适合在光照不均匀和噪声多的图片)
我们看一下OTSU的强大性:
import cv2
import numpy as np
import matplotlib.pyplot as plt
gray = cv2.imread(r'C:\Users\hi\Desktop\2.png',cv2.IMREAD_GRAYSCALE)
ret,binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
#binary_adaptive = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,151,7)
ret,binary_otsu = cv2.threshold(gray,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)
plt.figure(figsize=(20, 15))
plt.subplot(2, 2, 1)
plt.imshow(gray, cmap='gray')
plt.title('gray')
plt.axis('off')
plt.subplot(2, 2, 2)
plt.imshow(binary, cmap='gray')
plt.title('binary')
plt.axis('off')
plt.subplot(2, 2, 3)
plt.imshow(binary_otsu, cmap='gray')
plt.title('binary_otsu')
plt.axis('off')
plt.show()
原图是gray,不用otsu就需要人工去调阈值,binary这张图还需要去调整参数。
-----------------------------------------------
形态学:
膨胀(dilated)、腐蚀(eroded)、开运算(先腐蚀后膨胀)、闭运算(先膨胀后腐蚀)
import cv2
import numpy as np
import matplotlib.pyplot as plt
image = cv2.imread(r'C:\Users\hi\Desktop\2.png',cv2.IMREAD_GRAYSCALE)
ret,gray = cv2.threshold(image,200,255,cv2.THRESH_BINARY_INV|cv2.THRESH_OTSU)
kernel = np.ones((7,7),np.uint8)
dilated = cv2.dilate(gray,kernel,iterations=1)#膨胀
eroded = cv2.erode(gray,kernel,iterations=1)#腐蚀
open = cv2.dilate(eroded,kernel,iterations=1)#开运算
close = cv2.erode(dilated,kernel,iterations=1)#闭运算
plt.figure(figsize=(20, 15))
plt.subplot(2, 2, 1)
plt.imshow(dilated , cmap='gray')
plt.title('dilated ')
plt.axis('off')
plt.subplot(2, 2, 2)
plt.imshow(eroded, cmap='gray')
plt.title('eroded')
plt.axis('off')
plt.subplot(2, 2, 3)
plt.imshow(open, cmap='gray')
plt.title('open')
plt.axis('off')
plt.subplot(2, 2, 4)
plt.imshow(close, cmap='gray')
plt.title('close')
plt.axis('off')
plt.show()
开运算和闭运算,膨胀和腐蚀,哪个先使用,哪个的效果就是主要效果。如图就是,闭运算是膨胀先使用,就算使用了腐蚀有效恢复了图像形态,但是膨胀效果还是主要效果。
---------------------------------------------------------------------
读取相机流:
import cv2
capture = cv2.VideoCapture(0)
while True:
ret,frame = capture.read()
cv2.imshow("camera",frame)
key = cv2.waitKey(1)
if key!=-1:
break
capture.release()