openCV - 基础知识笔记

openCV-Python

openCV

1. 色彩空间

常用的色彩空间有:RGB/RGBA/GRAY/HSV/YUV
(1)RGB/RGBA:RGB是三通道,即红绿蓝三个通道;RGBA是四通道,比RGB多了个透明度。

RGB色彩模式是工业界的一种颜色标准,是通过对红( R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。

(2)GRAY:即灰度图像,单通道。

(3)HSV:H是色彩/色度,取值[0, 179],S是饱和度,取值[0, 255],V是亮度,取值[0, 255]。但是由于软件使用的值不同,取值范围也不同。通常需要拿openCV的HSV值和其他软件的HSV值进行对比时,要记得使用归一化处理。

(4)YUV:是一种彩色编码系统,主要用在视频、图像处理流水线中。

YUV是一种颜色空间,基于YUV的颜色编码是流媒体的常用编码方式。Y表示流明,U、V表示色度、浓度,这种表达方式起初是为了彩色电视与黑白电视之间的信号兼容。 对于图像每一点,Y确定其亮度,UV确认其彩度。

# openCV读取图片时候的初始格式是BGR格式
img1 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img2 = cv2.cvtColor(img, cv2.COLOR_BGR2RGBA)
img3 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img4 = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

2. 基本图形绘制

openCV内置的基本图形绘制有:直线、矩形、圆形、椭圆、多边形、文字。

import cv2
img = cv2.imread("")

# 坐标轴是从左上角到右下角
cv2.line(img, (100, 30), (210, 180), color=(0, 0, 255), thickness=2) # 直线 参数:坐标点1,2 绘制颜色 粗度
cv2.circle(img, (50, 50), 30, (0, 0, 255), 1) # 圆形 参数:圆心 半径  颜色 粗度
cv2.rectangle(img, (100, 30),(210, 180), color=(0, 0, 255), thickness=2) # 矩形 参数: 对角点1,2 颜色 粗度
cv2.ellipse(img, (100, 100), (100, 50), 0, 0, 360, (255, 0, 0), -1) # 椭圆 参数:圆心(1,2) 长短轴(1,2) 旋转角度 起始角度 颜色 粗度 默认-1
cv2.polylines(img, [pts], True, (0, 0, 255), 2) # 多边形 参数:所有角坐标 是否闭合 颜色 粗度
cv2.putText(img, 'hello world!', (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 1, lineType=cv2.LINE_AA) # 文字 参数:添加的文字,左上角坐标,字体,字体大小,颜色,字体粗细

cv2.imshow("pic", img)

3. 阈值操作:

(1)什么是二值化?
图像的二值化,就是将图像上的像素点的灰度值设置为0或255(0或1),也就是将整个图像呈现出明显的只有黑和白的视觉效果。

(2)二值化的类型有哪些?
OTSU二值化,普通二值化,自适应阈值二值化。
(不同类型的二值化本质区别是,如何找到一个界限来划分二值化。)

  • OTSU二值化:使用类间方差作为二值化的评估标准。
  • 简单阈值:通过设置一个阈值,大于该阈值设置为1,小于该阈值设置为0。
  • 自适应阈值:根据图像不同区域亮度分布,计算其局部阈值,所以对于图像不同区域,能够自适应计算不同的阈值。
#
img = cv2.imread('', 0)

ret, th1 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSH)
th2 = cv2.adaptiveThreshold(img, 255, 
ret, th2 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
#自适应阈值
th3 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
th4 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)

4. 图像运算

图像存储数据的本质就是张量,所以图像运算的本质是矩阵运算。
(1)加减:对应位置相加减。(INT8,值域在0-255之间,超过255,设置为255,低于0,设置为0)

cv2.add(x, y)
cv2.subtract(x,y)

(2)图像混合:本质上也是图像相加,根据两幅图像的权重不同相加,给人一种混合或者透明感。

dst = cv2.addweighted(img1, 0.7, img2, 0.3, 0)

(3)按位运算:常用按位操作有,与AND,或OR,非NOT,异或XOR等。

import cv2

img1 = cv2.imread('')
img2 = cv2.imread('')

rows, cols, channels = img2.shape
roi = img1[0:rows, 0:cols]

img2gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
ret,mask = cv2.threshold(img2gray, 10, 255, cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)

# cv2.imshow("mask_inv", mask_inv)

img1_bg = cv2.bitwise_and(roi, roi, mask=mask_inv)

# cv2.imshow("img1_bg ", img1_bg )

img2_fg = cv2.bitwise_and(img2, img2, mask=mask)

# cv2.imshow("img2_fg ", img2_fg )

det = cv2.add(img1_bg, img2_fg)
img1[0:rows, 0:cols]=dst

cv2.imshow('res', img1)
cv2.waitKey(0)

5. 图像的几何变换

(1)resize/transpose/flip 缩放/旋转/翻转

img_resize = cv2.resize(img, Size, fx, fy, interpolation) # size 缩放后的尺寸, fx,fy缩放系数 interpolation 选项所用的插值方法 默认双线性插值
img_trans=cv2.transpose(img) # 逆时针旋转90° 即矩阵转置
img_flip0=cv2.flip(img,0) # 参数:大于0表示沿y轴翻转,等于0表示沿x轴翻转,小于0表示 x和y同时翻转

(2)仿射变换 (线性变换): 任意一个二维图像,乘以一个仿射矩阵,就能得到仿射变换后的图像。(缩放、旋转、位移、倾斜、镜像)

rot_mat =  cv2.getRotationMatrix2D(center, -5, 1) # 获得仿射变换矩阵(旋转)
# center表示中间点的位置,-5表示逆时针旋转5度,1表示进行等比列的缩放
cv2.warpAffine(img, rot_mat, (img.shape[1], img.shape[0])) # 仿射运算
# img表示输入的图片,rot_mat表示仿射变化矩阵,(image.shape[1], image.shape[0])表示变换后的图片大小

(3)透视变换:将图片投影到一个新的视平面,也称作投影映射。

M = cv2.getPerspectiveTransform(pts1, pts2) # 参数:原来透视变换前坐标点位置, 透视变换后坐标点的位置
dst = cv2.warpPerspective(img, M, (200, 201))

(4)膨胀/腐蚀 (二值化图像)

  • 膨胀操作可以让颜色值大的像素变得更粗。
  • 腐蚀操作可以让颜色值大的像素变得更细。
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) # 定义膨胀/腐蚀的核
dst_dilate = cv2.dilate(img, kernel) # 膨胀
dst_erode = cv2.erode(img, kernel) # 腐蚀

(5)开/闭/梯度/礼帽/黑帽

  • 开操作:先腐蚀后膨胀,用来去噪。
  • 闭操作:先膨胀后腐蚀,用来填坑。
  • 梯度操作:膨胀减去腐蚀,提取轮廓。
  • 礼帽子操作:原图减去开操作,提取噪声。
  • 黑帽操作:原图减去闭操作,提取漏洞。
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) # 定义核
dst_open = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) # 开
dst_close = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel) # 闭
dst_grad = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel) # 梯度
dst_tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel) # 顶帽/礼帽
dst_black = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel) # 黑帽

6. 图像滤波

(1)什么是滤波?
滤波过程就是把不需要的信号频率去掉的过程/
滤波操作通过卷积操作来实现,卷积核一般称为滤波器。常见的滤波分为:低通滤波、高通滤波、中通滤波、阻带滤波。
滤波分析一般分为时域分析核频域分析。

  • 低通滤波:限制图像只允许低频信号通过,又叫平滑滤波。低频信号一般变换比较小,因此图像会变得平滑、模糊。主要用于去噪。
  • 高频滤波:限制图像只允许高频信号通过,变化大的信号,一般再图像边缘、轮廓的位置,因此高通滤波可以用于获取图像边缘、轮廓或者梯度。
  • 中通滤波:限制图像只允许已知范围频率的信号通过。
  • 阻带滤波:用于去掉已知频率范围内的信号。

(2)什么是频域和时域。
时域就是信号随着时间变化得到不同的取值;频域是根据不同频率的信号得到的频谱图。两者可以通过傅里叶变换和傅里叶逆变换实现相互的转换。
(以下的操作都是在时域上通过卷积操作进行的)

(3)卷积操作:卷积操作的本质就是卷积核在图像在从左到右从上到下扫描进行卷积,得到新的图像。(称为特征图)

(4)平滑操作:通过定义一个平滑算子(低通滤波器),对图像进行卷积操作。
平滑算子:均值滤波,高斯滤波,中值滤波,双边滤波。

(5)锐化操作:通过定义一个锐化算子(高通滤波器),对图像进行卷积操作。
锐化算子:Laplacian算子。
USM锐化算法:原图的2倍减去高斯滤波后的图像。

kernel_1 = np.array([[1,1,0],[1,0,-1],[0,-1,-1]], np.float32) # 高通滤波器 Laplacian算子
dst_1 = cv2.filter2d(src, -1, kernel=kernel_1) # 滤波运算

dst_2 = cv2.blue(src, (5,5)) # 均值滤波 定义5*5的均值滤波
dst_3 = cv2.GaussianBlur(src, (5,5), 1) # 高斯滤波  定义5*5的高斯滤波 1: 方差为1的高斯滤波 对高斯噪声平滑处理很好
dst_4 = cv2.medianBlur(src, 5) # 中值滤波  定义5*5的中值滤波 对椒盐噪声平滑处理很好

(6)梯度操作:通过定义一个梯度算子(滤波器),对图像进行卷积操作。(梯度一般有两个方向,一个横轴x,一个竖轴y)
梯度算子:Sobel,Scharr和Laplacian梯度滤波器。

img_x = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)  # X方向 sobel
img_y = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)  # y方向 sobel
img_XY = cv2.Sobel(img, cv2.CV_64F, 1, 1, ksize=3) # xy方向 sobel
img_lap = cv2.Laplacian(img,cv2.CV_16S,ksize = 3) # laplacian

abs_X = cv2.convertScaleAbs(img_x)   # 转回uint8
abs_Y = cv2.convertScaleAbs(img_y)   # 转回uint8
abs_XY = cv2.convertScaleAbs(img_XY)   # 转回uint8
abs_lap = cv2.convertScaleAbs(img_lap) 

cv2.imshow("abs_X", abs_X)
cv2.imshow("abs_Y", abs_Y)
cv2.imshow("abs_XY", abs_XY)
cv2.imshow('laplacian',abs_lap) 
cv2.waitKey(0)

7. Canny边缘提取算法

(1)Canny算法的流程:
① 彩色图像转换为灰度图像;
② 高斯滤波,滤除噪声点;
③ 计算图像梯度,根据梯度计算边缘幅值与角度;
④ 非极大值抑制;
⑤ 双阈值边缘连接处理;
⑥ 二值化图像输出结果。

(2)什么是非极大值抑制?
非极大值抑制是一种边缘稀疏技术,非极大值抑制的作用在于瘦边。即找到梯度最大的,对其他的进行抑制(消去)。对图像进行梯度计算后,仅仅基于梯度值提取的边缘仍然很模糊。使用这种方法,可以使得边缘只保留一个像素。
步骤:

  • 将当前像素的梯度强度与沿正负梯度方向上的两个像素进行比较。
  • 如果当前像素的梯度强度与另外两个像素相比最大,则该像素点保留为边缘点,否则该像素点将被抑制。

(3)什么是双阈值边缘连接处理?
这一步主要用来确定边缘,即哪些边缘是边缘,哪些不是。因此通过两个阈值,minVal和maxVal,当图像的灰度梯度高于maxVal时被认为是真的边界,那些低于 minVal 的边界会被抛弃。如果介于两者之间的话,就要看这个点是否与某个被确定为真正的边界点相连,如果是就认为它也是边界点,如果不是就抛弃。

双阈值检测及边缘连接原理详解及具体代码

(4)代码:

import cv2

img = cv2.imread("0.jpg", 0)
cv2.imshow('src', img)
img = cv2.convertScaleAbs(img, alpha=6, beta=0) #提高对比度
cv2.imshow('abs', img)
img = cv2.GaussianBlur(img, (5,5), 0)
canny = cv2.Canny(img, 50, 150) # 参数: 双阈值检测中两个参数
canny = cv2.resize(canny, dsize=(500, 500))
cv2.imshow('canny', canny)
cv2.waitKey(0)

8. 轮廓查找与绘制

(1)opencv如何查找轮廓信息?
轮廓发现是基于图像边缘提取的基础寻找对象轮廓的方法。所以边缘提取的阈值选定会影响最终轮廓发现结果。
它是通过搜索二值图像上的边缘拐点,然后进行连接,绘制轮廓。
(2)代码:
函数详解——寻找图像轮廓findContours()

# 函数内置canny
coutours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# RETR_TREE:提取所有轮廓并重新建立网状轮廓结构
# CHAIN_APPROX_NONE:获取每个轮廓的每个像素,相邻的两个点的像素位置差不超过1
# CHAIN_APPROX_SIMPLE:压缩水平方向,垂直方向,对角线方向的元素,值保留该方向的重点坐标,如果一个矩形轮廓只需4个点来保存轮廓信息
img_contour = cv2.drawContours(img, contours, -1, (0, 255, 0), 3)

(3)轮廓面积、周长、重心:

area = cv2.contourArea(contours[0]) # 面积
perimeter= cv2.arcLength(contours[0], True) # 周长
M= cv2.moment(contours[0]) # 重心

(4)轮廓近似:
简单来说,就是findContours函数得到轮廓中的坐标点后,approx对图像轮廓点进行多边形拟合

epsilon = 40 # 精度 就是另个轮廓点之间最大距离数
approx = cv2.approxPolyDP(contours[0], epsilon, True)
img_contour = cv2.drawContours(img, [approx], -1, (0, 255, 0), 3)

(5)凸包与凸性检测
convexHull():检测曲线是否有凸性缺陷,并能矫正缺陷。(凹进去就被叫做凸性缺陷)
isContourConvex():检测曲线是否为凸,只能返回True或False。

hull = cv2.convexHull(contours[0]) # 
f = cv2.isContourConvex(contours[0]) # 原始为凹 False
t = cv2.isContourConvex(hull) # 矫正后为凸 True

(6)边界检测

  • 边界矩形;
  • 外接正方形;
  • 外接圆;
mport cv2
import numpy as np

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

imggray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(imggray, 127, 255, 0)

contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 边界矩形
x, y, w, h = cv2.boundingRect(contours[0])
img_contour = cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)

# 最小矩形
rect = cv2.minAreaRect(contours[0])
box = cv2.boxPoints(rect)
box = np.int0(box)
img_contour = cv2.drawContours(img, [box], 0, (0, 0, 255), 2)

# 最小外切圆
(x, y), radius = cv2.minEnclosingCircle(contours[0])
center = (int(x), int(y))
radius = int(radius)
img_contour = cv2.circle(img, center, radius, (255, 0, 0), 2)

cv2.imshow("img_contour", img_contour)
cv2.waitKey(0)

(7)轮廓性质

  • 边界矩形的宽高比;
x,y,w,h = cv2.boundingRect(cnt)
aspect_ratio = float(w/h)
  • 轮廓面积与边界矩形面积比;
area = cv2.contourArea(cnt)
x,y,w,h = cv2.boundingRect(cnt)
rect_area = w*h
extent = float(area/rect_area )
  • 轮廓面积与凸包面积的比;
area = cv2.contourArea(cnt)
hull = cv2.convexHull(cnt)
hull_area = cv2.contourArea(hull)
solidity= float(hull/hull_area )
  • 与轮廓面积相等的圆形的直径;
area = cv2.contourArea(cnt)
equi_diameter = np.sqrt(4*area/np.pi)
  • 对象的方向;
    可以通过绘制外接椭圆,返回长短轴以及方向。
    也可以通过拟合,随机找对象中的点,拟合直线。
import cv2
import numpy as np

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

imggray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(imggray, 127, 255, 0)

contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 椭圆拟合
ellipse = cv2.fitEllipse(contours[0])
cv2.ellipse(img, ellipse, (255, 0, 0), 2)

# 直线拟合
h, w, _ = img.shape
[vx, vy, x, y] = cv2.fitLine(contours[0], cv2.DIST_L2, 0, 0.01, 0.01)
lefty = int((-x * vy / vx) + y)
righty = int(((w - x) * vy / vx) + y)
cv2.line(img, (w - 1, righty), (0, lefty), (0, 0, 255), 2)

cv2.imshow("img_contour", img)
cv2.waitKey(0)

9. 图像金字塔

(1)什么是图像金字塔?
图像金字塔就是将一张图片,按不同的比例缩放,形成一组不同尺寸大小的图片。(即,下采样和上采样)

(2)什么是高斯金字塔和拉普拉斯金字塔,两者有什么区别?
高斯金字塔(Gaussianpyramid): 先进行高斯模糊,再等比例缩放。(上采样/下采样缩放)
上采样一定会造成照片的模糊。
拉普拉斯金字塔(Laplacianpyramid): 用来从金字塔低层图像重建上层未采样图像,在数字图像处理中也即是预测残差,可以对图像进行最大程度的还原,配合高斯金字塔一起使用

两者的简要区别:高斯金字塔用来向下降采样图像,注意降采样其实是由金字塔底部向上采样,分辨率降低,它和我们理解的金字塔概念相反(注意);而拉普拉斯金字塔则用来从金字塔底层图像中向上采样重建一个图像。

图像金字塔详解

(3)代码:
高斯金字塔:

import cv2

img = cv2.imread(r"13.jpg")
for i in range(3):
    cv2.imshow(f"img{i}",img)
    # img = cv2.pyrDown(img)
    img = cv2.pyrUp(img)

cv2.waitKey(0)

拉普拉斯金字塔

import cv2

img = cv2.imread(r"12.jpg")
img_down = cv2.pyrDown(img)
img_up = cv2.pyrUp(img_down)
img_new = cv2.subtract(img, img_up)
#为了更容易看清楚,做了个提高对比度的操作
img_new = cv2.convertScaleAbs(img_new, alpha=5, beta=0)
cv2.imshow("img_LP", img_new)
cv2.waitKey(0)

10. 霍夫变换Hough

根据数学公式,找出图像中对应的形状。(极坐标/直角坐标转换为霍夫空间,再根据数学公式找到符合的形状)

代码:
(1)检测直线

import cv2
import numpy as np

image = cv2.imread("lines.jpg")
image_2 = image.copy()

image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

edges = cv2.Canny(image_gray, 100, 150)

lines = cv2.HoughLines(edges, 1, np.pi / 180, 150)

for line in lines:
    rho, theta = line[0]
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a * rho
    y0 = b * rho
    x1 = int(x0 + 1000 * (-b))  # 直线起点横坐标
    y1 = int(y0 + 1000 * (a))  # 直线起点纵坐标
    x2 = int(x0 - 1000 * (-b))  # 直线终点横坐标
    y2 = int(y0 - 1000 * (a))  # 直线终点纵坐标
    cv2.line(image, (x1, y1), (x2, y2), (0, 0, 255), 2)

imgs = np.hstack([image_2,image])
cv2.imshow("image_lines", imgs)
cv2.imwrite("test.jpg",imgs)

cv2.waitKey(0)

(2)检测圆形

import cv2
import numpy as np

rawImage = cv2.imread("circles.jpg")
image = cv2.GaussianBlur(rawImage, (3, 3), 1)
image_gray = cv2.cvtColor(image, cv2.COLOR_BGRA2GRAY)

edges = cv2.Canny(image_gray, 100, 150)


circle = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, 1, 80, param1=40, param2=20, minRadius=20, maxRadius=100)
if not circle is None:
    circle = np.uint16(np.around(circle))
    for i in circle[0, :]:
        cv2.circle(image, (i[0], i[1]), i[2], (0, 0, 255), 2)

imgs = np.hstack([rawImage,image])
cv2.imshow("image_lines", imgs)
cv2.imwrite("test.jpg",imgs)

cv2.waitKey(0)

11. 直方图

(1)什么是直方图?
直方图就是对一张图上,所有颜色值出现的次数的分布。

代码:

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('1.jpg')
# img[...,0]=0
# img[...,1]=0
# cv2.imshow("...",img)

# img_B = cv2.calcHist([img], [0], None, [256], [0, 256])
# plt.plot(img_B, label='B', color='b')

# img_G = cv2.calcHist([img], [1], None, [256], [0, 256])
# plt.plot(img_G, label='G', color='g')
#
img_R = cv2.calcHist([img], [2], None, [256], [0, 256])
plt.plot(img_R, label='R', color='r')

plt.show()

(2)什么是直方图均衡化?
直方图均衡化是一种利用灰度变换自动调节图像对比度质量的方法,基本思想是通过灰度级的概率密度函数求出灰度变换函数,它是一种以累计分布函数变换法为基础的直方图修正法。
代码:

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('7.jpg', 0)
cv2.imshow("src", img)

his = cv2.calcHist([img], [0], None, [255], [0, 255])
plt.plot(his, label='his', color='r')
# plt.show()

dst = cv2.equalizeHist(img)
cv2.imshow("dst", dst)

cv2.imwrite("15.jpg", dst)

his = cv2.calcHist([dst], [0], None, [255], [0, 255])
plt.plot(his, label='his', color='b')
plt.show()

(3)普通的直方图均衡化和自适应直方图均衡化有什么区别?
普通直方图均衡化可以会导致某些局部区域变得非常亮;因此我们希望图片局部进行直方图均衡化。(需要设置局部窗口的大小)

import cv2

img = cv2.imread('8.jpg', 0)
cv2.imshow("src", img)

dst1 = cv2.equalizeHist(img)
cv2.imshow("dst1", dst1)

clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))# 8*8即局部窗口大小
dst2 = clahe.apply(img)
cv2.imshow("dst2", dst2)

cv2.waitKey(0)

(4)直方图反投影:
利用HSV直方图提取某块颜色(需要有某块区域模板),就可以获取图片上某些区域的掩码。例如,蓝天、草坪……

import cv2
import numpy as np

roi = cv2.imread('10.jpg') # 被提取的图片
hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
target = cv2.imread('9.jpg') # 提取颜色的模板
hsvt = cv2.cvtColor(target, cv2.COLOR_BGR2HSV)

roihist = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])

cv2.normalize(roihist, roihist, 0, 255, cv2.NORM_MINMAX)
dst = cv2.calcBackProject([hsvt], [0, 1], roihist, [0, 180, 0, 256], 1)

disc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
dst = cv2.filter2D(dst, -1, disc)

ret, thresh = cv2.threshold(dst, 50, 255, 0)

thresh = cv2.merge((thresh, thresh, thresh))

res = cv2.bitwise_and(target, thresh)
res = np.hstack((target, thresh, res))

cv2.imshow('img', res)
cv2.waitKey(0)

12. 傅里叶变换

(1)什么是傅里叶变换?
傅里叶变换就是将图像从时域转换为频域,在频域上对图像进行操作。

时域(时间域)——自变量是时间,即横轴是时间,纵轴是信号的变化。其动态信号x(t)是描述信号在不同时刻取值的函数。
频域(频率域)——自变量是频率,即横轴是频率,纵轴是该频率信号的幅度,也就是通常说的频谱图。

(2)频谱图;

  • 频谱图是中心对称的;
  • 中心为低频信号,越往四周频率越高;
  • 如果频谱图中暗的点数更多,那么实际图像是比较柔和的(各点与邻域差异都不大,梯度相对较小) ;反之,如果频谱图中亮的点数多,那么实际图像一定是尖锐的(边界分明且边界两边像素差异较大);
  • 频域和时域可以相互转换。

(3)代码:

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

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

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

magnitude_spectrum = 20 * np.log(cv2.magnitude(dft_shift[:, :, 0], dft_shift[:, :, 1]))

plt.figure(figsize=(10, 10))
plt.subplot(221), plt.imshow(img, cmap='gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(222), plt.imshow(magnitude_spectrum, cmap='gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])

rows, cols = img.shape
crow, ccol = rows // 2, cols // 2
# create a mask first, center square is 1, remaining all zeros
mask = np.zeros((rows, cols, 2), np.uint8)
mask[crow - 30:crow + 30, ccol - 30:ccol + 30] = 1
fshift = dft_shift * mask
# apply mask and inverse DFT

f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = cv2.magnitude(img_back[:, :, 0], img_back[:, :, 1])

plt.subplot(223), plt.imshow(img_back, cmap='gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(224), plt.imshow(img_back)
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])

plt.show()

傅里叶变换

13. 分水岭算法

  • 什么是分水岭算法?
    简单来讲,分水岭就是将图片上的目标划分开的技术。通过不断的腐蚀,用腐蚀的次数代表数值,我们可以找到需要腐蚀次数最大的位置,设置为山峰。四周的数值逐渐降低。划定一个阈值,即可将目标划分开。
    分水岭算法的原理及实现

14. 特征提取

(1)什么是特征?
特征实质上就是一张图片上突出的地方。也就是会更加吸引我们注意的地方。而对计算机而言,特征就是能够达到目标和解决问题的地方。
(2)Harris角点检测;

dst = cv2.cornerHarris(gary_img, 2, 3, 0.04) # 得到角点位置的掩码图
img[dst>0.01*dst.max()] = [0,0,255]

(3)Shi-Tomasi角点检测:获得最好的角点;

corners = cv2.goodFeaturesToTrack(gray, 100, 0.01, 10)
corners = np.int0(corners)
for i in corners:
	x, y = i.ravel()
	cv2.circle(img, (x, y), 3, 255, 3)

对于上述两种角点,它们具有旋转不变特性。即即使图片旋转,也能找到角点。但是如果我们对图像近缩放,可能就找不到角点了。

(4)SIFT

sift = cv2.xfeatures2d.SIRF_create() # 有专利保护
kp = sift.detect(gray, None)
img2 = cv2.drawKeypoints(img, kp, None, color=(0,0,255))

(5)SURF:SURF比SIFT快。

suft = cv2.xfeatures2d.SURF_create() # 有专利保护
kp = sift.detect(gray, None)
img2 = cv2.drawKeypoints(img, kp, None, color=(0,0,255))

(6)Fast算法:

  • 原理:若某像素与其周围邻域内足够多的像素点相差较大,则该像素可能是角点。筛选出所有可能是角点的位置,再通过非极大值抑制来消除紧挨着的点。
  • 缺陷:过度依赖于阈值;候选角点可能会比较多。
fast = cv2.FastFeatureDetector_create(threshold=35)
fast.setNonmaxSuppression(False) # 关闭非极大值抑制
kp = fast.detect(grayImg, None)
img2 = cv2.drawKeypoints(img, kp, None, color=(0,0,255))

(7)ORB算法:ORB是FAST和BRIEF的合体。

orb = cv2.ORB_create()
kp = orb.detect(grayImg, None)
kp, des = orb.compute(grayImg, kp)

img2 = cv2.drawKeypoints(img, kp, None, color=(0,0,255), flags=0)

(8)特征匹配
FLANN匹配器:匹配两张图上的角点位置。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值