目标检测_初识

需要一些基本的cv知识

图像分辨率

图像分辨率可以定义为图像中存在的像素数。当像素数量增加时,图像的质量会增加。我们已经在前面看到了图像的形状,它给出了行和列的数量。这可以说是该图像的分辨率。几乎所有人都知道的一些标准分辨率是320 x 240像素(主要适用于小屏幕设备)、1024 x 768像素(适用于在标准计算机显示器上观看)、720 x 576像素(适合在宽高比为4:3的标准清晰度电视机上观看),1280 x 1024像素(适用于在宽高比为5:4的液晶显示器上全屏观看)、1920 x 1080像素(用于在高清电视上观看),现在我们甚至有4K、5K和8K分辨率,超高清显示器和电视分别支持3840 x 2160像素、5120 x 2880像素和7680 x 4320像素

图像像素的高位包含的信息比低位更多,我们可以将图像划分为不同级别的位平面。例如,将图像划分为8位(0-7)平面,其中最后几个平面包含图像的大部分信息。

bit plans

image-20231123110414030

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import cv2
import torch
from torch import nn
import matplotlib.pylab as plt
import numpy as np

img = cv2.imread("../imgs/00000.png",cv2.IMREAD_GRAYSCALE)

c1 = np.mod(img,2)
c2 = np.mod(np.floor(img/2),2)
c3 = np.mod(np.floor(img/4),2)
c4 = np.mod(np.floor(img/8),2)
c5 = np.mod(np.floor(img/16),2)
c6 = np.mod(np.floor(img/32),2)
c7 = np.mod(np.floor(img/64),2)
c8 = np.mod(np.floor(img/128),2)

cc = 2*(2*(2*c8+c7)+c6)
to_plot = [img,c1,c2,c3,c4,c5,c6,c7,c8,cc]
fig,axes = plt.subplots(2,5, subplot_kw={'xticks': [], 'yticks': []})
fig.subplots_adjust(hspace=0.05, wspace=0.05)
for ax,i in zip(axes.flat, to_plot):
ax.imshow(i, cmap='gray')

plt.tight_layout()
plt.show()

cv2.waitKey()

可以使用像素的高位重建图像

图像直方图

1
2
3
4
5
6
7
8
9
10
def his(img_gray):
hist = cv2.calcHist([img_gray], [0], None, [256], [0, 256])

plt.figure()
plt.title("Grayscale Histogram")
plt.xlabel("bins")
plt.ylabel("pixels")
plt.plot(hist)
plt.xlim([0, 256])
plt.show()

image-20231123134730139

图像深度

数字化图像的每个像素是用一组二进制数进行描述,像素的色彩由RGB通道决定,其中包含表示图像颜色的位数称为图像深度。如灰度图像,每个像素颜色占用1个字节8位,则称图像深度为8位,而RGB的彩色图像占用3字节,图像深度为24位。

图像深度又称为色深(Color Depth),它确定了一幅图像中最多能使用的颜色数,即彩色图像的每个像素最大的颜色数,或者确定灰度图像的每个像素最大的灰度级数。
使用opencv的imread读取模式有

IMREAD_UNCHANGED = -1, //返回原始图像。alpha通道不会被忽略,如果有的话。加载给定格式的图像,包括alpha通道。Alpha通道存储透明度信息——Alpha通道的值越高,像素就越不透明
IMREAD_GRAYSCALE = 0, //返回灰度图像
IMREAD_COLOR = 1, //返回通道顺序为BGR的彩色图像
IMREAD_ANYDEPTH = 2, //当输入具有相应的深度时返回16位/ 32位图像,否则将其转换为8位。.
IMREAD_ANYCOLOR = 4, //则以任何可能的颜色格式读取图像。

颜色空间

颜色空间是一种协议(protocol),用于以易于再现的方式表示颜色。我们知道,灰度图像具有单个像素值,彩色图像每个像素包含3个值——红色、绿色和蓝色通道的强度。

大多数计算机视觉用例处理RGB格式的图像。然而,视频压缩和设备独立存储等应用程序在很大程度上依赖于其他颜色空间,如色相(Hue即色相,就是我们平时所说的红、绿,如果你分的更细的话可能还会有洋红、草绿等等)、饱和度(色彩的深浅度(0-100%,对于一种颜色比如红色,我们可以用浅红——大红——深红——红得发紫等等语言来描述它)、色调(纯度,色彩的亮度(0-100%) ,这个在调整屏幕亮度的时候比较常见)即HSV颜色空间

RGB图像由不同颜色通道的颜色强度组成,即强度和颜色信息在RGB颜色空间中混合,但在HSV颜色空间中,颜色和强度信息彼此分离。这将使HSV颜色空间对光源更改更加稳健

image-20231123115359582

图像resize

机器学习模型使用固定大小的输入。同样的想法也适用于计算机视觉模型。我们用于训练模型的图像必须具有相同的大小。现在,如果我们通过从各种来源抓取图像来创建自己的数据集,这可能会成为问题。这就是调整图像大小的功能凸显出来的地方

INTER_NEAREST:最近邻插值

INTER_LINEAR:双线性插值

INTER_AREA:使用像素面积关系重新采样

INTER_CUBIC:4×4像素邻域上的双三次插值

INTER_LANCZOS4:8邻域上的Lanczos插值

1
2
3
4
5
import cv2
import numpy as npimg = cv2.imread("../imgs/00000.png")
cv2.imshow("img",img)
smaller_img = cv2.resize(img,(200,200),interpolation=cv2.INTER_LINEAR)
cv2.imshow("smaller_img",smaller_img)

图像旋转以及平移

可以用作图像增强的技术

1
2
3
4
5
6
7
8
import cv2
import numpy as np
img = cv2.imread("../imgs/00000.png")
rows,cols = img.shape[:2]
M = cv2.getRotationMatrix2D((cols/2,rows/2),45,1)
dst = cv2.warpAffine(img,M,(cols,rows))
cv2.imshow("dst",dst)
cv2.waitKey()

会使用到cv2.getRotationMatrix2D与cv2.warpAffine.

cv2.getRotationMatrix2D参数分别是中心,旋转角度以及缩放系数.

cv2.warpAffine是做仿射变换,

在这里插入图片描述

图像平移可以用于为模型添加平移不变性,因为通过平移,我们可以改变对象在图像中的位置,为模型提供更多的多样性,从而获得更好的可推广性,这在困难的条件下有效,即当对象没有完全对准图像中心时。这种增强技术还可以帮助模型正确地对具有部分可见对象的图像进行分类。以下图为例。即使图像中没有完整的鞋子,模型也应该能够将其分类为鞋子

1
2
3
4
5
M = np.float32([[1,0,-100],[0,1,-100]])
dst = cv2.warpAffine(img,M,(cols,rows))
plt.imshow(dst)
cv2.imshow("dst",dst)

image-20231123123137312

图像阈值

阈值分割是一种图像分割方法。它将像素值与阈值进行比较,并相应地进行更新。图像阈值的一个简单应用可以将图像划分为前景和背景,阈值只能应用于灰度图像。

image-20231123123310090

上面是简单阈值,此外还有自适应阈值

简单阈值是全局的,对于在不同区域具有不同照明条件的图像可能不太适用,此时可以使用自适应阈值处理。算法计算图像的局部阈值,在同一图像的不同区域获得不同的阈值,并为具有不同照明的图像提供了更好的结果。在自适应阈值的情况下,对图像的不同部分使用不同的阈值。该函数可为具有不同照明条件的图像提供更好的结果,因此被称为“自适应”。Otsu的二值化方法为整个图像找到一个最佳阈值。它适用于双峰图像(直方图中有2个峰值的图像)。

cv2.ADAPTIVE_THRESH_MEAN_C:阈值是邻域的平均值
cv2.ADAPTIVE_THRESH_GAUSSIAN_C:阈值是邻域值的加权和,其中权重是高斯窗口。
Block Size 决定邻域的大小。
C 从计算的平均值或加权平均值中减去常数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

#import the libraries
import numpy as np
import matplotlib.pyplot as plt
import cv2
%matplotlib inline

#ADAPTIVE THRESHOLDING
gray_image = cv2.imread('index.png',0)

ret,thresh_global = cv2.threshold(gray_image,127,255,cv2.THRESH_BINARY)
#here 11 is the pixel neighbourhood that is used to calculate the threshold value
thresh_mean = cv2.adaptiveThreshold(gray_image,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,2)

thresh_gaussian = cv2.adaptiveThreshold(gray_image,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2)

names = ['Original Image','Global Thresholding','Adaptive Mean Threshold','Adaptive Gaussian Thresholding']
images = [gray_image,thresh_global,thresh_mean,thresh_gaussian]

for i in range(4):
plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
plt.title(names[i])
plt.xticks([]),plt.yticks([])

plt.show()

image-20231123135259991

图像分割

图像分割是将图像中的每个像素分类到某个类别的任务。例如,将每个像素分类为前景或背景。图像分割对于从图像中提取相关部分是重要的。

分水岭算法是一种经典的图像分割算法。它将图像中的像素值视为地形。为了找到对象边界,它将初始标记作为输入。然后,该算法开始从标记淹没盆地(flooding the basin from the markers),直到标记在对象边界相遇。

watershed algorithm

位操作

按位运算包括AND、OR、NOT和XOR。在计算机视觉中,当我们有一个遮罩图像并想将该遮罩应用于另一个图像以提取感兴趣的区域时,这些操作非常有用。

image-20231123161116735

image-20231123161520256

边缘检测

边缘是图像中图像亮度急剧变化或具有不连续性的点。这种不连续性通常对应于:

  • 深度不连续
  • 表面方向的不连续性
  • 材料特性的变化
  • 场景照明的变化

边缘是图像的非常有用的特征,可以用于不同的应用,如图像中对象的分类和定位。甚至深度学习模型也会计算边缘特征,以提取图像中存在的对象的信息。

image-20231123161625316

1
2
3
4
5
6
7
8
9
import cv2
import numpy as np

img = cv2.imread("../imgs/00000.png")

edges = cv2.Canny(img, 100, 200)

cv2.imshow("edges", edges)
cv2.waitKey()

图像滤波

在图像滤波中,使用像素值的相邻值来更新像素值。但是,这些值最初是如何更新的呢?,有多种更新像素值的方法,例如从邻居中选择最大值,使用邻居的平均值等。每种方法都有自己的用途。例如,对邻域中的像素值取平均值用于图像模糊。

高斯滤波也用于图像模糊,其根据相邻像素与所考虑像素的距离为相邻像素赋予不同的权重。对于图像过滤,我们使用内核。核是不同形状的数字矩阵,如3 x 3、5 x 5等。核用于计算图像一部分的点积。当计算像素的新值时,内核中心与像素重叠。相邻像素值与内核中的相应值相乘。计算出的值被分配给与内核中心重合的像素。

img

image-20231123161852790

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import numpy as np
import cv2

image = cv2.imread('../imgs/test.png')
kernel = np.ones((5,5),np.float32)/25
#using the averaging kernel for image smoothening
averaging_kernel = np.ones((3,3),np.float32)/9
filtered_image = cv2.filter2D(image,-1,kernel)
cv2.imshow("avg_filtered_image",filtered_image)
#get a one dimensional Gaussian Kernel
gaussian_kernel_x = cv2.getGaussianKernel(5,1)
gaussian_kernel_y = cv2.getGaussianKernel(5,1)
#converting to two dimensional kernel using matrix multiplication
gaussian_kernel = gaussian_kernel_x * gaussian_kernel_y.T
#you can also use cv2.GaussianBLurring(image,(shape of kernel),standard deviation) instead of cv2.filter2D
filtered_image = cv2.filter2D(image,-1,gaussian_kernel)
cv2.imshow("filtered_image",filtered_image)
cv2.waitKey()

image-20231123170248409

上图的两个卷积核分别是

图像轮廓(contours)

轮廓是表示图像中对象边界的点或线段的闭合曲线。轮廓本质上是图像中对象的形状。与边缘不同,轮廓不是图像的一部分。相反,它们是与图像中对象的形状相对应的点和线段的抽象集合。我们可以使用轮廓来计算图像中对象的数量,根据对象的形状对其进行分类,或者从图像中选择特定形状的对象。

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np
import cv2
import matplotlib.pyplot as plt
image = cv2.imread('../imgs/test.png')
#converting RGB image to Binary
gray_image = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray_image,127,255,0)
#calculate the contours from binary image
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
with_contours = cv2.drawContours(image,contours,-1,(0,255,0),3)
plt.imshow(with_contours[...,::-1])
plt.show()

image-20231123163932600

特征匹配

使用SIFT或SURF从不同图像中提取的特征可以进行匹配,以找到存在于不同图像中的相似对象/模式。OpenCV库支持多种特征匹配算法,如brute force 匹配、knn特征匹配等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

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

#reading images in grayscale format
image1 = cv2.imread('../imgs/00000.png',0)

image2 = cv2.warpAffine(image1, np.float32([[1, 0, 100], [0, 1, -100]]), (image1.shape[1], image1.shape[0]))

sift = cv2.xfeatures2d.SIFT_create()
#finding out the keypoints and their descriptors
keypoints1,descriptors1 = sift.detectAndCompute(image1,None)
keypoints2,descriptors2 = sift.detectAndCompute(image2,None)

#matching the descriptors from both the images
bf = cv2.BFMatcher()
matches = bf.knnMatch(descriptors1,descriptors2,k = 2)


#selecting only the good features
good_matches = []
for m,n in matches:
if m.distance < 0.75*n.distance:
good_matches.append([m])
image3 = cv2.drawMatchesKnn(image1,keypoints1,image2,keypoints2,good_matches,None,flags=2)
cv2.imshow("image3",image3)
cv2.waitKey()

image-20231123165033904

img

在上面的图像中,我们可以看到从原始图像(左侧)中提取的关键点与其旋转版本的关键点相匹配。这是因为特征是使用SIFT提取的,SIFT对这种变换是不变的。

人脸检测

OpenCV支持基于haar级联的对象检测。Haar级联是基于机器学习的分类器,用于计算图像中的不同特征,如边缘、线条等。然后,这些分类器使用多个正样本和负样本进行训练。OpenCV Github仓库中提供了针对人脸、眼睛等不同对象的经过训练的分类器,也可以针对任何对象训练自己的haar级联。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#import required libraries
import numpy as np
import cv2
import matplotlib.pyplot as plt

#load the classifiers downloaded
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml')
#read the image and convert to grayscale format
img = cv2.imread('rotated_face.jpg')
gray = cv2.cvtColor(img, cv.COLOR_BGR2GRAY)
#calculate coordinates
faces = face_cascade.detectMultiScale(gray, 1.1, 4)
for (x,y,w,h) in faces:
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
roi_gray = gray[y:y+h, x:x+w]
roi_color = img[y:y+h, x:x+w]
eyes = eye_cascade.detectMultiScale(roi_gray)
#draw bounding boxes around detected features
for (ex,ey,ew,eh) in eyes:
cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)
#plot the image
plt.imshow(img)
#write image
cv2.imwrite('face_detection.jpg',img)

很多级联器的xml文件都是直接拿别人的,网上也有训练的教程.

图像梯度向量

image gradient vector

图像梯度矢量被定义为每个单独像素的度量,包含x轴和y轴上的像素颜色变化。该定义与连续多变量函数的梯度一致,该函数是所有变量的偏导数的向量。

边缘检测算子

Sharpening An Image  2

prewitt

Prewitt算子不是只依赖于四个直接相邻的邻居,而是利用八个周围的像素来获得更平滑的结果。

image-20231123095504365

sobel

为了更加强调直接相邻像素的影响,它们被分配了更高的权重。

image-20231123172141630

角点检测

角点检测(Corner Detection)是计算机视觉系统中用来获得图像特征的一种方法,广泛应用于运动检测、图像匹配、视频跟踪、三维建模和目标识别等领域中。也称为特征点检测。 角点通常被定义为两条边的交点,更严格的说,角点的局部邻域应该具有两个不同区域的不同方向的边界。而实际应用中,大多数所谓的角点检测方法检测的是拥有特定特征的图像点,而不仅仅是“角点”。这些特征点在图像中有具体的坐标,并具有某些数学特征,如局部最大或最小灰度、某些梯度特征等

Harris

常用特征

SIFT

关键点是处理图像时应该注意的一个概念。这些基本上是图像中的兴趣点。关键点类似于给定图像的特征。它们是定义图像中有趣内容的位置。关键点很重要,因为无论图像如何修改(旋转、收缩、扩展、失真),我们都会为图像找到相同的关键点。

尺度不变特征变换(SIFT)是一种非常流行的关键点检测算法。它包括以下步骤:

  • Scale-space extrema detection
  • Keypoint localization
  • Orientation assignment
  • Keypoint descriptor
  • Keypoint matching

从SIFT提取的特征可用于图像拼接、对象检测等应用。下面的代码和输出显示了使用SIFT计算的关键点及其方向。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#import required libraries
import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
#show OpenCV version
print(cv2.__version__)
#read the iamge and convert to grayscale
image = cv2.imread('index.png')
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
#create sift object
sift = cv2.xfeatures2d.SIFT_create()
#calculate keypoints and their orientation
keypoints,descriptors = sift.detectAndCompute(gray,None)
#plot keypoints on the image
with_keypoints = cv2.drawKeypoints(gray,keypoints)
#plot the image
plt.imshow(with_keypoints)

SURF

Speeded Up Robust Features(SURF)是SIFT的增强版。它的工作速度要快得多,并且对图像转换更健壮。

在SIFT中,使用高斯拉普拉斯算子来近似尺度空间。拉普拉斯算子是用于计算图像边缘的核。拉普拉斯核通过近似图像的二阶导数来工作。因此,它对噪声非常敏感。我们通常将高斯核应用于拉普拉斯核之前的图像,因此将其命名为高斯拉普拉斯

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#import required libraries
import cv2
import numpy as np
import matplotlib.pyplot as plt
#show OpenCV version
print(cv2.__version__)
#read image and convert to grayscale
image = cv2.imread('index.png')
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
#instantiate surf object
surf = cv2.xfeatures2d.SURF_create(400)
#calculate keypoints and their orientation
keypoints,descriptors = surf.detectAndCompute(gray,None)

with_keypoints = cv2.drawKeypoints(gray,keypoints)

plt.imshow(with_keypoints)

HOG

面向梯度直方图(HOG)是一种从像素颜色中提取特征的有效方法,用于构建对象识别分类器。

参考资料

综述

  1. Object Detection in 2023: The Definitive Guide - viso.ai
  2. [1905.05055] Object Detection in 20 Years: A Survey (arxiv.org)
  3. [2104.11892] A Survey of Modern Deep Learning based Object Detection Models (arxiv.org)
  4. A comprehensive review of object detection with deep learning - ScienceDirect

博客

  1. Object Detection for Dummies Part 1: Gradient Vector, HOG, and SS | Lil’Log (lilianweng.github.io)
  2. A Beginner’s Guide to Image Processing With OpenCV and Python (analyticsvidhya.com)
  3. 也许还不错的学习网站PyImageSearch - You can master Computer Vision, Deep Learning, and OpenCV.
  4. 维基百科 卷积核Kernel (image processing) - Wikipedia)
-------------本文结束感谢您的阅读-------------
感谢阅读.

欢迎关注我的其它发布渠道