sponsored links

OpenCV图像处理

一、图片基本操作(加载、显示、保存)

import cv2 as cv  #导入OpenCV
src = cv.imread('beauty.png')  #加载图片
# cv.namedWindow('picture',cv.WINDOW_AUTOSIZE)   #创建一个窗口,用于显示图像(窗口的名称,窗口的大小自动根据图像尺寸而变化)
cv.imshow('image',src)  #显示图片
cv.imwrite('image.jpg', src)   #保存图片到当前目录
cv.waitKey(0)
# cv.destroyAllWindows()

二、图像的一些数组操作

几何变换

平移:如果需要将图像向右平移tx个像素(负数表示向左),向下平移ty个像素(正数表示向上),则变换矩阵为:[[1, 0, tx], [0, 1, ty]]

import cv2 as cv 
image = cv2.imread('lf.png')
tx = 20
ty = 30
translation_matrix = np.float32([[1, 0, tx], [0, 1, ty]])
image_translated = cv2.warpAffine(image, translation_matrix, (image.shape[1], image.shape[0]))
# 使用resize函数可以进行伸缩变换,例如将图像宽度放大两倍:
image_resized = cv2.resize(image, (2 * image.shape[1], image.shape[0]), interpolation=cv2.INTER_CUBIC)

获取图像的基本信息:

type(image) 得到整张图像的类型
image.shape 得到图像的形状
image.size 得到图像像素值的个数
image.dtype 得到图像像素值的类型
pixel_data = np.array(image) 得到图像矩阵

与Numpy数组操作相关的图像的处理:

import cv2 as cv  
import numpy as np  #导入numpy
cv.namedWindow('picture',cv.WINDOW_AUTOSIZE)
#创建单通道图片
img = np.ones([400,400,1], np.uint8)
img = img * 0  #给每个像素点赋值0得到一张纯黑色的图片

#创建一张像素为9的图片
m1 = np.ones([3,3],np.uint8)  
m1.fill(9)  #

#创建多通道图片
img = np.zeros([400,400,3],np.uint8)
img[: ,: ,0] = np.ones([400,400])*255  #对通道0赋值为蓝色

cv.waitKey(0)
cv.destroyAllWindows()

对图像通道的操作:

b, g, r = cv.split(src)  #通道分离
src = cv.merge([b, g, r])   #通道合并

对图像像素点值的操作:

height = image.shape[0]  #获取图像的高度
width = image.shape[1]   #获取图像的宽度
channels = image.shape[2]   #获取图像的通道数
for row in range(height):  #遍历图像数组中的每个像素点
    for col in range(width):
        for c in range(channels):
            pv = image[row, col, c]
            image[row, col, c] = 255 - pv  
#OpenCV中有快速简单的实现上面功能的API 
dst = cv.bitwise_not(image)

三、色彩空间

1.常见色彩空间

  • RGB:最常见的色彩空间,OpenCV显示系统使用BGR颜色,有时需要添加第四个元素:透明度(alpha)。
  • HSV和HIS:将颜色分解为hue、saturation和value/luminance,这是描述颜色更自然的方式。当忽略value时,可以使算法对输入图像的光照条件不太敏感。HSV对应的取值范围为:H:0-180, S:0-255, V:0-255。
  • YCrCb:JPEG图像格式使用的色彩空间

2.色彩空间的转换

  • HSV与RGB:
    hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
  • YCrCb与RGB:
    Ycrcb = cv.cvtColor(image, cv.COLOR_BGR2YCrCb)
  • gray与RGB:

四、像素运算

1.算术运算

图像间的加、减、乘、除:

imadd = cv.add(image1, image2)
imsub = cv.subtract(image1, image2)
immul = cv.multiply(image1, image2)
imdiv = cv.divide(image1, image2)

均值与标准差

mean = cv.mean(image) #计算图片每个通道所有元素均值
dev = cv.meanStdDev(image)  #计算图片每个通道所有元素均值标准差

2.逻辑运算

  • 与、或、非
imand = cv.bitwise_and(m1, m2)
imor = cv.bitwise_or(m1, m2)
imnot = cv.bitwise_not(m1)

3.应用-遮罩层控制、调节亮度和对比度

调节对比度和亮度

#参数c为对比度,b为亮度
def contrast_brightness_demo(image, c, b):  
    h, w, ch = image.shape
    blank = np.zeros([h, w, ch], image.dtype)
    dst = cv.addWeighted(image, c, blank, 1-c, b)
    cv.imshow("con-bri-demo", dst)

# addWeighted(InputArray src1, double alpha, InputArray src2,  double beta, double gamma, OutputArray dst =None, int dtype=None)    
#addWeighted()函数作用:计算两个数组的加权和(dst = alpha*src1 + beta*src2 + gamma)。即将两幅图像进行融合    

五、ROI与泛洪填充

1.什么是ROI,如何获取

ROI(Region of Interest), 对某个图片区域进行提取操作,用numpy获取ROI,例如:rio= src[20:300,250:750]

2.泛洪填充

  • floodFill(image, mask, seedPoint, newVal, loDiff, upDiff, flags)
    src(seed.x, seed.y)- loDiff <= src(x,y) <= src(seed.x, seed.y)+ upDiff
  • 如何填充一个对象内部区域由flags决定:
    FLOODFILL_FIXED_RANGE – 改变图像,泛洪填充
    FLOODFILL_MASK_ONLY – 不改变图像、只填充遮罩层本身、忽略新的颜色值参数
def fill_color(image):   #改变图像,范围内填红色
    copyim = image.copy()
    h, w = image.shape[:2]  #提取图像高和宽
    mask = np.zeros([h+2, w+2], np.uint8)  #这里必须+2和使用uint8
    cv.floodFill(copyim, mask, (30,30), (0,0,255), (100,100,100),(50,50,50),cv.FLOODFILL_FIXED_RANGE)
    cv.imshow("fillcolor", copyim)

def fill_binary(image):   #不改变图像、只填充遮罩层本身、忽略新的颜色值参数
    image = np.zeros([400,400,3], np.uint8)
    image[100:300, 100:300, :] = 255
    cv.imshow("fillbinary", image)
    mask = np.ones([402,402,1], np.uint8)
    mask[101:301, 101:301] = 0
    cv.floodFill(image, mask, (200,200), (0,0,255), cv.FLOODFILL_MASK_ONLY)  
    cv.imshow("filledbinary",image)

六、模糊操作

基本原理:模糊是基于离散的卷积,模糊是卷积的一种表象,主要定义好每个卷积核,不同卷积核得到不同的卷积效果。

# 均值模糊,可去噪
dst = cv.blur(image, (5, 5))  #卷积核大小为(5,5)

# 中值模糊对椒盐噪声有很好的去燥效果
dst = cv.medianBlur(image, 5)   #卷积核大小为(5,5)

# 保留图像主要特征,可抑制高斯噪声
dst = cv.GaussianBlur(image, (0, 0), 15) 

 #自定义卷积核的模糊处理
 kernel = np.ones([5, 5], np.float32)/25
 dst = cv.filter2D(image, -1, kernel=kernel)
 #卷积核数值为奇数或者加起来总和等于1(有增强效果)或者0(突出边缘和梯度效果)
 #锐化算子:kernel = np.array([[0, -1, 0],[-1, 5, -1],[0, -1, 0]], np.float32) 

七、边缘保留滤波(EPF)

1.高斯双边(美颜滤镜)

 dst = cv.bilateralFilter(image, 0, 100, 15)
 # (src,d,sigmacolor,sigmaspace)指定sigma参数反算d

2.均值迁移

dst = cv.pyrMeanShiftFiltering(image, 10, 50)
#(src,sp,sr)

八、图像直方图

一维直方图:

import cv2 as cv
from matplotlib import pyplot as plt

image = cv.imread("test.png")
plt.hist(image.ravel(), 256, [0, 256])  #image.ravel()统计不同像素值频次; (x, bins,range)
plt.show("直方图")

多维直方图:

import cv2 as cv
from matplotlib import pyplot as plt

image = cv.imread("test.png")
color = ('blue', 'green', 'red')
for i, color in enumerate(color):
    hist = cv.calcHist([image], [i], None, [256], [0, 256])  #(images, channels, mask, histSize, ranges)
    plt.plot(hist, color=color)
    plt.xlim([0, 256])
plt.show()

直方图比较:

import cv2 as cv

image1 = cv.imread("test1.png")
image2 = cv.imread("test2.png")
def create_rgb_hist(image):
    h, w, c = image.shape
    rgbHist = np.zeros([16*16*16, 1], np.float32)  #必须为np.float32
    bsize = 256 / 16
    for row in range(h):
        for col in range(w):
            b = image[row, col, 0]
            g = image[row, col, 1]
            r = image[row, col, 2]
            index = np.int(b/bsize)*16*16 + np.int(g/bsize)*16 + np.int(r/bsize)
            rgbHist[np.int(index), 0] = rgbHist[np.int(index), 0] + 1
    return rgbHist
hist1 = create_rgb_hist(image1)
hist2 = create_rgb_hist(image2)
match1 = cv.compareHist(hist1, hist2, cv.HISTCMP_BHATTACHARYYA)  #巴氏距离
match2 = cv.compareHist(hist1, hist2, cv.HISTCMP_CORREL)   #相关性
match3 = cv.compareHist(hist1, hist2, cv.HISTCMP_CHISQR)   #卡方

直方图均衡化,针对灰度图像,对比度增强:

gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
dst = cv.equalizeHist(gray)

局部自适应直方图均衡化,可以用参数进行干涉:

gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
clahe = cv.createCLAHE(clipLimit=5.0, tileGridSize=(8, 8))
dst = clahe.apply(gray)

九、图像二值化

全局二值化:

gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
ret, binary = cv.threshold(gray, 127, 255, cv.THRESH_BINARY|cv.THRESH_OTSU)
#(src, thresh, maxval, threshholdType)
#OTSU(多个波峰)和Triangle(单个波峰)都是自动的全局阈值,故这里127不起作用

局部自适应二值化:

gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
binary = cv.adaptiveThreshold(gray, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 25, 10) 
# (src, maxValue, adaptiveMethod, threshholdType, blockSize, C), blockSize必须是奇数  

自定义二值化:

gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
h, w = gray.shape[:2]
m = np.reshape(gray, [1, w*h])
mean = m.sum() / (w*h)
ret, binary = cv.threshold(gray, mean, 255, cv.THRESH_BINARY)    

十、图像梯度

1.一阶导数与Soble算子

grad_x = cv.Scharr(image, cv.CV_32F, 1, 0)  #Scharr是Soble算子的增强版
grad_y = cv.Scharr(image, cv.CV_32F, 0, 1)
gradx = cv.convertScaleAbs(grad_x)
grady = cv.convertScaleAbs(grad_y)
cv.imshow("gradient-x", gradx)
cv.imshow("gradient-y", grady)
gradxy = cv.addWeighted(gradx, 0.5, grady, 0.5, 0)

2.二阶导数与拉普拉斯算子

#1
dst = cv.Laplacian(image, cv.CV_32F)
lpls = cv.convertScaleAbs(dst)
#2
kernel = np.array([[1, 1, 1], [1, -8, 1], [1, 1, 1]])  #拉普拉斯8邻域算子
dst = cv.filter2D(image, cv.CV_32F, kernel=kernel)
lpls = cv.convertScaleAbs(dst)

十一、Canny 边缘提取

五步:高斯模糊-灰度转换-计算梯度-非最大信号抑制-高低阈值输出二值图像

blurred = cv.GaussianBlur(image, (3, 3), 0)
gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)
# X Gradient
x_grad = cv.Sobel(gray, cv.CV_16SC1, 1, 0)
# Y Gradient
y_grad = cv.Sobel(gray, cv.CV_16SC1, 0, 1)
#edge
edge_output = cv.Canny(x_grad, y_grad, 50, 150) #高阈值与低阈值应当3:1(2:1)
#edge_output = cv.Canny(gray, 50, 150) #有时也可以获得较好的效果
cv.imshow("Canny Edge", edge_output)
#提取彩色边缘
dst = cv.bitwise_and(image, image, mask=edge_output)
cv.imshow("Color Edge", dst)

十二、特征匹配

当一个物体被从不同角度拍摄后,特征会略有不同。如果能够计算这两个角度之间的变换关系,可以进行三维重构等任务。
OpenCV可以帮助我们提取两张图像的特征,并且进行特征之间的匹配。

# 首先对两张图像分别进行ORB特征提取。
image1 = cv2.imread('image1.jpg', flags=cv2.IMREAD_COLOR)
image2 = cv2.imread('image2.jpg', flags=cv2.IMREAD_COLOR)
orb = cv2.ORB_create()
points1, desc1 = orb.detectAndCompute(image1, None)
points2, desc2 = orb.detectAndCompute(image2, None)

# 然后使用暴力匹配获得两张图像中能够匹配的关键点(key point)和描述子(descriptor)。
matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
match = matcher.match(desc1, desc2)

# 将关键点之间距离最接近的10个关键点相连,并可视化。
match = sorted(match, key=lambda x: x.distance)[:10]
result = cv2.drawMatches(image1, points1, image2, points2, match, None, flags=2)

十三、人脸检测

face_cascade = cv2.CascadeClassifier('face.xml')
image = cv2.imread('lf.jpg')
result = image.copy()
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(image_gray, 1.3, 5)
for x, y, w, h in faces:
  cv2.rectangle(result, (x, y), (x + w, y + h), (255, 0, 0), 2)
Tags: