geaxgx / playing-card-detection

MIT License
422 stars 141 forks source link

Transform just 1 card without hull and enclose entire card in bounding box and generate new scene #6

Open Shameendra opened 5 years ago

Shameendra commented 5 years ago

Hi, i was wondering that i wanted to generate a scene with just the card, without the hulls and my bounding box encloses the card. I have been trying to modify your code to do this but always run into errors. Could you take a look and advise what i am doing wrong. My code is:

`

Scenario with 1 card:

# The original image of a cover has the shape (cardH,cardW,4)
# We first paste it in a zero image of shape (imgH,imgW,4) at position decalX, decalY
# so that the original image is centerd in the zero image

 decalX=int((imgW-cardW)/2)
 decalY=int((imgH-cardH)/2)  
# imgaug keypoints of the bounding box of a whole card
def card_to_kps(decalX=decalX, decalY=decalY):
      kps = ia.KeypointsOnImage([ia.Keypoint(x=decalX,y=decalY),
                               ia.Keypoint(x=decalX+length,y=decalY),
                               ia.Keypoint(x=decalX+length,y=decalY+breadth),
                               ia.Keypoint(x=decalX,y=decalY+breadth)], shape=(imgH,imgW,3))

      return kps

def kps_to_polygon(kps):

        #Convert imgaug keypoints to shapely polygon

    pts=[(kp.x,kp.y) for kp in kps]
    return Polygon(pts)

def kps_to_BB(kps):
    """
        Determine imgaug bounding box from imgaug keypoints
    """
    extend=3 # To make the bounding box a little bit bigger
    kpsx=[kp.x for kp in kps.keypoints]
    minx=max(0,int(min(kpsx)-extend))
    maxx=min(imgW,int(max(kpsx)+extend))
    kpsy=[kp.y for kp in kps.keypoints]
    miny=max(0,int(min(kpsy)-extend))
    maxy=min(imgH,int(max(kpsy)+extend))
    if minx==maxx or miny==maxy:
        return None
    else:
        return ia.BoundingBox(x1=minx,y1=miny,x2=maxx,y2=maxy

# imgaug transformation for card
transform_1card = iaa.Sequential([
    iaa.Affine(scale=[0.65,1]),
    iaa.Affine(rotate=(-180,180)),
    iaa.Affine(translate_percent={"x":(-0.25,0.25),"y":(-0.25,0.25)}),
])

# imgaug transformation for the background
scaleBg=iaa.Resize({"height": imgH, "width": imgW})

def augment(img,list_kps,seq, restart=True):
    """
        Apply augmentation 'seq' to image 'img' and keypoints 'list_kps'
        If restart is False, the augmentation has been made deterministic outside the function 
    """ 
    # Make sequence deterministic
    while True:
        if restart:
            myseq=seq.to_deterministic()
        else:
            myseq=seq

        # Augment image, keypoints and bbs 
        img_aug = myseq.augment_images([img])[0]
        list_kps_aug = [myseq.augment_keypoints([kp])[0] for kp in list_kps]
        list_bbs = [kps_to_BB(list_kps_aug[1]),kps_to_BB(list_kps_aug[2])]
        valid=True
        # Check the cover bounding box stays inside the image
        for bb in list_bbs:
        if bb is None or int(round(bb.x2)) >= imgW or int(round(bb.y2)) >= imgH or int(bb.x1)<=0 or int(bb.y1)<=0:
                valid=False
                break
        if valid: break
        elif not restart:
            img_aug=None
            break

    return img_aug,list_kps_aug,list_bbs

class BBA:  # Bounding box + annotations
    def __init__(self,bb,classname):      
        self.x1=int(round(bb.x1))
        self.y1=int(round(bb.y1))
        self.x2=int(round(bb.x2))
        self.y2=int(round(bb.y2))
        self.classname=card
class Scene:
def __init__(self,bg,img1):        
     self.createCardsScene(bg,img1)

def createCardsScene(self,bg,img1):

    # Randomly transform 1st card
    self.img1=np.zeros((imgH,imgW,4),dtype=np.uint8)
    self.img1[decalY:decalY+cardH,decalX:decalX+cardW,:]=img1
    self.img1, self.bbs1=augment(self.img1, transform_1cover)
    #self.class1=class1

def display(self):
    fig,ax=plt.subplots(1,figsize=(8,8))
    ax.imshow(self.final)
    for bb in self.listbba:
        rect=patches.Rectangle((bb.x1,bb.y1),bb.x2-bb.x1,bb.y2-bb.y1,linewidth=1,edgecolor='b',facecolor='none')
        ax.add_patch(rect)
def res(self):
    return self.final
def write_files(self,save_dir,display=False):
    jpg_fn, xml_fn=give_me_filename(save_dir, ["jpg","xml"])
    plt.imsave(jpg_fn,self.final)
    if display: print("New image saved in",jpg_fn)
    create_voc_xml(xml_fn,jpg_fn, self.listbba,display=display)`
geaxgx commented 5 years ago

Hi, I imagine you get syntax errors, no ? Your code is not indented correctly (for instance the class Scene), or have missing parenthese (in return of the function kps_to_BB).

Shameendra commented 5 years ago

Hi , thanks for the reply. The indentations are not an issue and also the missing parentheses. Those are errors while pasting the code here. The issue i have is in how to randomly transform a card and paste it in a new background in the line,

 self.img1, self.bbs1=augment(self.img1, transform_1cover)

i get errors like"missing one argument:seq" or "something like KeypointsOnImage is not iterable" when i try to pass kps as an argument, or even errors like 'list' object has no attribute 'keypoints' in the function def kps_to_bb(kps) I was wondering how to change the code such that i paste the entire card and the 4 corners as keypoints and transform them is such a way that it also returns bounding box coordinates of entire card

geaxgx commented 5 years ago

The error "missing one argument" seems very clear. You give only 2 arguments in the call to augment, while you should give 3 (missing argument: list_kps).

Shameendra commented 5 years ago

yes i understood that. i tried it and it gives me the above mentioned errors. i will try to solve myself in the meantime, but if you have any suggestions, it would be very helpful