openpose-exercise-1

openpose-exercise-1

之前出于兴趣看了关于人体pose的相关的,现在想总结一下。

参考的代码是torch实现的openpose,网址我在之前的blog里面给出过。 openpose是做体姿态估计的,大估的过程是先检测出关键点,然后将关键点以某种方式连接起来,可以做多人的估计,效果挺好的,看完之后,我在想能不能用这里面的想法来做其他的总是呢,比如人脸的关键点检测,然后我就试了一下。这一系列blog,就准备记录这些过程。

准备数据

无人工不智能,这次没有用公共数据集,我是用的我自己的自拍照,大致有100张。 用了一个比较好用的标注程序,叫sloth.

sloth的使用

sloth有官方的文档,按教程上的操作即可,如果想要标注自己的风格的话,比如点,或者bbox都是可以的,只需要修一个配置文件即可,如下


LABELS = ( 
    {"attributes": {"class": "A"},
     "item":     "sloth.items.PointItem",
     "inserter": "sloth.items.PointItemInserter",
     "text":     "0",
    },  
    {"attributes": {"class": "B"},
     "item":     "sloth.items.PointItem",
     "inserter": "sloth.items.PointItemInserter",
     "text":     "1",
    },  
)


这是标记两个点的,我用了5个点,来标记我的脸。 标注好了之后,保存结果,会有一个json文件,在标注之前为了让sloth能够运行,需要先产生一个basic的json文件, 这个是告诉sloth有哪些是需要标注的。我是这么写的一个。

import json
import os
import sys 

"""
usage method:
python ....py imgDir

output: imgDir/imgDir.json
"""
def main():
    imgDir = sys.argv[1]
    if not os.path.exists(imgDir):
        print("%s doesn't exist"%(imgDir))
        return

    #json_path = os.path.join(imgDir,"%s.json" %(imgDir))
    json_path = "%s.json" % imgDir
    dirs = os.listdir(imgDir)
    imgpaths = []
    for x in dirs:
        if x.endswith(".jpg"):
            imgpaths.append(x)
    
    print("We have %d imgs" %(len(imgpaths)))

    result = []
    for i, item in enumerate(imgpaths):
        tempDict = {}
        tempDict["annotations"] = []
        tempDict["class"] = "image"   # this is necessary, cannot be changed
        tempDict["filename"] = item
        result.append(tempDict)

    w = open(json_path, 'w')
    w.write(json.dumps(result))

    w.close()

if __name__ == "__main__":
    main()

标注完了之后这个json自己会变化,即会加上已经标注的信息。里面是个列表,最前面的2个如下,

[{"annotations": [{"ids": "20", "x": 379.4439945600007, "class": "A", "y": 470.3524515900009}, {"ids": "20", "x": 727.2676562400014, "class": "B", "y": 482.2100764    200009}, {"ids": "20", "x": 486.16261803000094, "class": "C", "y": 351.77620329000064}, {"ids": "20", "x": 628.4541159900012, "class": "D", "y": 355.72874490000066    }, {"ids": "20", "x": 561.260908620001, "class": "E", "y": 513.830409300001}], "class": "image", "filename": "myimg_009.jpg"}, {"annotations": [{"ids": "20", "x":     648.2168240400013, "class": "A", "y": 612.6439495500011}, {"ids": "20", "x": 984.1828608900018, "class": "B", "y": 604.7388663300011}, {"ids": "20", "x": 727.26765    62400014, "class": "C", "y": 521.735492520001}, {"ids": "20", "x": 877.4642374200016, "class": "D", "y": 509.877867690001}, {"ids": "20", "x": 810.2710300500015, "    class": "E", "y": 664.0269904800012}], "class": "image", "filename": "myimg_006.jpg"}, 

由于这里面用的是coco的数据集,为了简单的话,要把这个json文件,转成和coco类似的文件,这样直接用coco里面写好的代码就比较方便。但是coco里面的内容非常多,还有分割信息,一张img上也可能有多个人,但是我这里只有5个点,所以,对于我自己的这个demo的话,我想的是不需要分割的信息,最后试了下效果还可以。

将这个文件转成coco类似的文件,方法是查coco的数据集是长什么样的,然后就可以写了。我是这么写的。

import os,sys
import cv2
import json

def main():
    origin = sys.argv[1]
    imgsDir = sys.argv[2]
    # imgsDir   in order to read image to get img's shape
    newName = origin.strip().split(".")[0]+"_coco"+".json"
    w = open(newName, 'w')
    BigDic= {"info":{}, "images":[], "licenses":[],"annotations":[],"categories":[]
    }
    data = open(origin,"r",encoding="utf-8")
    ret = json.loads(data.read())
    keypoints = []
    shapes = []   # save img's shape
    cnt = 0
    for item in ret:
        img_path = item["filename"]
        kpyts = item["annotations"]
        points = []   #save four points's infos, 
        for item in kpyts:
            #class_id = item["class"]   # class_id 不需要,顺序就是class_id
            pos_x = item["x"]
            pos_y = item["y"]
            points += [pos_x, pos_y, 2]
        keypoints.append([img_path, points])

        #print(img_path)
        height, width, _ = cv2.imread(os.path.join(imgsDir,img_path)).shape
        shapes.append([height, width])
        cnt += 1
        if cnt % 20 == 0:
            print("have finished %d!" % cnt)

    data.close()
    # GET THE DATA from original json finished!!!
    # next we START to transfer!
    assert len(keypoints)==len(shapes)
    l = len(keypoints)
    print("we have %d imgs" %(l))

    for i in range(l):
        img_path = keypoints[i][0]
        temp = {}
        temp["license"] = None
        temp["file_name"] = img_path
        temp["coco_url"] = None
        temp["height"] = shapes[i][0]
        temp["width"] = shapes[i][1]
        temp["date_captured"] = None
        temp["flickr_url"] = None
        temp["id"] = i

        BigDic["images"].append(temp)
        ## 我们现在annotations的数目和图片的数量是一样多的。
        # area is not width*height, but we here use width*height temporly!
        ann = {"segmentation": [], "area":shapes[i][0]*shapes[i][1], "keypoints":[], "image_id": i, "bbox":[0, 0, shapes[i][1], shapes[i][0]], "category_id": 1, "id": i}
        ann["keypoints"] = keypoints[i][1]
        BigDic["annotations"].append(ann)

    w.write(json.dumps(BigDic))
    w.close()

if __name__ == "__main__":
    main()

  • 不需要mask

因为原本的coco里面是有分割的信息的,所以有mask的产生,但是我这里就需要了, 所以代码里面凡是有关于mask的我全部给去掉了。

  • gen train json

去掉了mask了之后,生成训练的json文件就比较方便了,直接用propressing/下面的gen..py那个代码,注意里面的有些地方,需要调成绝对路,不然读时可能读不到。

网络构建

前面是数据的准备部分,现在开始构建网络,原作是用vgg来提feature的,然后进入6个stage的检测和不断地refine关键点的过程。原作中是有两个主分支的,一个主分支pred关键点的位置置信度,一个分支关键点的向量场,这里因为我是检测脸的,所以我不需要第二个分支,网络中关于coco的地方,要注意修gai,有些cang的比较深,比如在mytransform.py里面也有。其他的基本上没有什么gai变。网络输入是368, 我也没有gai,

配置信息我也没有gai,呵呵,调包xia.

inference

直接上图吧,效果还可以, avator avator

注意的地方

有许多地方要gai,还是需要把整个代码非常shuxi,不然很容易出错。

打赏,谢谢~~

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,多谢支持~

打开微信扫一扫,即可进行扫码打赏哦