烟雾检测(1)HOG+SVM 检测

前言

作为一个普通的研一学生,之前没有做过图像处理的课题,只是简单接触过opencv和python,是在此方向是个纯小白。但是模式识别课程需要做一个烟雾检测的大作业,而老师只是讲orb、hog、lbp算法的原理,根本不知道怎么实现,毫无头绪。国庆节假期期间,在csdn上查阅了许多大佬的文章,终于有些进展。现分享我的些许成果,其中有很多不正之处,望见谅。

效果如下,将下图喂到test程序内可得img1所示输出。

烟雾检测(1)HOG+SVM 检测_第1张图片

烟雾检测(1)HOG+SVM 检测_第2张图片

本篇为大作业完成过程的第一篇,后续内容会陆续发布。

大作业要求

报告的主题是video based smoke detection,四人一组,一组交一份报告。

预先提供train、test两个数据集,内部有smoke和non两个文件夹,文件夹内有若干100*100大小的图片。

报告内容包括四部分:1、特征表示;2、降维及聚类;3、分类;4、模型评价及选择。

注:特征表示要从ORB、HOG、LBP算法中至少选择一种,还要使用CNN算法提取特征对比

(还有其他要求,不过上课时记得笔记丢失,只记得这一条)

图片预处理

拿到图片集后,发现图片的是这样的(部分图片)。图片大小的统一的,都是100*100,但是图片的名字命名规则缺没有规律(也可能是有我没发现的规律), 图片读取十分不方便。

烟雾检测(1)HOG+SVM 检测_第3张图片

全选图片后,对任一个图片重命名,图片集实现了批量图片重命名,得到如下图所示的图片集:

烟雾检测(1)HOG+SVM 检测_第4张图片

 可以看出所有图片的名字得到统一化,接下来通过程序读取图片集就变得简单啦。

 以下是代码分析

训练集内所有烟雾图片和无烟雾图片分别读取到pos_list和neg_list列表内

PosNum = 688
NegNum = 817
pos_path = 'train\\smoke_mqa\\'
neg_path = 'train\\non_mqa\\'


#导入正、负图片集
for i in range(0,PosNum):
    fileName = pos_path+'yw ('+str(i+1)+').jpg'
    img  = cv2.imread(fileName)
    pos_list.append(img) 

for i in range(0,NegNum):
    fileName =neg_path+'no_yw ('+str(i+1)+').jpg'
    img = cv2.imread(fileName)
    neg_list.append(img)

将pos_list和neg_list列表内的图片通过computeHOGs函数HOG特征提取、整合、存储到gradient_list列表内,然后根据正负图片集生产图片集标签,标签信息存储到labels列表内。 

#添加图片集标签    
computeHOGs(pos_list,gradient_list,wsize=(100,100))
for _ in range(len(pos_list)):
    labels.append(+1)
    
computeHOGs(neg_list,gradient_list,wsize=(100,100))
for _ in range(len(neg_list)):
    labels.append(-1)

HOG特征提取

HOG算法提取的图像形状特征:

1)灰度化处理图片;

2)采用Gamma校正法对输入图像进行颜色空间的标准化;

3)计算图像每个像素的梯度,将像素的梯度方向在0-360°平均划分为n个bins;

4)将图像换分为小的细胞单元(cell),每个cell有唯一的梯度特征向量,每个cell大小为(x,x);

5)统计每个cell的梯度特征向量,形成梯度直方图;

6)将y*y个cell组成一个正方形的块(block),一个block内所有cell的特征向量串联得到该block的HOG特征向量;

7)将所有block内所有的HOG特征向量串联得到此图片的HOG特征向量。

对于HOG算法的实现编程能力强的同学可以自己编写算法函数,显然本博主不是,所以我使用是opencv库内嵌的hog算法函数compute。依据此函数输入一张待处理的灰度图img,可以输出该图片hog特征序列。

使用compute函数前,需要预先初始化hog算法,依据训练集的图片和期望特征提取的复杂程度设定HOGDescriptor函数的入口参数。其中,winSize为感兴趣区域ROI大小,即训练集图片图片的大小;blockSize为块大小;blockStride为块移动步增量;cellSize为胞元大小;nBin为梯度方向数。

def computeHOGs(img_list,gradient_list,wsize=(100,100)): #计算roi的hog特征
    hog = cv2.HOGDescriptor((100,100),(10,10),(5,5),(5,5),nBin)
    # 窗口大小  块大小 快滑动增量 胞元大小 梯度方向数
    for i in range(len(img_list)):
        img  = img_list[i]
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)    #灰度化
        gray = cv2.equalizeHist(gray)       #直方图均衡化,防止有些图片过亮或过暗
        gray = gamma_trans(gray,gram)        #伽马变换
        gradient_list.append(hog.compute(gray))    
    return gradient_list

 HOG算法提取图片的HOG特征向量实现步骤为:

1)将图片分割为若干cellSize大小的cell;

2)从图片的左上角开始,提取blockSize大小block的梯度值;

3)block以blockStride为移动距离从左到右,再到下一行遍历整张图片;

4)根据nBins分割梯度值,得到hog特征向量

烟雾检测(1)HOG+SVM 检测_第5张图片

SVM生成模型

支持向量机(SVM)是一种监督机器学习算法,可用于分类或回归挑战。通过SVM算法可以找到离分隔超平面最近的点,确保它们离分割面的距离尽可能远。 核函数kernel利用低维的输入空间,将其转换为高维空间;即将不可分离问题转换为可分离问题。

创建svm分类器,设置svm内核、伽马变换系数和惩罚系数,如下图所示。生成模型,并保存为svm1.xml。

#训练svm
svm1 = cv2.ml.SVM_create()
svm1.setType(cv2.ml.SVM_C_SVC)
svm1.setGamma(0.5)
svm1.setC(3)
svm1.setKernel(cv2.ml.SVM_LINEAR) #线性
svm1.train(np.array(gradient_list), cv2.ml.ROW_SAMPLE, np.array(labels))
svm1.save("svm1.xml") 

 烟雾检测(1)HOG+SVM 检测_第6张图片

至此,模型训练完成。 

测试集测试

def gamma_trans(img,gamma): #伽马变换
    gamma_table = [np.power(x/255.0,gamma)*255.0 for x in range(256)]
    gamma_table = np.round(np.array(gamma_table)).astype(np.uint8)
    return cv2.LUT(img,gamma_table)

def computeHOGs(img_list,gradient_list,wsize=(100,100)): #计算roi的hog特征
    hog = cv2.HOGDescriptor((100,100),(10,10),(5,5),(5,5),nBin)
    # 窗口大小  块大小 快滑动增量 胞元大小 梯度方向数
    for i in range(len(img_list)):
        img  = img_list[i]
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)    #灰度化
        gray = cv2.equalizeHist(gray)       #直方图均衡化,防止有些图片过亮或过暗
        gray = gamma_trans(gray,gram)        #伽马变换
        gradient_list.append(hog.compute(gray))    
    return gradient_list

def sliding_window(image, stepSize, windowSize):#滑动窗口
  for y in range(0, image.shape[0], stepSize):
    for x in range(0, image.shape[1], stepSize):
        yield (x, y, image[y:y + windowSize[1], x:x + windowSize[0]])
        #哪个维度超纲,哪个维度就显示原图

def mqa_hog_predict(mqa_img,i,z):
    scale = 1
    w,h = 100,100
    x,y = 0,0
    rectangles = []
    font = cv2.FONT_HERSHEY_PLAIN
    cs_num = 0
    for (x, y, roi) in sliding_window(mqa_img, 10, (100, 100)):#对得到的图进行滑动窗口,(100, 40)为窗口大小,本文应取(64, 64)
        if roi.shape[1] != w or roi.shape[0] != h:         #判断是否超纲
            continue
        
        gray = cv2.cvtColor(roi,cv2.COLOR_BGR2GRAY)
        gray = cv2.equalizeHist(gray)
        gray = gamma_trans(gray,gram)
        test_gradient = myHog.compute(gray)
    
        a, res = svm1.predict(np.array([test_gradient]), flags=cv2.ml.STAT_MODEL_RAW_OUTPUT)
        _, result = svm1.predict(np.array([test_gradient]))
        score = res[0][0]
        #if result[0][0] == 1 :#and score > my_res :
        if score < my_res :
            # cs_num+=1
            #z+=1
            rx, ry, rx2, ry2 = int(x * scale), int(y * scale), int((x+w) * scale), int((y+h) * scale)
            rectangles.append([rx, ry, rx2, ry2, score])
    windows = np.array(rectangles)
    boxes = nms(windows,0.5)
    # print(len(boxes))
    # print(z,len(boxes))
    if z == 1:
        if len(boxes) > 8 :
            for (x, y, x2, y2, score) in boxes:  #
              cv2.rectangle(mqa_img, (int(x),int(y)),(int(x2), int(y2)),(0, 255, 0), 1)
              cv2.putText(mqa_img, "%f" % score, (int(x),int(y)), font, 1, (0, 255, 0))
        cv2.imshow("img"+str(i), mqa_img)    #显示图像,常与下一函数连用,否则图片一闪而过
    return  score

PosTestNum = 552
NegTestNum = 831
m1,m2=0,0 
for i in range(0,NegTestNum):
        fileName = 'test\\non_mqa\\csw ('+str(i+1)+').jpg'
        # 导入正样本图片
        img  = cv2.imread(fileName)
        m1=mqa_hog_predict(img,i,0)
        mysj.append(m1)
#画图
plt.hist(mysj,bins=(100))
plt.title("label1")
plt.show()
for i in range(0,PosTestNum):
        fileName = 'test\\smoke_mqa\\csy ('+str(i+1)+').jpg'
        # 导入负样本图片
        img  = cv2.imread(fileName)
        m2=mqa_hog_predict(img,1000+i,0) 
        mysj1.append(m2)   
   
plt.hist(mysj1,bins=(100))
plt.title("label2")
plt.show() 

由train.py生成的模型,利用test.py对测试集的图片进行测试,生成以下两张柱状图。label1为使用无烟雾图片得到的相似度分布图,小于0部分为二分类混淆矩阵的FP(假正例)部分,大于0为TN(正反例)部分。label3为使用烟雾图片得到的相似度分布图,小于0部分为二分类混淆矩阵的TP(真正例)部分,大于0为FN(假反例)部分。

烟雾检测(1)HOG+SVM 检测_第7张图片

烟雾检测(1)HOG+SVM 检测_第8张图片

 由两图可知检测程序的实现效果不太理想,主要原因为训练集内图片太少、hog算法理解浅薄、hog算法自身的局限。

 小结

这作业对我这种既不研究图像识别,又不研究机器学习的一般人太难了,课题组的师兄师姐们去年的作业也不是烟雾检测,不能借鉴往年作业。越做越感觉任务量越巨大,做到现在还没完成总任务的四分之一,只是完成第一条和第三条作业要求的hog算法,任重而道远啊。对于作业的第二条——降维和聚类,现阶段正在学习,等到学完相关课程之后再一一加入。对于作业的第四条——模型评价及选择,经过课程学习后,本人觉得应该放在最后完成,故待前三条完成后攻克。

下一步计划打算使用LBP算法进行特征提取和分类,将会在下一篇文章分享,敬请期待。=========================================================================

本篇借鉴了以下博客内容,如有侵权,立删。

HOG算法的实现 - tangjunjun - 博客园 (cnblogs.com)

​​​​​​(6条消息) opencv-python 入门实战:传统方法Hog+svm实现目标检测_weixin_44689486的博客-CSDN博客

 (6条消息) Python+OpenCV+HOG+SVM+行人检测_nsh119的博客-CSDN博客

你可能感兴趣的:(hog,python,svm)