计算机视觉——python实现花的分类

新建一个rbghistogram.py文件

import cv2 
class RGBHistogram:

def __init__(self,bins):
# store the number of bins the histogram will use
self.bins = bins
def describe(self,image,mask=None):
# compute a 3D histogram in the RGB colorspace,
# then normalize the histogram so that images
# with the same content,but either scaled larger
# or smaller will have(roughly) the same histogram
hist = cv2.calcHist([image],[0,1,2],
mask,self.bins,[0,256,0,256,0,256])
cv2.normalize(hist,hist)
# return out 3D histogram as a flattened array
return hist.flatten()

我们首先导入cv2,这是我们需要创建图像描述符的唯一的package。

然后,我们定义了RGBHistogram类,用于封装花卉图像的量化方式。__init__方法只接受一个参数——一个包含3D直方图的bins的列表。

描述图像将由describe方法处理,该方法接收两个参数,一个将构建颜色直方图的图像,以及一个可选的mask。如果我们提供mask,则只有与mask区域相关联的像素将用于构造直方图。这允许我们仅描述图像的花瓣,忽略图像的其余部分(即,背景,其与花本身无关)。

接着,构造直方图。calcHist函数的第一个参数是我们想要描述的图像的列表,该函数具体的参数请参考前面的文章。然后将生成的图像进行标准化,并以特征向量返回。

注意:cv2.normalize函数在OpenCV 2.4.X和OpenCV 3.0之间略有不同。 在OpenCV 2.4.X中,cv2.normalize函数实际上会返回规范化的直方图。 但是,在OpenCV 3.0+中,cv2.normalize实际上对函数内的直方图进行了规范化,并更新了传入的第二个参数(即“输出”)。这是一个微妙但重要的区别,在使用这两个参数时要记住 OpenCV版本.

现在已经定义了图像描述符,我们可以创建代码来对给定花朵的物种进行分类:

from __future__ import print_function
from preprocess import RGBHistogram
from sklearn.preprocessing import LabelEncoder
from sklearn.ensemble import RandomForestClassifier
from sklearn.cross_validation import train_test_split
from sklearn.metrics import classification_report
import numpy as np
import argparse
import glob
import cv2
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--images", required = True,
help = "path to the image dataset")
ap.add_argument("-m", "--masks", required = True,
help = "path to the image masks")
args = vars(ap.parse_args())

我们首先导入必要的package。我们首先导入了RGBHistogram用于描述我们的每个图像。

然后导入scikit-learn库的LabelEncoder类。为了构建机器学习分类器以区分花种,我们首先需要一种方法来编码与每个花类相关联的“类标签”。我们希望将向日葵,番红花,雏菊和三色紫罗兰区分开来,但为了构建机器学习模型,这些种类(以字符串表示的)需要转换为整数。LabelEncoder类就是用来干这件事的。

我们使用的实际分类模型是RandomForestClassifier。随机森林是用于分类的集成学习方法,由多个决策树组成。

对于随机森林中的每棵树,构建一个自举(替换采样)样本,通常由66%的数据集组成。然后,基于自举样本构建决策树。在树中的每个节点处,仅采用预测变量的样本来计算节点分割标准。通常使用sqrt(n)预测变量,其中n是特征空间中预测变量的数量。然后重复该过程以训练森林中的多棵树(关于随机森林分类器的详细内容超出了本文的范围,有兴趣的可以参考机器学习方法)。

但是,如果您是使用机器学习的新手,随机森林是一个很好的起点,特别是在计算机视觉领域,他们只需很少的努力即可获得更高的精度。同样,虽然这不适用于所有计算机视觉分类问题,但随机森林是获得基线准确度的良好起点。

然后我们从scikit-learn导入train_test_split函数。在构建机器学习模型时,我们需要两组数据:训练集(training set)和测试(testing set)(或验证(validation set))集。

我们使用training data对机器学习模型进行训练(在这种情况下,我们使用随机森林学习模型)。然后使用testing data对模型进行评估。

保持这两组是独一无二的非常重要,因为它允许在尚未看到的数据点上评估模型。如果模型已经看到了数据点,那么结果是有偏见的,因为它具有不公平的优势!

最后,我们使用NumPy进行数值处理,使用argparse来解析命令行参数,使用glob来抓取磁盘上的图像路径,使用cv2进行OpenCV绑定。

接着我们需要两个命令行参数:--images,指向包含其花图像的目录,--mask,指向包含mask鲜花的目录。这些mask使我们只能专注于我们想要描述的花朵部分(即花瓣),忽略背景和其他杂乱,否则会扭曲特征向量并插入不需要的噪音。

更多关于此数据集请参考Flowers

# grab the image and mask paths 
imagePaths = sorted(glob.glob(args["images"] + "\\*.png"))
maskPaths = sorted(glob.glob(args["masks"] + "\\*.png"))
# initialize the list of data and class label targets
data = []
target = []
# initialize the image descriptor
desc = RGBHistogram([8,8,8])
# loop over the image and mask paths
for (imagePath,maskPath) in zip(imagePaths,maskPaths):
# load the image and mask
image = cv2.imread(imagePath)
mask = cv2.imread(maskPath)
mask = cv2.cvtColor(mask,cv2.COLOR_BGR2GRAY)
# describe the image
features = desc.describe(image,mask)
# update the list of data and targets
data.append(features)
target.append(imagePath.split("_")[-2])

我们使用glob来分别抓住我们的图像和mask的路径。通过传入包含图像的目录,然后是通配符*.png,我们能够快速构建图像路径列表。

接着,我们简单地初始化数据矩阵和类标签列表(即花的种类)。

然后实例化我们的图像描述符——每个通道有8个bins的3D RGB颜色直方图。该图像描述符将产生用于表征花的颜色的8×8×8=512维特征向量。

接着我们开始在我们的图像和mask上循环。我们将图像和mask从磁盘中加载进来,然后在、将mask转换为灰度。

接着应用我们的3D RGB颜色直方图产生我们的特征向量,然后将其存储在数据矩阵中。

然后解析花的种类,并更新target列表。

现在我们可以应用我们的机器学习方法了。

# grab the unique target names and encode the labels 
targetNames = np.unique(target)
le = LabelEncoder()
target = le.fit_transform(target)
# construct the training and testing splits
(trainData,testData,trainTarget,testTarget) = train_test_split(data,target,
test_size=0.3,random_state = 42)
# train the classifier
model = RandomForestClassifier(n_estimators=25,random_state=84)
model.fit(trainData,trainTarget)
# evaluate the classifier
print(classification_report(testTarget,model.predict(testData),
target_names=targetNames))

首先,我们给我们的类标签进行编码。NumPy的unique方法用于查找唯一的species名称,然后将其输入LabelEncoder。调用fit_transform将“唯一”物种名称“拟合(fits)”为整数,一个species对应于一个category,然后将字符串“转换(transform)”为相应的整数类。target变量现在包含一个整数列表,每个数据点对应一个整数列表,其中每个整数映射到一个花种名称。

接着,我们开始构建我们的训练和测试集。我们将使用train_test_split函数。我们需要传递我们数据矩阵和target列表,指定测试数据集是整个数据集大小的30%。使用伪随机状态42,以便我们可以在以后的运行中重现我们的结果。

调用RandomForestClassifier函数,使用森林中的25个决策树进行训练。同样,明确使用伪随机状态,以便我们的结果是可重复的。

然后使用classification_report函数打印出我们的模型的准确性。我们将实际testing targets作为第一个参数传递,然后让模型预测它认为花种对测试数据的影响。然后,classification_report函数将预测与真实targets进行比较,并为整个系统和每个单独的类别标签打印准确度报告。

为了进一步研究分类,我们定义了以下代码:

# loop over a sample of the images 
for i in np.random.choice(np.arange(0,len(imagePaths)),10):
# grab the image and mask paths
imagePath = imagePaths[i]
maskPath = maskPaths[i]
# load the image and mask
image = cv2.imread(imagePath)
mask = cv2.imread(maskPath)
mask = cv2.cvtColor(mask,cv2.COLOR_BGR2GRAY)
# describe the image
features = desc.describe(image,mask)
# predict what type of flower the image is
flower = le.inverse_transform(model.predict([features]))[0]
print(imagePath)
print("I think this flower is a {}".format(flower.upper()))
cv2.imshow("image",image)

cv2.waitKey(0)

我们首先从所有图片里面随机挑选10张不同的图像进行调查,然后获取对应的图片和mask的路径。

然后我们将图片和mask的路径加载进来。并将mask图片转换为灰度图像。

然后,我们利用describe提取特征向量,以表征花的颜色。

我们查询我们的随机森林分类器以确定花的种类,然后将其打印到控制台并屏幕上显示。

最后执行我们的脚本程序:

python classify.py --image dataset\images --mask dataset\masks

运行结果

计算机视觉——python实现花的分类

计算机视觉——python实现花的分类

博客地址(有完整代码):https://0leo0.github.io/2018/case_study_06.html

关注不迷路哦!!!


分享到:


相關文章: