详解OpenCV实现特征提取的方法

目录
  • 前言
  • 1. 颜色
  • 2. 形状
  • 3. 纹理
    • a. GLCM
    • b.  LBP
  • 结论

前言

如何从图像中提取特征?第一次听说“特征提取”一词是在 YouTube 上的机器学习视频教程中,它清楚地解释了我们如何在大型数据集中提取特征。

很简单,数据集的列就是特征。然而,当我遇到计算机视觉主题时,当听说我们将从图像中提取特征时,吃了一惊。是否开始浏览图像的每一列并取出每个像素?

一段时间后,明白了特征提取在计算机视觉中的含义。特征提取是降维过程的一部分,其中,原始数据的初始集被划分并减少到更易于管理的组。

简单来说,对于图像,每个像素都是一个数据,图像处理所做的只是从图像中提取有用的信息,从而减少了数据量,但保留了描述图像特征的像素。

图像处理所做的只是从图像中提取有用的信息,从而减少数据量,但保留描述图像特征的像素。

在本文中,让我们探索几种从图像中提取颜色、形状和纹理特征的方法。这些方法基于处理图像的经验,如果有任何错误,请随时添加或纠正它们!

1. 颜色

每次处理图像项目时,色彩空间都会自动成为最先探索的地方。了解设置图像环境的色彩空间对于提取正确的特征至关重要。

使用 OpenCV,我们可以将图像的颜色空间转换为提供的几个选项之一,如 HSV、LAB、灰度、YCrCb、CMYK 等。每个颜色空间的简单分解:

a. HSV(色相饱和度值)

色调:描述主波长,是指定颜色的通道

饱和度:描述色调/颜色的纯度/色调

:描述颜色的强度

import cv2
from google.colab.patches import cv2_imshow

image = cv2.imread(image_file)
hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
cv2_imshow(hsv_image)

RGB 与 HSV 颜色空间

b. LAB

L:描述颜色的亮度,与强度互换使用

A : 颜色成分范围,从绿色到品红色

B:从蓝色到黄色的颜色分量

import cv2
from google.colab.patches import cv2_imshow

image = cv2.imread(image_file)
lab_image = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)
cv2_imshow(lab_image)

RGB 与 LAB 色彩空间

YCrCb

Y : 伽马校正后从 RGB 颜色空间获得的亮度

Cr:描述红色 (R) 分量与亮度的距离

Cb:描述蓝色 (B) 分量与亮度的距离

import cv2
from google.colab.patches import cv2_imshow

image = cv2.imread(image_file)
ycrcb_image = cv2.cvtColor(image, cv2.COLOR_BGR2YCrCb)
cv2_imshow(ycrcb_image)

RGB 与 YCrCb 颜色空间

这些颜色空间的重要性有时会被低估。为了从图像中获得相关信息,这些颜色空间提供了一个机会来识别特征是否在每个图像中看起来更不同。关于色彩空间最疯狂的事情是我们可以用不同的色彩空间执行加法/减法,结果你会感到惊讶!

探索图像色彩空间的另一个有用函数是简单地使用*numpy.mean()*,它给出图像数据集中色彩空间中每个通道的平均值。如果我们想查看颜色空间中的哪个通道主导数据集,这将特别有用。

import cv2
from google.colab.patches import cv2_imshow
import numpy as np
import plotly.figure_factory as ff

# Check the distribution of red values
red_values = []
for i in range(len(images)):
  red_value = np.mean(images[i][:, :, 0])
  red_values.append(red_value)

# Check the distribution of green values
green_values = []
for i in range(len(images)):
  green_value = np.mean(images[i][:, :, 1])
  green_values.append(green_value)

# Check the distribution of blue values
blue_values = []
for i in range(len(images)):
  blue_value = np.mean(images[i][:, :, 2])
  blue_values.append(blue_value)

# Plotting the histogram
fig = ff.create_distplot([red_values, green_values, blue_values], group_labels=["R", "G", "B"], colors=['red', 'green', 'blue'])
fig.update_layout(showlegend=True, template="simple_white")
fig.update_layout(title_text='Distribution of channel values across images in RGB')
fig.data[0].marker.line.color = 'rgb(0, 0, 0)'
fig.data[0].marker.line.width = 0.5
fig.data[1].marker.line.color = 'rgb(0, 0, 0)'
fig.data[1].marker.line.width = 0.5
fig.data[2].marker.line.color = 'rgb(0, 0, 0)'
fig.data[2].marker.line.width = 0.5
fig

一旦我们已经识别或探索了足够多的图像色彩空间,并确定我们只对单个通道感兴趣,我们就可以使用*cv2.inRange()*来屏蔽不需要的像素。这在 HSV 颜色空间中尤其实用。

import cv2
from google.colab.patches import cv2_imshow

# Reading the original image
image_spot = cv2.imread(image_file)
cv2_imshow(image_spot)

# Converting it to HSV color space
hsv_image_spot = cv2.cvtColor(image_spot, cv2.COLOR_BGR2HSV)
cv2_imshow(hsv_image_spot)

# Setting the black pixel mask and perform bitwise_and to get only the black pixels
mask = cv2.inRange(hsv_image_spot, (0, 0, 0), (180, 255, 40))
masked = cv2.bitwise_and(hsv_image_spot, hsv_image_spot, mask=mask)
cv2_imshow(masked)

RGB vs HSV vs Masked 图像使用 cv2.inRange() 检索黑点

有时,我们甚至可以使用*cv2.kmeans()来量化图像的颜色,从本质上将颜色减少到几个整洁的像素。根据我们的目标,我们可以使用cv2.inRange()*来检索目标像素。通常,这个函数在识别图像的重要部分时很有魅力,我总是会在继续使用其他颜色特征提取方法之前检查这个函数。

import cv2
from google.colab.patches import cv2_imshow

image_spot_reshaped = image_spot.reshape((image_spot.shape[0] * image_spot.shape[1], 3))

# convert to np.float32
Z = np.float32(image_spot_reshaped)
# define criteria, number of clusters(K) and apply kmeans()
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
K = 2
ret, label, center = cv2.kmeans(Z, K, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
# Now convert back into uint8, and make original image
center = np.uint8(center)
res = center[label.flatten()]
res2 = res.reshape((image_spot.shape))

cv2_imshow(res2)

使用 cv2.kmeans() 进行颜色量化 (K=2)

2. 形状

一旦我们充分探索了颜色特征,我们可能会在某个时候想要提取图像中的形状。

例如,你的任务是区分不同类型的酒杯。颜色在这里可能并不重要,但形状可以告诉我们很多关于它们的信息。

同样,我要做的是将图像转换为其他颜色空间,看看是否有任何颜色空间会使对象的边缘或形状更加突出。然后,我们可以使用*cv2.findContours()*来检索图像中的所有轮廓。从这里开始,我们将检查感兴趣轮廓的所有属性。

理想情况下,一旦我们能够提取定义轮廓形状的正确属性,我们会将其应用于数据集中的所有图像,提取的数字将成为我们新的非图像数据集。看看我们如何将数据量减少到只有一列形状特征,仍然可以解释我们的酒杯图像吗?

让我们探索一下我们可以使用 OpenCV 从轮廓中提取的许多属性。正如之前已经展示过的,我将在此处提供链接以供参考

  1. 轮廓面积
  2. 轮廓周长
  3. 轮廓近似
  4. 凸包
  5. 凸性检测
  6. 矩形边界
  7. 最小外接圆
  8. 拟合椭圆
  9. 拟合直线

在很多情况下发现 cv2.HoughCircles() 和 cv2.SimpleBlobDetector() 在检测圆圈时都没有给出准确的结果,原因之一可能是预处理图像中的圆圈不够明显。但是,cv2.SimpleBlobDetector() 仍然提供一些方便的内置过滤器,如惯性、凸性、圆度和面积,以尽可能准确地检索圆。

3. 纹理

在某些时候,我们可能想要提取纹理特征,因为我们已经用尽了颜色和形状特征。灰度共生矩阵(GLCM)和局部二值模式(LBP)都是我用过的纹理特征,不过大家常用的其他纹理特征也可以在下方评论,我很想知道!

a. GLCM

很难在图像方面特别理解 GLCM 的概念。从统计学上讲,GLCM 是一种考虑像素空间关系的纹理检查方法。它的工作原理是计算具有特定值和特定空间关系的像素对在图像中出现的频率,创建 GLCM,然后从该矩阵中提取统计度量。

包含 GLCM 功能的一个易于使用的包是scikit-image包。在 GLCM 中,我们还可以推导出一些描述更多关于纹理的统计数据,例如:

对比度:测量灰度共生矩阵的局部变化。

相关性:测量指定像素对的联合概率出现。

平方:提供 GLCM 中元素的平方和。也称为均匀性或角二阶矩。

同质性:测量 GLCM 中元素分布与 GLCM 对角线的接近程度。

import cv2
from google.colab.patches import cv2_imshow

image_spot = cv2.imread(image_file)
gray = cv2.cvtColor(image_spot, cv2.COLOR_BGR2GRAY)

# Find the GLCM
import skimage.feature as feature

# Param:
# source image
# List of pixel pair distance offsets - here 1 in each direction
# List of pixel pair angles in radians
graycom = feature.greycomatrix(gray, [1], [0, np.pi/4, np.pi/2, 3*np.pi/4], levels=256)

# Find the GLCM properties
contrast = feature.greycoprops(graycom, 'contrast')
dissimilarity = feature.greycoprops(graycom, 'dissimilarity')
homogeneity = feature.greycoprops(graycom, 'homogeneity')
energy = feature.greycoprops(graycom, 'energy')
correlation = feature.greycoprops(graycom, 'correlation')
ASM = feature.greycoprops(graycom, 'ASM')

print("Contrast: {}".format(contrast))
print("Dissimilarity: {}".format(dissimilarity))
print("Homogeneity: {}".format(homogeneity))
print("Energy: {}".format(energy))
print("Correlation: {}".format(correlation))
print("ASM: {}".format(ASM))

从灰度共生矩阵 (GLCM) 获得的特征

b.  LBP

由于已经有很多文章解释了本地二进制模式,在这里节省你的时间并在此处分享参考链接:

简而言之,LBP 是一种纹理算子,它通过对周围像素进行阈值处理并以二进制数表示它们来标记图像的像素。LBP 让我们吃惊的是,该操作返回的灰度图像清晰地显示了图像中的纹理。在这里,我们尝试根据理解分解LBP内部的操作:

对于每个中心像素,我们尝试与周围像素进行比较,如果中心像素大于或小于周围像素,则给它们一个标签。结果,我们周围有 8 个标签,并且通过在整个图像中保持顺时针或逆时针方向的一致模式,我们将它们布置在 2d 数组中并将它们转换为二进制数。

在我们对整个图像的每个像素执行操作后会出现这样的矩阵。

从这里,我们可以看到,生成的矩阵与我们的原始图像具有相同的形状,我们能够像绘制图像一样绘制和显示 LBP。

import cv2
from google.colab.patches import cv2_imshow

class LocalBinaryPatterns:
  def __init__(self, numPoints, radius):
    self.numPoints = numPoints
    self.radius = radius

  def describe(self, image, eps = 1e-7):
    lbp = feature.local_binary_pattern(image, self.numPoints, self.radius, method="uniform")
    (hist, _) = np.histogram(lbp.ravel(), bins=np.arange(0, self.numPoints+3), range=(0, self.numPoints + 2))

    # Normalize the histogram
    hist = hist.astype('float')
    hist /= (hist.sum() + eps)

    return hist, lbp

image = cv2.imread(image_file)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
desc = LocalBinaryPatterns(24, 8)
hist, lbp = desc.describe(gray)
print("Histogram of Local Binary Pattern value: {}".format(hist))

contrast = contrast.flatten()
dissimilarity = dissimilarity.flatten()
homogeneity = homogeneity.flatten()
energy = energy.flatten()
correlation = correlation.flatten()
ASM = ASM.flatten()
hist = hist.flatten()

features = np.concatenate((contrast, dissimilarity, homogeneity, energy, correlation, ASM, hist), axis=0)
cv2_imshow(gray)
cv2_imshow(lbp)

灰度图像与 LBP 表示

类似地,我们可以将 LBP 存储在直方图中,并将其视为一个特征,我们可以将其输入分类器以进行分类。PyImageSearch 的 Adrian Rosebrock 在这方面做了一个惊人的例子!

我在纹理特征方面没有太多经验,但是在收集更多信息并尝试在项目中实现它们之后,我有兴趣深入研究它。

结论

总而言之,在这篇文章中,分享了在之前的项目中使用过的三个特征的经验,主要是颜色、形状和纹理特征。连同代码和结果,试图说明我采取每一步的原因。

到此这篇关于详解OpenCV实现特征提取的方法的文章就介绍到这了,更多相关OpenCV特征提取内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • OpenCV特征提取与检测之Harris角点检测

    目录 前言 1. 效果图 2. 原理 3. 源码 3.1 Harris角点检测 3.2 精细角点检测 总结 前言 这篇博客将了解什么是特征,角点,哈里斯角点检测(Harris Corner Detection)的概念.并使用cv2.cornerHarris(),cv2.cornerSubPix()实现哈里斯角点检测: 1. 效果图 原图 VS Harris角点检测效果图如下: 原图 VS Harris角点检测效果图如下: 惊细角点效果图如下:Harris角点用红色像素标记,精细角点用绿色像素标记

  • opencv-python 提取sift特征并匹配的实例

    我就废话不多说,直接上代码吧! # -*- coding: utf-8 -*- import cv2 import numpy as np from find_obj import filter_matches,explore_match from matplotlib import pyplot as plt def getSift(): ''' 得到并查看sift特征 ''' img_path1 = '../../data/home.jpg' #读取图像 img = cv2.imread(i

  • OpenCV特征提取与检测之Shi-Tomasi角点检测器

    前言 角点通常被定义为两条边的交点,或者说,角点的局部邻域应该具有两个不同区域的不同方向的边界.角点检测(Corner Detection)是计算机视觉系统中获取图像特征的一种方法,广泛应用于运动检测.图像匹配.视频跟踪.三维重建和目标识别等,也可称为特征点检测. 角点检测算法的基本思想: 使用一个固定窗口在图像上进行任意方向上的滑动,比较滑动前与滑动后两种情况,窗口中的像素灰度变化程度,如果存在任意方向上的滑动,都有着较大灰度变化,那么我们可以认为该窗口中存在角点. 目前,角点检测算法还不是十

  • opencv2基于SURF特征提取实现两张图像拼接融合

    本文实例为大家分享了opencv2实现两张图像拼接融合的具体代码,供大家参考,具体内容如下 要用到两个文件,estimate.cpp和matcher.h(在有关鲁棒匹配这篇博文中有) estimate.cpp的头文件也需要添加一些东西才行,以下是对的,已经成功运行. 加了using namespace std;之后,cv::可以去掉了. estimate.cpp: #include <iostream> #include <vector> #include <opencv2/

  • python利用opencv实现SIFT特征提取与匹配

    本文实例为大家分享了利用opencv实现SIFT特征提取与匹配的具体代码,供大家参考,具体内容如下 1.SIFT 1.1.sift的定义 SIFT,即尺度不变特征变换(Scale-invariant feature transform,SIFT),是用于图像处理领域的一种描述.这种描述具有尺度不变性,可在图像中检测出关键点,是一种局部特征描述子. 1.2.sift算法介绍 SIFT由David Lowe在1999年提出,在2004年加以完善 .SIFT在数字图像的特征描述方面当之无愧可称之为最红

  • Python + OpenCV 实现LBP特征提取的示例代码

    背景 看了些许的纹理特征提取的paper,想自己实现其中部分算法,看看特征提取之后的效果是怎样 运行环境 Mac OS Python3.0 Anaconda3(集成了很多包,浏览器界面编程,清爽) 步骤 导入包 from skimage.transform import rotate from skimage.feature import local_binary_pattern from skimage import data, io,data_dir,filters, feature fro

  • 详解OpenCV实现特征提取的方法

    目录 前言 1. 颜色 2. 形状 3. 纹理 a. GLCM b.  LBP 结论 前言 如何从图像中提取特征?第一次听说“特征提取”一词是在 YouTube 上的机器学习视频教程中,它清楚地解释了我们如何在大型数据集中提取特征. 很简单,数据集的列就是特征.然而,当我遇到计算机视觉主题时,当听说我们将从图像中提取特征时,吃了一惊.是否开始浏览图像的每一列并取出每个像素? 一段时间后,明白了特征提取在计算机视觉中的含义.特征提取是降维过程的一部分,其中,原始数据的初始集被划分并减少到更易于管理

  • 详解OpenCV执行连通分量标记的方法和分析

    目录 1.OpenCV 连通分量标记和分析 1.1 OpenCV 连通分量标记和分析函数 1.2 项目结构 2.案例实现 2.1 使用 OpenCV 实现基本的连通分量标记 2.2 完整代码 2.3 过滤连通分量 2.4 C++代码案例 在本教程中,您将学习如何使用 OpenCV 执行连通分量标记和分析.具体来说,我们将重点介绍 OpenCV 最常用的连通分量标记函数:cv2.connectedComponentsWithStats. 连通分量标记(也称为连通分量分析.斑点提取或区域标记)是图论

  • 详解opencv去除背景算法的方法比较

    目录 背景减除法 (1)BackgroundSubtractorMOG (2)BackgroundSubtractorMOG2 (3)BackgroundSubtractorGMG 帧差法 最近做opencv项目时,使用肤色分割的方法检测目标物体时,背景带来的干扰非常让人头痛.于是先将背景分割出去,将影响降低甚至消除.由于初次接触opencv,叙述不当的地方还请指正. 背景减除法 (以下文字原文来源于https://docs.opencv.org/3.4.7/d8/d38/tutorial_bg

  • 详解OpenCV自适应直方图均衡化的应用

    目录 介绍 主要代码 比较 CLAHE 和直方图均衡化 介绍 在<直方图均衡化详解>中,我们已经了解的直方图均衡化的基本概念,并且可以使用 cv2.equalizeHist() 函数执行直方图均衡. 在本节中,将介绍如何应用对比度受限的自适应直方图均衡化 ( Contrast Limited Adaptive Histogram Equalization, CLAHE ) 来均衡图像,CLAHE 是自适应直方图均衡化( Adaptive Histogram Equalization, AHE

  • 详解Java 本地接口 JNI 使用方法

    详解Java 本地接口 JNI 使用方法 对于Java程序员来说,Java语言的好处和优点,我想不用我说了,大家自然会说出很多一套套的.但虽然我们作为java程序员,但我们不得不承认java语言也有一些它本身的缺点.比如在性能.和底层打交道方面都有它的缺点.所以java就提供了一些本地接口,他主要的作用就是提供一个标准的方式让java程序通过虚拟机与原生代码进行交互,这也就是我们平常常说的java本地接口(JNI--java native Interface).它使得在 Java 虚拟机 (VM

  • 详解jQuery中ajax.load()方法

    jQuery load() 方法 jQuery load() 方法是简单但强大的 AJAX 方法. load() 方法从服务器加载数据,并把返回的数据放入被选元素中. 语法: $(selector).load(URL,data,callback); load()函数用于从服务器加载数据,并使用返回的html内容替换当前匹配元素的内容. load()函数默认使用GET方式,如果提供了对象形式的数据,则自动转为POST方式. 因为默认使用的是Get请求方式,所以我们也可以在url加数据进行提交. 例

  • 详解vue beforeEach 死循环问题解决方法

    什么是beforeEach? beforeEach 是一个vue-router的路由导航钩子,一般我用它做路由守卫. 什么是路由守卫? 路由跳转前做一些验证,比如登录验证,是网站中的普遍需求.对此,vue-route 提供的beforeRouteUpdate可以方便地实现导航守卫(navigation-guards).导航守卫(navigation-guards)这个名字,听起来怪怪的,但既然官方文档是这样翻译的,就姑且这么叫吧.** 文档地址:https://router.vuejs.org/

  • 详解ES6新增字符串扩张方法includes()、startsWith()、endsWith()

    当有人问到用来确定一个字符串是否包含在另一个字符串中有哪些方法时,我们会不假思索回答道:indexOf方法.其实,ES6 又提供了三种新方法includes().startsWith().endsWith(),也是比较好用的. indexOf方法在这里就不多说了,大家都比较熟悉,意思就是:返回给定元素在数组中第一次出现的位置,返回结果是匹配开始的位置,如果没有出现则返回-1. 下面详细介绍ES6新增的这三种方法: ①includes():返回布尔值,表示是否找到了参数字符串. 如下所示: let

  • Python pandas 列转行操作详解(类似hive中explode方法)

    最近在工作上用到Python的pandas库来处理excel文件,遇到列转行的问题.找了一番资料后成功了,记录一下. 1. 如果需要爆炸的只有一列: df=pd.DataFrame({'A':[1,2],'B':[[1,2],[1,2]]}) df Out[1]: A B 0 1 [1, 2] 1 2 [1, 2] 如果要爆炸B这一列,可以直接用explode方法(前提是你的pandas的版本要高于或等于0.25) df.explode('B') A B 0 1 1 1 1 2 2 2 1 3

  • 详解Android aidl的使用方法

    AIDL是Android中IPC(Inter-Process Communication)方式中的一种,AIDL是Android Interface definition language的缩写(对于小白来说,AIDL的作用是让你可以在自己的APP里绑定一个其他APP的service,这样你的APP可以和其他APP交互.) AIDL只是Android中众多进程间通讯方式中的一种方式, AIDL和Messenger的区别: Messenger不适用大量并发的请求:Messenger以串行的方式来处

随机推荐