def align(groupid, dat): res = [] translations = [] for i, group in enumerate(zip(*dat)): if i == 0: # We want to look at everything for the title left_border = 0 else: # Skip the voting target for the rest #left_border = 80 left_border = 0 Iref_orig = sh.standardImread(group[0], flatten=True) Iref = Iref_orig[:, left_border:] r = [] r_img = [] for i in range(len(group)): I_orig = sh.standardImread(group[i], flatten=True) I = I_orig[:, left_border:] Inorm = make_norm(I, Iref) (H, imres, err) = imagesAlign.imagesAlign(Inorm, Iref, trfm_type='translation') r_img.append((make_norm(I_orig, Iref_orig), H)) r.append(translate(group[i])) translations.append(r_img) res.append(r) translated_images = [] for contest in zip(*translations): c_res = [] """ print 'new' arr = np.zeros((3,3)) for _,H in contest: arr += H arr /= len(contest) print arr """ for img, H in contest: translated = sh.imtransform(np.copy(img), H, fillval=np.nan) align_res = np.nan_to_num(translated) c_res.append(align_res) translated_images.append(c_res) translated_images = zip(*translated_images) return res, translated_images
def align(groupid, dat): res = [] translations = [] for i,group in enumerate(zip(*dat)): if i == 0: # We want to look at everything for the title left_border = 0 else: # Skip the voting target for the rest #left_border = 80 left_border = 0 Iref_orig=sh.standardImread(group[0],flatten=True) Iref = Iref_orig[:,left_border:] r = [] r_img = [] for i in range(len(group)): I_orig=sh.standardImread(group[i],flatten=True) I=I_orig[:,left_border:] Inorm = make_norm(I, Iref) (H,imres,err)=imagesAlign.imagesAlign(Inorm,Iref,trfm_type='translation') r_img.append((make_norm(I_orig, Iref_orig), H)) r.append(translate(group[i])) translations.append(r_img) res.append(r) translated_images = [] for contest in zip(*translations): c_res = [] """ print 'new' arr = np.zeros((3,3)) for _,H in contest: arr += H arr /= len(contest) print arr """ for img,H in contest: translated = sh.imtransform(np.copy(img), H, fillval=np.nan) align_res = np.nan_to_num(translated) c_res.append(align_res) translated_images.append(c_res) translated_images = zip(*translated_images) return res, translated_images
def cluster_imgpatchesV2(imgpaths, bb_map, init_clusters=None, THRESHOLD=0.95): """ Given a list of imgpaths, and bounding boxes for each image, cluster the bounding boxes from each image. Input: list imgpaths: dict bb_map: maps {str imgpath: (y1,y2,x1,x2)} list init_clusters: An initial set of cluster centers, of the form: {imgpath_i: (imgpath_i, bb_i)} float THRESHOLD: A cutoff value to use when determining if the patch was found. Ranges from [0.0, 1.0], where higher values is 'stricter', i.e. THRESHOLD=1.0 means only accept exact matches (not recommended). Higher values also means more computation time. Output: A dict of the form: {c_imgpath: [(imgpath_i, bb_i, score), ...} where each c_imgpath is the 'center' of a given cluster C. """ clusters = {} unlabeled_imgpaths = list(imgpaths) while unlabeled_imgpaths: curimgpath = unlabeled_imgpaths.pop() bb = bb_map[curimgpath] I = shared.standardImread(curimgpath, flatten=True) _t = time.time() print "...calling find_patch_matchesV1..." matches = partask.do_partask(findpatchmatches, unlabeled_imgpaths, _args=(I, bb, bb, THRESHOLD)) print "...finished find_patch_matchesV1 ({0} s)".format(time.time() - _t) # Manually add in I matches.append((curimgpath, -1.0, 1.0, None, bb[0], bb[1], bb[2], bb[3], 1.0)) if matches: # 0.) Retrieve best matches from matches (may have multiple # matches for the same imagepath) print "...number of pre-filtered matches: {0}".format(len(matches)) bestmatches = {} # maps {imgpath: (imgpath,sc1,sc2,Ireg,y1,y2,x1,x2,rszFac)} for (filename,sc1,sc2,Ireg,y1,y2,x1,x2,rszFac) in matches: y1, y2, x1, x2 = map(lambda c: int(round(c/rszFac)), (y1, y2, x1, x2)) if filename not in bestmatches: bestmatches[filename] = (filename,sc1,sc2,y1,y2,x1,x2,rszFac) else: old_sc2 = bestmatches[filename][2] if sc2 < old_sc2: bestmatches[filename] = (filename,sc1,sc2,y1,y2,x1,x2,rszFac) print "...found {0} matches".format(len(bestmatches)) # 1.) Handle the best matches for _, (filename,sc1,sc2,y1,y2,x1,x2,rszFac) in bestmatches.iteritems(): if filename in unlabeled_imgpaths: unlabeled_imgpaths.remove(filename) clusters.setdefault(curimgpath, []).append((filename, (y1,y2,x1,x2), sc2)) else: print "...Uh oh, no matches found. This shouldnt' have \ happened." pdb.set_trace() print "...Completed clustering. Found {0} clusters.".format(len(clusters)) return clusters
def distance2(img, imgpath2): """ L2 norm between img1, img2 """ img2 = shared.standardImread(imgpath2, flatten=True) bb2 = bb_map.get(imgpath2, None) if bb2 != None: img2 = img2[bb2[0]:bb2[1], bb2[2]:bb2[3]] img2 = common.resize_img_norescale(img2, (img.shape[1], img.shape[0])) diff = np.linalg.norm(img - img2) return diff
def distance3(img, imgpath2): """ NCC score between img1, img2. """ imgCv = cv.fromarray(np.copy(img.astype(np.float32))) img2 = shared.standardImread(imgpath2, flatten=True) bb2 = bb_map.get(imgpath2, None) if bb2 != None: img2 = img2[bb2[0]:bb2[2], bb2[2]:bb2[3]] img2Cv = cv.fromarray(np.copy(img2.astype(np.float32))) outCv = cv.CreateMat(imgCv.height - img2Cv.height+1, imgCv.width - img2Cv.width+1, imgCv.type) cv.MatchTemplate(imgCv, img2Cv, outCv, cv.CV_TM_CCOEFF_NORMED) return outCv.max()
def distance3(img, imgpath2): """ NCC score between img1, img2. """ imgCv = cv.fromarray(np.copy(img.astype(np.float32))) img2 = shared.standardImread(imgpath2, flatten=True) bb2 = bb_map.get(imgpath2, None) if bb2 != None: img2 = img2[bb2[0]:bb2[2], bb2[2]:bb2[3]] img2Cv = cv.fromarray(np.copy(img2.astype(np.float32))) outCv = cv.CreateMat(imgCv.height - img2Cv.height + 1, imgCv.width - img2Cv.width + 1, imgCv.type) cv.MatchTemplate(imgCv, img2Cv, outCv, cv.CV_TM_CCOEFF_NORMED) return outCv.max()
def do_aligning(imgpaths, outdir, idx): Iref_imgP = imgpaths.pop(idx) Iref_np = scipy.misc.imread(Iref_imgP, flatten=True) Iref = shared.standardImread(Iref_imgP, flatten=True) Iref_crop = cropout_stuff(Iref, 0.2, 0.2, 0.2, 0.2) Iouts = global_align(Iref_crop, imgpaths) ref_dir = os.path.join(outdir, 'ref') try: os.makedirs(ref_dir) except: pass Iref_imgname = os.path.split(Iref_imgP)[1] scipy.misc.imsave(os.path.join(ref_dir, Iref_imgname), Iref) for imgpath, H, Ireg_crop, err in Iouts: print "For imgpath {0}, err={1:.4f}, H:".format(imgpath, err) imgname = os.path.splitext(os.path.split(imgpath)[1])[0] I = scipy.misc.imread(imgpath, flatten=True) Hc = correctH(Ireg_crop, H) print Hc rot_H = Hc[:2, :2] trans_H = Hc[:2, 2] """ Note: imagesAlign's H is of the form: [a b X] [c d Y] where positive Y means go down, and positive X means to right (as usual). scipy's affine_transform's offset should be offset=(y,x), but where positive y is go UP, and positive x is to the LEFT. """ #Itrans = scipy.ndimage.interpolation.affine_transform(I, rot_H, # offset=(-trans_H[1], -trans_H[0]), # output_shape=I.shape) #Icv = cv.LoadImageM(imgpath, cv.CV_LOAD_IMAGE_GRAYSCALE) #Icv_trans = cv.CreateMat(Icv.rows, Icv.cols, Icv.type) #H_cv = cv.fromarray(Hc.astype(np.float32)[:2,:]) #cv.WarpAffine(Icv, Icv_trans, H_cv) #Itrans = np.asarray(Icv) Itrans = imtransform(I, H) Itrans = np.nan_to_num(Itrans) outP = os.path.join(outdir, "{0}_err{1:.4f}.png".format(imgname, err)) Ioverlay = np.zeros(Itrans.shape) Ioverlay[:, :] = Itrans Ioverlay[:, :] += Iref_np scipy.misc.imsave(outP, Ioverlay)
def closest_label(imgpath, exemplars): mindist = None bestmatch = None img = shared.standardImread(imgpath, flatten=True) bb = bb_map.get(imgpath, None) if bb != None: img = img[bb[0]:bb[1], bb[2]:bb[3]] for label, imgpaths in exemplars.iteritems(): for imgpathB in imgpaths: dist = distance2(img, imgpathB) if mindist == None or dist < mindist: bestmatch = label mindist = dist return bestmatch, mindist
def do_aligning(imgpaths, outdir, idx): Iref_imgP = imgpaths.pop(idx) Iref_np = scipy.misc.imread(Iref_imgP, flatten=True) Iref = shared.standardImread(Iref_imgP, flatten=True) Iref_crop = cropout_stuff(Iref, 0.2, 0.2, 0.2, 0.2) Iouts = global_align(Iref_crop, imgpaths) ref_dir = os.path.join(outdir, 'ref') try: os.makedirs(ref_dir) except: pass Iref_imgname = os.path.split(Iref_imgP)[1] scipy.misc.imsave(os.path.join(ref_dir, Iref_imgname), Iref) for imgpath, H, Ireg_crop, err in Iouts: print "For imgpath {0}, err={1:.4f}, H:".format(imgpath, err) imgname = os.path.splitext(os.path.split(imgpath)[1])[0] I = scipy.misc.imread(imgpath, flatten=True) Hc = correctH(Ireg_crop, H) print Hc rot_H = Hc[:2, :2] trans_H = Hc[:2,2] """ Note: imagesAlign's H is of the form: [a b X] [c d Y] where positive Y means go down, and positive X means to right (as usual). scipy's affine_transform's offset should be offset=(y,x), but where positive y is go UP, and positive x is to the LEFT. """ #Itrans = scipy.ndimage.interpolation.affine_transform(I, rot_H, # offset=(-trans_H[1], -trans_H[0]), # output_shape=I.shape) #Icv = cv.LoadImageM(imgpath, cv.CV_LOAD_IMAGE_GRAYSCALE) #Icv_trans = cv.CreateMat(Icv.rows, Icv.cols, Icv.type) #H_cv = cv.fromarray(Hc.astype(np.float32)[:2,:]) #cv.WarpAffine(Icv, Icv_trans, H_cv) #Itrans = np.asarray(Icv) Itrans = imtransform(I, H) Itrans = np.nan_to_num(Itrans) outP = os.path.join(outdir, "{0}_err{1:.4f}.png".format(imgname, err)) Ioverlay = np.zeros(Itrans.shape) Ioverlay[:,:] = Itrans Ioverlay[:,:] += Iref_np scipy.misc.imsave(outP, Ioverlay)
def closest_label(imgpath, bb, exemplars): bestlabel = None mindist = None bbBest = None img = shared.standardImread(imgpath, flatten=True) for label, tuples in exemplars.iteritems(): imgpaths2, bbs2 = [], [] for imgpath2, bb2 in tuples: imgpaths2.append(imgpath2) bbs2.append(bb2) closestdist, bbOut = get_closest_ncclk(imgpath, img, bb, imgpaths2, bbs2) if bestlabel == None or closestdist < mindist: bestlabel = label mindist = closestdist bbBest = bbOut return bestlabel, mindist, bbBest
def closest_label(imgpath, bb, exemplars): bestlabel = None mindist = None bbBest = None img = shared.standardImread(imgpath, flatten=True) for label, tuples in exemplars.iteritems(): imgpaths2, bbs2 = [], [] for imgpath2, bb2 in tuples: imgpaths2.append(imgpath2) bbs2.append(bb2) closestdist, bbOut = get_closest_ncclk( imgpath, img, bb, imgpaths2, bbs2) if bestlabel is None or closestdist < mindist: bestlabel = label mindist = closestdist bbBest = bbOut return bestlabel, mindist, bbBest
def global_align(Iref, imgpaths): """ Using IREF as a reference, aligns every image in IMGPATHS to IREF. Input: IplImage IREF: An OpenCV IplImage instance, i.e. the reference image we will align against. list IMGPATHS: A list of image paths. Output: list IOUTS. [(str imgpath, nparray H, IplImage Ireg, float err), ...]. IOUTS: A list of tuples containing the aligned image Ireg, along with the discovered transformation matrix H, alignment error ERR, and the path to the ballot image IMGPATH. """ Iouts = [] # [(imgpath, H, Ireg, err), ...] for imgpath in imgpaths: I = shared.standardImread(imgpath, flatten=True) Icrop = cropout_stuff(I, 0.2, 0.2, 0.2, 0.2) H, Ireg, err = imagesAlign(Icrop, Iref, trfm_type='rigid', rszFac=0.25) Ireg = np.nan_to_num(Ireg) Iouts.append((imgpath, H, Ireg, err)) return Iouts
def temp_match(I, bb, imList, bbSearch=None, bbSearches=None, rszFac=0.75, padSearch=0.75, padPatch=0.0): bb = list(bb) if bbSearch != None: bbSearch = list(bbSearch) if bbSearches != None: bbSearches = list(bbSearches) matchList = [] # (filename, left,right,up,down) I = np.round(shared.fastResize(I,rszFac)*255.)/255; bb[0] = bb[0]*rszFac bb[1] = bb[1]*rszFac bb[2] = bb[2]*rszFac bb[3] = bb[3]*rszFac [bbOut,bbOff]=shared.expand(bb[0],bb[1],bb[2],bb[3],I.shape[0],I.shape[1],padPatch) patchFoo = I[bbOut[0]:bbOut[1],bbOut[2]:bbOut[3]] patch = patchFoo[bbOff[0]:bbOff[1],bbOff[2]:bbOff[3]] if bbSearch != None: bbSearch[0] = bbSearch[0]*rszFac bbSearch[1] = bbSearch[1]*rszFac bbSearch[2] = bbSearch[2]*rszFac bbSearch[3] = bbSearch[3]*rszFac for cur_i, imP in enumerate(imList): if bbSearches != None: bbSearch = map(lambda c: c*rszFac, bbSearches[cur_i]) I1 = shared.standardImread(imP,flatten=True) I1 = np.round(shared.fastResize(I1,rszFac)*255.)/255. # crop to region if specified if bbSearch != None: [bbOut1,bbOff1]=shared.expand(bbSearch[0],bbSearch[1], bbSearch[2],bbSearch[3], I1.shape[0],I1.shape[1],padSearch) I1=I1[bbOut1[0]:bbOut1[1],bbOut1[2]:bbOut1[3]] if I1.shape[0] < patch.shape[0] or I1.shape[1] < patch.shape[1]: w_big = max(I1.shape[0], patch.shape[0]) h_big = max(I1.shape[1], patch.shape[1]) I1_big = np.zeros((w_big, h_big)).astype('float32') I1_big[0:I1.shape[0], 0:I1.shape[1]] = I1 I1 = I1_big patchCv=cv.fromarray(np.copy(patch)) ICv=cv.fromarray(np.copy(I1)) outCv=cv.CreateMat(abs(I1.shape[0]-patch.shape[0])+1,abs(I1.shape[1]-patch.shape[1])+1, cv.CV_32F) cv.MatchTemplate(ICv,patchCv,outCv,cv.CV_TM_CCOEFF_NORMED) Iout=np.asarray(outCv) Iout[Iout==1.0]=0.995; # opencv bug score1 = Iout.max() # NCC score YX=np.unravel_index(Iout.argmax(),Iout.shape) i1=YX[0]; i2=YX[0]+patch.shape[0] j1=YX[1]; j2=YX[1]+patch.shape[1] (err,diff,Ireg)=shared.lkSmallLarge(patch,I1,i1,i2,j1,j2, minArea=np.power(2, 17)) score2 = err / diff.size # pixel reg score if bbSearch != None: matchList.append((imP,score1,score2,Ireg, i1+bbOut1[0],i2+bbOut1[0], j1+bbOut1[2],j2+bbOut1[2],rszFac)) else: matchList.append((imP,score1,score2,Ireg, i1,i2,j1,j2,rszFac)) return matchList
def do_digit_group(b2imgs, img2b, partitions_map, partitions_invmap, partition_exmpls, badballotids, img2page, img2flip, attrinfo, digitexemplars_map, digitpatch_outdir, voteddir_root, digpatch2imgpath_outP, mode=GRP_PER_PARTITION): """ Input: dict B2IMGS: dict IMG2B: dict PARTITIONS_MAP: dict PARTITIONS_INVMAP: dict PARTITIONS_EXMPLS: list BADBALLOTIDS: List of quarantined/discarded ballot ids. dict IMG2PAGE: dict IMG2FLIP: maps {str imgpath: bool isflip} dict ATTRINFO: [x1,y1,x2,y2,attrtype,page,numdigits,digitdist] dict DIGITEXEMPLARS_MAP: maps {str digitval: [[str regionP, (y1,y2,x1,x2), str digitpatch_i], ...]} str DIGITPATCH_OUTDIR: Root dir of extracted digit patches. str VOTEDDIR_ROOT: Root dir of voted ballots. int MODE: Output: dict DRESULTS. maps {int ID: [str digitstr, imgpath, [[str digit_i, (x1,y1,x2,y2), score_i, digpatchP_i], ...]]}, where ID is partitionID/ballotID depending on MODE. """ x1, y1, x2, y2, attrtype, page, numdigits, digitdist = attrinfo # 0.) Depending on MODE, grab the image paths to work with. d_imgpaths = [] # imgpaths with the digit attribute present flip_map = {} # maps {str imgpath: bool isflip} if mode == GRP_PER_PARTITION: for partitionID, ballotIDs in partition_exmpls.iteritems(): imgpaths = b2imgs[ballotIDs[0]] imgpaths_ordered = sorted(imgpaths, key=lambda imP: img2page[imP]) d_imgpaths.append(imgpaths_ordered[page]) for imgpath in imgpaths_ordered: flip_map[imgpath] = img2flip[imgpath] else: for ballotID, imgpaths in b2imgs.iteritems(): if ballotID in badballotids: continue imgpaths_ordered = sorted(imgpaths, key=lambda imP: img2page[imP]) d_imgpaths.append(imgpaths_ordered[page]) flip_map = img2flip # 1.) Load the digit exemplars digit_ex_imgs = {} # maps {(str digit, str meta): nparray digit_img} for digit, exemplars in digitexemplars_map.iteritems(): for i, (regionP, bb, digitpatch) in enumerate(exemplars): I = shared.standardImread(digitpatch, flatten=True) digit_ex_imgs[(digit, i)] = I # 2.) Invoke digitParse bb = (y1, y2, x1, x2) rejected_hashes = {} accepted_hashes = {} # RESULTS: [(imgpath_i, ocrstr_i, imgpatches_i, patchcoords_i, scores_i), ...] pm_results = part_match.digitParse(digit_ex_imgs, d_imgpaths, bb, numdigits, flipmap=flip_map, rejected_hashes=rejected_hashes, accepted_hashes=accepted_hashes, hspace=digitdist) # 3.) Finally, munge PM_RESULTS into DRESULTS, and also extract # each digit patch into proj.digitpatch_out. dresults = {} extract_jobs = [] # [[imgpath, (x1,y1,x2,y2), outpath], ...] digpatch2imgpath = {} # maps {str digpatchpath: (str imgpath, int idx)} for (imgpath, ocrstr, imgpatches, patchcoords, scores) in pm_results: ballotid = img2b[imgpath] # Recreate directory structure rp = os.path.relpath(os.path.abspath(imgpath), os.path.abspath(voteddir_root)) imgname = os.path.splitext(os.path.split(imgpath)[1])[0] if mode == GRP_PER_PARTITION: id = partitions_invmap[ballotid] else: id = ballotid entry = [] for i,digit in enumerate(ocrstr): y1, y2, x1, x2 = patchcoords[i] digpatchP = pathjoin(digitpatch_outdir, rp, "{0}_dig{1}_{2}.png".format(imgname, digit, i)) entry.append([digit, (x1,y1,x2,y2), scores[i], digpatchP]) extract_jobs.append((imgpath, (x1,y1,x2,y2), digpatchP, img2flip[imgpath])) digpatch2imgpath[digpatchP] = (imgpath, i) row = (ocrstr, imgpath, entry) dresults[id] = row pickle.dump(digpatch2imgpath, open(digpatch2imgpath_outP, 'wb'), pickle.HIGHEST_PROTOCOL) print "...Extracting DigitPatches..." t = time.time() do_extract_digitpatches(extract_jobs) dur = time.time() - t print "...Finished extracting digit patches ({0} s).".format(dur) return dresults
def temp_match(I, bb, imList, bbSearch=None, bbSearches=None, rszFac=0.75, padSearch=0.75, padPatch=0.0): bb = list(bb) if bbSearch is not None: bbSearch = list(bbSearch) if bbSearches is not None: bbSearches = list(bbSearches) matchList = [] # (filename, left,right,up,down) I = np.round(shared.fastResize(I, rszFac) * 255.) / 255 bb[0] = bb[0] * rszFac bb[1] = bb[1] * rszFac bb[2] = bb[2] * rszFac bb[3] = bb[3] * rszFac [bbOut, bbOff] = shared.expand(bb[0], bb[1], bb[2], bb[3], I.shape[ 0], I.shape[1], padPatch) patchFoo = I[bbOut[0]:bbOut[1], bbOut[2]:bbOut[3]] patch = patchFoo[bbOff[0]:bbOff[1], bbOff[2]:bbOff[3]] if bbSearch is not None: bbSearch[0] = bbSearch[0] * rszFac bbSearch[1] = bbSearch[1] * rszFac bbSearch[2] = bbSearch[2] * rszFac bbSearch[3] = bbSearch[3] * rszFac for cur_i, imP in enumerate(imList): if bbSearches is not None: bbSearch = map(lambda c: c * rszFac, bbSearches[cur_i]) I1 = shared.standardImread(imP, flatten=True) I1 = np.round(shared.fastResize(I1, rszFac) * 255.) / 255. # crop to region if specified if bbSearch is not None: [bbOut1, bbOff1] = shared.expand(bbSearch[0], bbSearch[1], bbSearch[2], bbSearch[3], I1.shape[0], I1.shape[1], padSearch) I1 = I1[bbOut1[0]:bbOut1[1], bbOut1[2]:bbOut1[3]] if I1.shape[0] < patch.shape[0] or I1.shape[1] < patch.shape[1]: w_big = max(I1.shape[0], patch.shape[0]) h_big = max(I1.shape[1], patch.shape[1]) I1_big = np.zeros((w_big, h_big)).astype('float32') I1_big[0:I1.shape[0], 0:I1.shape[1]] = I1 I1 = I1_big patchCv = cv.fromarray(np.copy(patch)) ICv = cv.fromarray(np.copy(I1)) outCv = cv.CreateMat(abs(I1.shape[ 0] - patch.shape[0]) + 1, abs(I1.shape[1] - patch.shape[1]) + 1, cv.CV_32F) cv.MatchTemplate(ICv, patchCv, outCv, cv.CV_TM_CCOEFF_NORMED) Iout = np.asarray(outCv) Iout[Iout == 1.0] = 0.995 # opencv bug score1 = Iout.max() # NCC score YX = np.unravel_index(Iout.argmax(), Iout.shape) i1 = YX[0] i2 = YX[0] + patch.shape[0] j1 = YX[1] j2 = YX[1] + patch.shape[1] (err, diff, Ireg) = shared.lkSmallLarge( patch, I1, i1, i2, j1, j2, minArea=np.power(2, 17)) score2 = err / diff.size # pixel reg score if bbSearch is not None: matchList.append((imP, score1, score2, Ireg, i1 + bbOut1[0], i2 + bbOut1[0], j1 + bbOut1[2], j2 + bbOut1[2], rszFac)) else: matchList.append((imP, score1, score2, Ireg, i1, i2, j1, j2, rszFac)) return matchList
def cluster_imgpatchesV2(imgpaths, bb_map, init_clusters=None, THRESHOLD=0.95): """ Given a list of imgpaths, and bounding boxes for each image, cluster the bounding boxes from each image. Input: list imgpaths: dict bb_map: maps {str imgpath: (y1,y2,x1,x2)} list init_clusters: An initial set of cluster centers, of the form: {imgpath_i: (imgpath_i, bb_i)} float THRESHOLD: A cutoff value to use when determining if the patch was found. Ranges from [0.0, 1.0], where higher values is 'stricter', i.e. THRESHOLD=1.0 means only accept exact matches (not recommended). Higher values also means more computation time. Output: A dict of the form: {c_imgpath: [(imgpath_i, bb_i, score), ...} where each c_imgpath is the 'center' of a given cluster C. """ clusters = {} unlabeled_imgpaths = list(imgpaths) while unlabeled_imgpaths: curimgpath = unlabeled_imgpaths.pop() bb = bb_map[curimgpath] I = shared.standardImread(curimgpath, flatten=True) _t = time.time() print "...calling find_patch_matchesV1..." matches = partask.do_partask(findpatchmatches, unlabeled_imgpaths, _args=(I, bb, bb, THRESHOLD)) print "...finished find_patch_matchesV1 ({0} s)".format(time.time() - _t) # Manually add in I matches.append( (curimgpath, -1.0, 1.0, None, bb[0], bb[1], bb[2], bb[3], 1.0)) if matches: # 0.) Retrieve best matches from matches (may have multiple # matches for the same imagepath) print "...number of pre-filtered matches: {0}".format(len(matches)) bestmatches = { } # maps {imgpath: (imgpath,sc1,sc2,Ireg,y1,y2,x1,x2,rszFac)} for (filename, sc1, sc2, Ireg, y1, y2, x1, x2, rszFac) in matches: y1, y2, x1, x2 = map(lambda c: int(round(c / rszFac)), (y1, y2, x1, x2)) if filename not in bestmatches: bestmatches[filename] = (filename, sc1, sc2, y1, y2, x1, x2, rszFac) else: old_sc2 = bestmatches[filename][2] if sc2 < old_sc2: bestmatches[filename] = (filename, sc1, sc2, y1, y2, x1, x2, rszFac) print "...found {0} matches".format(len(bestmatches)) # 1.) Handle the best matches for _, (filename, sc1, sc2, y1, y2, x1, x2, rszFac) in bestmatches.iteritems(): if filename in unlabeled_imgpaths: unlabeled_imgpaths.remove(filename) clusters.setdefault(curimgpath, []).append( (filename, (y1, y2, x1, x2), sc2)) else: print "...Uh oh, no matches found. This shouldnt' have \ happened." pdb.set_trace() print "...Completed clustering. Found {0} clusters.".format(len(clusters)) return clusters