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)
得到图像矩阵
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)
hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
Ycrcb = cv.cvtColor(image, cv.COLOR_BGR2YCrCb)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
图像间的加、减、乘、除:
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) #计算图片每个通道所有元素均值标准差
imand = cv.bitwise_and(m1, m2)
imor = cv.bitwise_or(m1, m2)
imnot = cv.bitwise_not(m1)
调节对比度和亮度
#参数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(Region of Interest), 对某个图片区域进行提取操作,用numpy获取ROI,例如:rio= src[20:300,250:750]
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)
dst = cv.bilateralFilter(image, 0, 100, 15)
# (src,d,sigmacolor,sigmaspace)指定sigma参数反算d
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)
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)
#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)
五步:高斯模糊-灰度转换-计算梯度-非最大信号抑制-高低阈值输出二值图像
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)