www.pudn.com > malic.rar > xmltocvhaardata.py


#!/usr/bin/python

import string
import xml.sax
from xml.sax.handler import *
import sys
import Image

class MalicXMLHandler(ContentHandler):
    def __init__(self, input_image_dir, partsnames, width, height):
        self.input_image_dir= input_image_dir
        self.partsnames= partsnames
        self.width= width
        self.height= height
        self.image_fnames= []
        self.parts_boxes= []
        self.char= ""
        self.data= []

            
        parts_pairs= []
        if partsnames:
            for i in range (len(partsnames) / 2):
                parts_pairs.append((partsnames[i*2], partsnames[i*2 + 1]))

        self.parts_pairs= parts_pairs

    def startElement(self, name, attrs):
        if name == 'Template':
            self.image_fname= attrs["fg_image_fname"]
            self.parts_pairs_co= []
            for i in range (len(self.parts_pairs)):
                self.parts_pairs_co.append([None,None]) # parts_pairs_co= [[xy,xy],[xy,xy]...]

            self.parts_boxes.append({})
            self.parts_boxes[-1]['fname']= attrs["fg_image_fname"]

        if name == 'Cells':
            i= 0
            for pair in self.parts_pairs:
                j= 0
                for partsname in pair:
                    if attrs["parts"] == partsname:
                        x= int( string.atof(attrs["x"]) )
                        y= int( string.atof(attrs["y"]) )
                        self.parts_pairs_co[i][j]= (x, y)
                    j+= 1
                i+= 1
        return

    def parts_pair_center(self, parts_pair):
        """
        @parts_pair: [xy, xy]  #e.g left_eye_l_edge, right_eye_r_edge
        """
        center= (((parts_pair[0][0] + parts_pair[1][0]) / 2),
                 ((parts_pair[0][1] + parts_pair[1][1]) / 2))
        return center

    def endElement(self,name):
        if name == 'Template':
            co_num= 0
            co_string= ""
            #coordinate data formating to self.data
            #pair_co = [xy, xy]
            for parts_pair in self.parts_pairs_co:
                if parts_pair[0] and parts_pair[1]:
                    center= self.parts_pair_center(parts_pair)
                    x0= center[0] - self.width / 2
                    y0= center[1] - self.height / 2
                    co_string= "%s %s %s %s %s" % (co_string, x0, y0, self.width, self.height)
                    co_num+= 1

            fname= "%s/%s" % (self.input_image_dir, self.image_fname)
            str= "%s %s%s" % (fname, co_num, co_string)
            self.data.append(str)

    def output_data(self):
        for i in self.data:
            sys.stdout.write("%s\n" % i)

class MalicBGImageHandler(MalicXMLHandler):
    def __init__(self, input_image_dir= "./", partsnames= None, \
                 width= 50, height= 50, bg_image_output_dir= "./", offset_xy= (0,0)):
        MalicXMLHandler.__init__(self, input_image_dir, partsnames, width, height)
        self.bgImageFnameAndBox = []
        self.bg_image_output_dir= bg_image_output_dir
        self.offset_xy= offset_xy
        
    def startElement(self, name, attrs):
        MalicXMLHandler.startElement(self, name, attrs)
        
    def endElement(self, name):
        if name == 'Template':
            bgImageFnameAndBox={}
            co_num= 0
            co_string= ""
            #coordinate data formating to self.data
            #pair_co = [xy, xy]
            parts_boxes= []
            for parts_pair in self.parts_pairs_co:
                if parts_pair[0] and parts_pair[1]:
                    center= self.parts_pair_center(parts_pair)
                    center= (center[0] + self.offset_xy[0], center[1] + self.offset_xy[1])
                    
                    x0= center[0] - self.width / 2 
                    y0= center[1] - self.height / 2 
                    x1= x0 + self.width
                    y1= y0 + self.height
                    parts_boxes.append((x0, y0, x1, y1))
                    co_num+= 1
            fname= "%s/%s" % (self.input_image_dir, self.image_fname)
            bgImageFnameAndBox['image_fname']= fname
            bgImageFnameAndBox['boxes']= parts_boxes
            self.data.append(bgImageFnameAndBox)
            return
        
    def output_data(self):
        count= 0
        for fname_and_box in self.data:
            fname= fname_and_box['image_fname']
            im= Image.open(fname)
            for box in fname_and_box['boxes']:
                bg_im= im.crop(box)
                fname= "%s/bg_image%.6d.jpg" % (self.bg_image_output_dir, count)
                print fname
                bg_im.save(fname)
                count+= 1
    

class MalicBGRandImageHandler (MalicXMLHandler):
    def __init__(self, input_image_dir= "./", partsnames= None, \
                 width= 50, height= 50, bg_image_output_dir= "./", bg_image_num_from_onefile= 1):
        MalicXMLHandler.__init__(self,input_image_dir, partsnames, width, height)

        self.bgImageFnameAndBox       = []
        self.bg_image_output_dir      = bg_image_output_dir
        self.bg_image_num_from_onefile= bg_image_num_from_onefile
        self.parts_boxes= []

    def startElement (self, name, attrs):
        MalicXMLHandler.startElement(self, name, attrs)
        if name == 'Template':
            try:
                attrs['face_rect']
            except KeyError:
                self.face_box= None
                return

            self.parts_boxes.append({})
            self.parts_boxes[-1]['fname']= attrs["fg_image_fname"]
            
            face_rect= [None] * 4
            tmp= string.split(attrs['face_rect'])
            i= 0;
            for val_str in tmp:
                face_rect[i]= int(val_str)
                i+= 1
            self.face_box= [face_rect[0], face_rect[1],\
                            face_rect[0] + face_rect[2], face_rect[1] + face_rect[3]]
    def create_box (self, center, width, height):
        x0= center[0] - width / 2
        y0= center[1] - height / 2
        x1= center[0] + width / 2
        y1= center[1] + height / 2

        return (x0,y0,x1,y1)
    
    def endElement (self, name):
        MalicXMLHandler.endElement(self,name)
        if name == 'Template':
            boxes= []
            for parts_pair in self.parts_pairs_co:
                if self.face_box and parts_pair[0] and parts_pair[1]:
                    center= self.parts_pair_center(parts_pair)
                    boxes.append(self.create_box(center, self.width, self.height))
            self.parts_boxes[-1]['box']= boxes

            if len(boxes):
                for i in range (self.bg_image_num_from_onefile):
                    box= None
                    fname= "%s/%s" % (self.input_image_dir, self.image_fname)
                    im= Image.open(fname)
                    while(not box):
                        box= self.__randCropBoxWithNegBox(self.face_box, boxes, \
                                                          self.width, self.height, im.size)
                        
                    
                    self.bgImageFnameAndBox.append({'image_fname': fname, 'box': box})
        return
    def __randCropBoxWithNegBox(self, face_box, neg_boxes, width, height, image_size):
        """
        chose random box from source_box which not overlap neg_box
        """
        #huristic
        x0= face_box[0] - int(width * 0.2)
        x1= face_box[2] + int(width * 0.2)
        y0= face_box[1] - int(height)
        y1= face_box[3] + int(height * 0.2)

        x_range= range(x0, x1)
        y_range= range(y0, y1)

        #x_range= (face_box[0], face_box[2])
        #y_range= (face_box[1], face_box[3])

        import random
        x= random.choice(x_range)
        y= random.choice(y_range)
        center= (x,y)

        def is_negative (box, xy, w= 0, h= 0):
            """
            @box: negative box
            @xy:  check coordinate
            @w: box in xy arrowed width
            """
            return ((xy[0] > box[0] + w) and (xy[0] < box[2] - w) and \
                    (xy[1] > box[1] + h) and (xy[1] < box[3] - h))
                
        # huristic
        w= int(width * 0.2)
        h= int(height * 0.2)

        for box in neg_boxes:
            if is_negative(box, center, w, h): 
                return None

        x0= center[0] - width / 2
        y0= center[1] - height / 2
        x1= x0 + width
        y1= y0 + height

        if x0 < 0 or y0 < 0 or x1 > image_size[0] or y1 > image_size[1]:
            return None

        return (x0,y0,x1,y1)

    def output_data(self):
        count= 0
        for fname_and_box in self.bgImageFnameAndBox:
            fname= fname_and_box['image_fname']
            im= Image.open(fname)
            bg_im= im.crop(fname_and_box['box'])
            fname= "%s/bg_image%.6d.jpg" % (self.bg_image_output_dir, count)
            print fname
            bg_im.save(fname)
            count+= 1

    
if __name__ == '__main__':
    import sys, glob, operator, getopt

    def usage_and_exit():
        print "-?, --help\n\t show this message \n",\
              "-f, --xmlfilename= xmlfilename\n\t xmlfilename which include face vert data\n",\
              "-i, --input_image_dir= input_image_directory_name\n",\
              "\tdirectory name which exist input image\n",\
              "-p, --partsnames=\"leftparts1 rightperts1, leftperts2,...\"\n",\
              "\t set face parts names which generate or not generate images\n",\
              "-w, --width= num\n\t set width\n",\
              "-h, --height= num\n\t set height\n",\
              "-d, --bg_image_output_dir= dirname\n\t set bgimage (XXXXX.jpg) output dir\n",\
              "-n, --bg_image_num_from_onefile= num\n\t set bgimage num from one file (with -r option)\n",\
              "--xoffset= num\n\t set xoffset width (with -b option)\n",\
              "--yoffset= num\n\t set yoffset height (with -b option)\n",\
              "-b\n\t generate bgimage\n",\
              "-r\n\t generate random selection image (with -b option)\n",\
              "-ex\n\t show example"
        
        sys.exit(0)

    def show_example_and_exit():
        print "xmltocvhaardata.py example (written 2005/12/06)"
        print "generate positive eye image info file\n",\
              "\t$ xmltocvhaardata.py -f ./img/vertdata.xml -i ./img \\\n",\
              "\t-p \"left_eye_l_edge left_eye_r_edge right_eye_l_edge right_eye_r_edge\"\\\n",\
              "\t-w 25 -h 25\\\n",\
              "\t> eyeinfo.dat"
        
        print "generate negative random image and info file of eye (not include eye image)\n",\
              "\t$ xmltocvhaardata.py -f ./img/vertdata.xml -i ./img \\\n",\
              "\t-p \"left_eye_l_edge left_eye_r_edge right_eye_l_edge right_eye_r_edge\"\\\n",\
              "\t-b -r -d ./eye_bgimg -w 50 -h 50 -n 3 > eye_bg_info.dat"
        print "generate eye image as negative\n",\
              "\t$ xmltocvhaardata.py -f ./img/vertdata.xml -i ./img \\\n",\
              "\t-p \"left_eye_l_edge left_eye_r_edge right_eye_l_edge right_eye_r_edge\"\\\n",\
              "\t-b -d ./eye_bgimg -w 50 -h 50 > eye_as_bg_info.dat"

        print "\nnow malic has forrow face parts attributes\n",\
              "\tl_eyebrow_l_edge, l_eyebrow_r_edge, r_eyebrow_l_edge, r_eyebrow_r_edge,"\
              "left_eye_l_edge, left_eye_r_edge, right_eye_l_edge, right_eye_r_edge,"\
              "nose_l_edge, nose_r_edge, mouse_left_edge, mouse_right_edge"
        
        
        sys.exit(0)

        
    try:
        opts, args = getopt.getopt(sys.argv[1:], "?:f:i:p:w:h:brd:n:", \
                                   ["help","xmlfilename=","input_image_dir=",\
                                    "partsnames="\
                                    "width=", "height=", "bgimage", "random",\
                                    "bg_image_output_dir=", "bg_image_num_from_onefile=",\
                                    "xoffset=", "yoffset=", "ex"])
        pass
    except getopt.GetoptError:
        usage_and_exit()

    fname= partsnames= bg_image= bg_random= None
    input_image_dir    = "./"
    bg_image_output_dir= "./"
    bg_image_num_from_onefile= 1
    width= 25
    height= 25
    xoffset= yoffset= 0

    for (k, v) in opts:
        if   k in ("-?", "--help") : usage_and_exit()
        elif k in ("-f", "--xmlfilename")     : fname= v
        elif k in ("-i", "--input_image_dir") : input_image_dir= v
        elif k in ("-p", "--partsnames")      : partsnames= v
        elif k in ("-w", "--width")  : width= string.atoi(v)
        elif k in ("-h", "--height") : height= string.atoi(v)
        elif k in ("-d", "--bg_image_output_dir")       : bg_image_output_dir= v
        elif k in ("-n", "--bg_image_num_from_onefile" ): bg_image_num_from_onefile= int(v)
        elif k == "--xoffset" : xoffset= int(v)
        elif k == "--yoffset" : yoffset= int(v)
        elif k == "-b" : bg_image= True
        elif k == "-r" : bg_random= True
        elif k == "--ex" : show_example_and_exit()
        
    if partsnames:
        partsnames= string.split(partsnames)
        if (len(partsnames) % 2):
            sys.exit(8)

        
    parser= xml.sax.make_parser()
    
    if bg_image:
        if bg_random:
            handler= MalicBGRandImageHandler(input_image_dir, partsnames, width, height,\
                                             bg_image_output_dir, bg_image_num_from_onefile)
        else:
            offset_xy= (xoffset, yoffset);
            handler= MalicBGImageHandler(input_image_dir, partsnames, width, height,\
                                         bg_image_output_dir, offset_xy)
    else:
        handler= MalicXMLHandler(input_image_dir, partsnames, width, height)

    parser.setContentHandler(handler)
    parser.parse(fname)
    handler.output_data()