本文主要讲如何通过HOG特征和SVM分类器实现部分交通标志的检测。由于能力有限,本文的检测思路很简单,主要是用来自己练习编程用,也顺便发布出来供需要的人参考。本项目完整的代码可以在我的github上下载:traffic-sign-detection。博客或代码中遇到的任何问题,欢迎指出,希望能相互学习。废话不多说了,下面就来一步步介绍我的检测过程。**
from xml.dom.minidom import Documentimport osimport cv2def write_img_to_xml(imgfile, xmlfile):
"""
write xml file.
Args:
imgfile: image file.
xmlfile: output xml file.
"""
img = cv2.imread(imgfile)
img_folder, img_name = os.path.split(imgfile)
img_height, img_width, img_depth = img.shape
doc = Document()
annotation = doc.createElement("annotation")
doc.appendChild(annotation)
folder = doc.createElement("folder")
folder.appendChild(doc.createTextNode(img_folder))
annotation.appendChild(folder)
filename = doc.createElement("filename")
filename.appendChild(doc.createTextNode(img_name))
annotation.appendChild(filename)
size = doc.createElement("size")
annotation.appendChild(size)
width = doc.createElement("width")
width.appendChild(doc.createTextNode(str(img_width)))
size.appendChild(width)
height = doc.createElement("height")
height.appendChild(doc.createTextNode(str(img_height)))
size.appendChild(height)
depth = doc.createElement("depth")
depth.appendChild(doc.createTextNode(str(img_depth)))
size.appendChild(depth) with open(xmlfile, "w") as f:
doc.writexml(f, indent="t", addindent="t", newl="n", encoding="utf-8")
def write_imgs_to_xmls(imgdir, xmldir):
img_names = os.listdir(imgdir) for img_name in img_names:
img_file = os.path.join(imgdir,img_name)
xml_file = os.path.join(xmldir, img_name.split(".")[0]+".xml") print img_name, "has been written to xml file in ", xml_file
write_img_to_xml(img_file, xml_file)
def hog_feature(img_array, resize=(64,64)): """extract hog feature from an image. Args: img_array: an image array. resize: size of the image for extracture. Return: features: a ndarray vector. """ img = cv2.cvtColor(img_array, cv2.COLOR_BGR2GRAY) img = cv2.resize(img, resize) bins = 9 cell_size = (8, 8) cpb = (2, 2) norm = "L2" features = ft.hog(img, orientations=bins, pixels_per_cell=cell_size, cells_per_block=cpb, block_norm=norm, transform_sqrt=True) return features
def extra_hog_features_dir(img_dir, write_txt, resize=(64,64)):
"""extract hog features from images in a directory.
Args:
img_dir: image directory.
write_txt: the path of a txt file used for saving the hog features of all images.
resize: size of the image for extracture.
Return:
none.
"""
img_names = os.listdir(img_dir)
img_names = [os.path.join(img_dir, img_name) for img_name in img_names] if os.path.exists(write_txt):
os.remove(write_txt) with open(write_txt, "a") as f:
index = 0
for img_name in img_names:
img_array = cv2.imread(img_name)
features = hog_feature(img_array, resize)
label_name = img_name.split("/")[-1].split("_")[0]
label_num = img_label[label_name]
row_data = img_name + "t" + str(label_num) + "t"
for element in features:
row_data = row_data + str(round(element,3)) + " "
row_data = row_data + "n"
f.write(row_data) if index%100 == 0: print "total image number = ", len(img_names), "current image number = ", index
index += 1
HOG特征提取的一些参数设置可以在函数中看到,如图像尺寸为64×64,设置了9个梯度方向(bin=9)进行梯度信息统计,cell的大小为8×8,每个block包含4个cell(cpb=(2, 2)),标准化方法采用L2标准化(norm=”L2”)。
def affine(img, delta_pix):
"""affine transformation
Args:
img: a numpy image array.
delta_pix: the offset for affine.
Return:
res: affined image.
"""
rows, cols, _ = img.shape
pts1 = np.float32([[0,0], [rows,0], [0, cols]])
pts2 = pts1 + delta_pix
M = cv2.getAffineTransform(pts1, pts2)
res = cv2.warpAffine(img, M, (rows, cols)) return resdef affine_dir(img_dir, write_dir, max_delta_pix):
""" affine transformation on the images in a directory.
Args:
img_dir: image directory.
write_dir: save directory of affined images.
max_delta_pix: the maximum offset for affine.
"""
img_names = os.listdir(img_dir)
img_names = [img_name for img_name in img_names if img_name.split(".")[-1]=="jpg"] for index, img_name in enumerate(img_names):
img = cv2.imread(os.path.join(img_dir,img_name))
save_name = os.path.join(write_dir, img_name.split(".")[0]+"f.jpg")
delta_pix = np.float32(np.random.randint(-max_delta_pix, max_delta_pix+1, [3,2]))
img_a = affine(img, delta_pix)
cv2.imwrite(save_name, img_a)
上面函数输入参数max_delta_pix用来控制随机仿射变换的最大强度(正整数),max_delta_pix的绝对值越大,变换越明显(太大可能导致目标信息的完全丢失),我在扩充时这个参数取为10。需要注意的是,10只是变换的最大强度,在对每一张图片进行变换前,会在[-max_delta, max_delta]生成一个随机整数delta_pix(当然你也可以多取几次不同的值来生成更多的变换图片),这个整数控制了当前图片变换的强度。以下是一些变换的结果示例:

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/106/viewspace-2809605/ ,如需转载,请注明出处,否则将追究法律责任。