diff --git a/.idea/SynthText.iml b/.idea/SynthText.iml deleted file mode 100644 index 6711606..0000000 --- a/.idea/SynthText.iml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index c139e1c..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 1757dd2..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f7ca6b1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +FROM python:3.7-buster + +# For japanese +RUN apt-get update && apt-get install -y ffmpeg libsm6 libxext6 git libmecab2 libmecab-dev mecab mecab-ipadic mecab-ipadic-utf8 mecab-utils vim \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# jupyter notebook libs +RUN pip install jupyterlab +RUN pip install traitlets==5.1.1 +RUN pip install "ipykernel<5.5.2" + +WORKDIR /workspace +COPY ./ /workspace/ +RUN python -m pip install -r /workspace/requirements.txt + +ENV TZ=Asia/Singapore +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +WORKDIR /workspace \ No newline at end of file diff --git a/README.md b/README.md index 3b9ed06..6c0d616 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,9 @@ Add support for chinese ![Japanese example 4](results/sample4.png "Synthetic Japanese Text Samples 4") -The library is written in Python. The main dependencies are: +The code in the `master` branch is for Python2. Python3 is supported in the `python3` branch. + +The main dependencies are: ``` pygame, opencv (version 3.3), PIL (Image), numpy, matplotlib, h5py, scipy @@ -119,20 +121,29 @@ For an explanation of the fields in `dset.h5` (e.g.: `seg`,`area`,`label`), plea ### Pre-processed Background Images The 8,000 background images used in the paper, along with their segmentation and depth masks, have been uploaded here: -`http://zeus.robots.ox.ac.uk/textspot/static/db/`, where, `` can be: +`http://www.robots.ox.ac.uk/~vgg/data/scenetext/preproc/`, where, `` can be: + +| filenames | size | description | md5 hash | +|:--------------- | ----:|:---------------------------------------------------- |:-------------------------------- | +| `imnames.cp` | 180K | names of images which do not contain background text | | +| `bg_img.tar.gz` | 8.9G | images (filter these using `imnames.cp`) | 3eac26af5f731792c9d95838a23b5047 | +| `depth.h5` | 15G | depth maps | af97f6e6c9651af4efb7b1ff12a5dc1b | +| `seg.h5` | 6.9G | segmentation maps | 1605f6e629b2524a3902a5ea729e86b2 | + +Note: due to large size, `depth.h5` is also available for download as 3-part split-files of 5G each. +These part files are named: `depth.h5-00, depth.h5-01, depth.h5-02`. Download using the path above, and put them together using `cat depth.h5-0* > depth.h5`. -- `imnames.cp` [180K]: names of filtered files, i.e., those files which do not contain text -- `bg_img.tar.gz` [8.9G]: compressed image files (more than 8000, so only use the filtered ones in imnames.cp) -- `depth.h5` [15G]: depth maps -- `seg.h5` [6.9G]: segmentation maps +[`use_preproc_bg.py`](https://github.com/ankush-me/SynthText/blob/master/use_preproc_bg.py) provides sample code for reading this data. Note: I do not own the copyright to these images. ### Generating Samples with Text in non-Latin (English) Scripts -@JarveeLee has modified the pipeline for generating samples with Chinese text [here](https://github.com/JarveeLee/SynthText_Chinese_version). -@gachiemchiep has modified the pipeline for generating samples with Japanese text [here](https://github.com/gachiemchiep/SynthText). - +- @JarveeLee has modified the pipeline for generating samples with Chinese text [here](https://github.com/JarveeLee/SynthText_Chinese_version). +- @adavoudi has modified it for arabic/persian script, which flows from right-to-left [here](https://github.com/adavoudi/SynthText). +- @MichalBusta has adapted it for a number of languages (e.g. Bangla, Arabic, Chinese, Japanese, Korean) [here](https://github.com/MichalBusta/E2E-MLT). +- @gachiemchiep has adapted for Japanese [here](https://github.com/gachiemchiep/SynthText). +- @gungui98 has adapted for Vietnamese [here](https://github.com/gungui98/SynthText). +- @youngkyung has adapted for Korean [here](https://github.com/youngkyung/SynthText_kr). ### Further Information Please refer to the paper for more information, or contact me (email address in the paper). - diff --git a/colorize3_poisson.py b/colorize3_poisson.py index befd4e7..3cad231 100644 --- a/colorize3_poisson.py +++ b/colorize3_poisson.py @@ -6,11 +6,12 @@ import scipy.ndimage.interpolation as sii import os import os.path as osp -import cPickle as cp +#import cPickle as cp +import _pickle as cp #import Image from PIL import Image from poisson_reconstruct import blit_images - +import pickle def sample_weighted(p_dict): ps = p_dict.keys() @@ -38,14 +39,18 @@ def __init__(self,alpha,color): elif color.ndim==3: #rgb image self.color = color.copy().astype('uint8') else: - print color.shape + print (color.shape) raise Exception("color datatype not understood") class FontColor(object): def __init__(self, col_file): - with open(col_file,'r') as f: - self.colorsRGB = cp.load(f) + with open(col_file,'rb') as f: + #self.colorsRGB = cp.load(f) + u = pickle._Unpickler(f) + u.encoding = 'latin1' + p = u.load() + self.colorsRGB = p self.ncol = self.colorsRGB.shape[0] # convert color-means from RGB to LAB for better nearest neighbour @@ -402,7 +407,7 @@ def check_perceptible(self, txt_mask, bg, txt_bg): diff = np.linalg.norm(bg_px-txt_px,ord=None,axis=1) diff = np.percentile(diff,[10,30,50,70,90]) - print "color diff percentile :", diff + print ("color diff percentile :", diff) return diff, (bgo,txto) def color(self, bg_arr, text_arr, hs, place_order=None, pad=20): @@ -425,7 +430,7 @@ def color(self, bg_arr, text_arr, hs, place_order=None, pad=20): # initialize the placement order: if place_order is None: - place_order = np.array(xrange(len(text_arr))) + place_order = np.array(range(len(text_arr))) rendered = [] for i in place_order[::-1]: diff --git a/common.py b/common.py index b217734..4982573 100644 --- a/common.py +++ b/common.py @@ -25,17 +25,17 @@ def colorprint(colorcode, text, o=sys.stdout, bold=False): o.write(colorize(colorcode, text, bold=bold)) def warn(msg): - print colorize(Color.YELLOW, msg) + print (colorize(Color.YELLOW, msg)) def error(msg): - print colorize(Color.RED, msg) + print (colorize(Color.RED, msg)) # http://stackoverflow.com/questions/366682/how-to-limit-execution-time-of-a-function-call-in-python class TimeoutException(Exception): pass @contextmanager def time_limit(seconds): def signal_handler(signum, frame): - raise TimeoutException, colorize(Color.RED, " *** Timed out!", highlight=True) + raise TimeoutException(colorize(Color.RED, " *** Timed out!", highlight=True)) signal.signal(signal.SIGALRM, signal_handler) signal.alarm(seconds) try: diff --git a/gen.py b/gen.py index 2f4cd2f..76ef6eb 100644 --- a/gen.py +++ b/gen.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -#-*- coding: utf-8 -*- +# -*- coding: utf-8 -*- # Author: Ankush Gupta # Date: 2015 @@ -37,15 +37,15 @@ OUT_FILE = 'results/SynthText.h5' OUT_DIR = 'results' + def get_data(): """ - Download the image,depth and segmentation data: - Returns, the h5 database. - """ + Download the image,depth and segmentation data: + Returns, the h5 database. + """ if not osp.exists(DB_FNAME): try: - colorprint(Color.BLUE, '\tdownloading data (56 M) from: ' + DATA_URL, bold=True) - print + print('\tdownloading data (56 M) from: ' + DATA_URL) sys.stdout.flush() out_fname = 'data.tar.gz' wget.download(DATA_URL, out=out_fname) @@ -53,10 +53,10 @@ def get_data(): tar.extractall() tar.close() os.remove(out_fname) - colorprint(Color.BLUE, '\n\tdata saved at:' + DB_FNAME, bold=True) + print('\n\tdata saved at:' + DB_FNAME) sys.stdout.flush() except: - print colorize(Color.RED, 'Data not found and have problems downloading.', bold=True) + print('Data not found and have problems downloading.') sys.stdout.flush() sys.exit(-1) # open the h5 file and return: @@ -65,19 +65,18 @@ def get_data(): def add_res_to_db(imgname, res, db): """ - Add the synthetically generated text image instance - and other metadata to the dataset. - """ + Add the synthetically generated text image instance + and other metadata to the dataset. + """ ninstance = len(res) - for i in xrange(ninstance): + for i in range(ninstance): dname = "%s_%d" % (imgname, i) db['data'].create_dataset(dname, data=res[i]['img']) db['data'][dname].attrs['charBB'] = res[i]['charBB'] db['data'][dname].attrs['wordBB'] = res[i]['wordBB'] - + db['data'][dname].attrs['txt'] = res[i]['txt'] text_utf8 = [char.encode('utf8') for char in res[i]['txt']] - db['data'][dname].attrs['txt'] = text_utf8 - + db['data'][dname].attrs['txt_utf8'] = text_utf8 def save_res_to_imgs(imgname, res): """ @@ -85,23 +84,22 @@ def save_res_to_imgs(imgname, res): and other metadata to the dataset. """ ninstance = len(res) - for i in xrange(ninstance): + for i in range(ninstance): filename = "{}/{}_{}.png".format(OUT_DIR, imgname, i) # Swap bgr to rgb so we can save into image file img = res[i]['img'][..., [2, 1, 0]] cv2.imwrite(filename, img) - def main(viz=False): # open databases: - print colorize(Color.BLUE, 'getting data..', bold=True) + print('getting data..') db = get_data() - print colorize(Color.BLUE, '\t-> done', bold=True) + print('\t-> done') # open the output h5 file: - out_db = h5py.File(OUT_FILE,'w') + out_db = h5py.File(OUT_FILE, 'w') out_db.create_group('/data') - print colorize(Color.GREEN,'Storing the output in: '+OUT_FILE, bold=True) + print('Storing the output in: ' + OUT_FILE) # get the names of the image files in the dataset: imnames = sorted(db['image'].keys()) @@ -112,7 +110,7 @@ def main(viz=False): start_idx, end_idx = 0, min(NUM_IMG, N) RV3 = RendererV3(DATA_PATH, max_time=SECS_PER_IMG, lang=args.lang) - for i in xrange(start_idx, end_idx): + for i in range(start_idx, end_idx): imname = imnames[i] try: # get the image: @@ -130,23 +128,23 @@ def main(viz=False): # re-size uniformly: sz = depth.shape[:2][::-1] - img = np.array(img.resize(sz, Image.ANTIALIAS)) - seg = np.array(Image.fromarray(seg).resize(sz, Image.NEAREST)) + img = np.array(img.resize(sz, Image.Resampling.LANCZOS)) + seg = np.array(Image.fromarray(seg).resize(sz, Image.Resampling.NEAREST)) - print colorize(Color.RED, '%d of %d' % (i, end_idx - 1), bold=True) + print('%d of %d' % (i, end_idx - 1)) res = RV3.render_text(img, depth, seg, area, label, ninstance=INSTANCE_PER_IMAGE, viz=viz) if len(res) > 0: # non-empty : successful in placing text: - add_res_to_db(imname,res,out_db) + add_res_to_db(imname, res, out_db) # visualize the output: if viz: save_res_to_imgs(imname, res) - if 'q' in raw_input(colorize(Color.RED, 'continue? (enter to continue, q to exit): ', True)): + if 'q' in input('continue? (enter to continue, q to exit): '): break except: traceback.print_exc() - print colorize(Color.GREEN, '>>>> CONTINUING....', bold=True) + print('>>>> CONTINUING....') continue db.close() out_db.close() @@ -155,10 +153,10 @@ def main(viz=False): if __name__ == '__main__': import argparse - parser = argparse.ArgumentParser(description='Genereate Synthetic Scene-Text Images') + parser = argparse.ArgumentParser(description='Generate Synthetic Scene-Text Images') parser.add_argument('--viz', action='store_true', dest='viz', default=False, help='flag for turning on visualizations') parser.add_argument('--lang', default='ENG', - help='Select language : ENG/JPN') + help='Select language : ENG or JPN') args = parser.parse_args() main(args.viz) diff --git a/invert_font_size.py b/invert_font_size.py index ee70eaa..fb08179 100644 --- a/invert_font_size.py +++ b/invert_font_size.py @@ -18,9 +18,8 @@ models = {} # linear model FS = FontState() -# plt.figure() -# plt.hold(True) -for i in xrange(len(FS.fonts)): + +for i in range(len(FS.fonts)): font = freetype.Font(FS.fonts[i], size=12) h = [] for y in ys: diff --git a/poisson_reconstruct.py b/poisson_reconstruct.py index b49eab8..59f1453 100644 --- a/poisson_reconstruct.py +++ b/poisson_reconstruct.py @@ -99,7 +99,7 @@ def blit_images(im_top,im_back,scale_grad=1.0,mode='max'): im_res = np.zeros_like(im_top) # frac of gradients which come from source: - for ch in xrange(im_top.shape[2]): + for ch in range(im_top.shape[2]): ims = im_top[:,:,ch] imd = im_back[:,:,ch] @@ -203,7 +203,7 @@ def contiguous_regions(mask): # plt.imshow(im_alpha_L) # plt.show() - for i in xrange(500,im_alpha_L.shape[1],5): + for i in range(500,im_alpha_L.shape[1],5): l_actual = im_actual_L[i,:]#-im_actual_L[i,:-1] l_alpha = im_alpha_L[i,:]#-im_alpha_L[i,:-1] l_poisson = im_poisson_L[i,:]#-im_poisson_L[i,:-1] @@ -212,7 +212,6 @@ def contiguous_regions(mask): with sns.axes_style("darkgrid"): plt.subplot(2,1,2) plt.plot(l_alpha,label='alpha') - plt.hold(True) plt.plot(l_poisson,label='poisson') plt.plot(l_actual,label='actual') plt.legend() @@ -227,7 +226,6 @@ def contiguous_regions(mask): with sns.axes_style("white"): plt.subplot(2,1,1) plt.imshow(im_alpha[:,:,::-1].astype('uint8')) - plt.hold(True) plt.plot([0,im_alpha_L.shape[0]-1],[i,i],'r') plt.axis('image') plt.show() diff --git a/prep_scripts/floodFill.py b/prep_scripts/floodFill.py index 1f61ef1..10596f6 100644 --- a/prep_scripts/floodFill.py +++ b/prep_scripts/floodFill.py @@ -13,11 +13,11 @@ import h5py import os.path as osp import multiprocessing as mp -import traceback, sys + def get_seed(sx,sy,ucm): n = sx.size - for i in xrange(n): + for i in range(n): if ucm[sx[i]+1,sy[i]+1] == 0: return (sy[i],sx[i]) @@ -41,7 +41,7 @@ def get_mask(ucm,viz=False): sx,sy = np.where(mask==0) seed = get_seed(sx,sy,ucm) i += 1 - print " > terminated in %d steps"%i + print (" > terminated in %d steps"%i) if viz: plt.imshow(mask) @@ -81,7 +81,7 @@ def get_imname(self,i): return "".join(map(chr, self.ucm_h5[self.ucm_h5['names'][0,self.i]][:])) def __stop__(self): - print "DONE" + print ("DONE") self.ucm_h5.close() raise StopIteration @@ -101,14 +101,14 @@ def get_valid_name(self): def next(self): imname = self.get_valid_name() - print "%d of %d"%(self.i+1,self.N) + print ("%d of %d"%(self.i+1,self.N)) ucm = self.ucm_h5[self.ucm_h5['ucms'][0,self.i]][:] ucm = ucm.copy() self.i += 1 return ((ucm>self.th).astype('uint8'),imname) ucm_iter = ucm_iterable(db_path,th) - print "cpu count: ", mp.cpu_count() + print ("cpu count: ", mp.cpu_count()) parpool = mp.Pool(4) ucm_result = parpool.imap_unordered(get_mask_parallel, ucm_iter, chunksize=1) @@ -116,16 +116,16 @@ def next(self): if res is None: continue ((mask,area,label),imname) = res - print "got back : ", imname + print ("got back : ", imname) mask = mask.astype('uint16') mask_dset = dbo_mask.create_dataset(imname, data=mask) mask_dset.attrs['area'] = area mask_dset.attrs['label'] = label # close the h5 files: - print "closing DB" + print ("closing DB") dbo.close() - print ">>>> DONE" + print (">>>> DONE") base_dir = '/home/' # directory containing the ucm.mat, i.e., output of run_ucm.m diff --git a/ransac.py b/ransac.py index cb5b1fc..5bd271d 100644 --- a/ransac.py +++ b/ransac.py @@ -30,7 +30,7 @@ def fit_plane_ransac(pts, neighbors=None,z_pos=None, dist_inlier=0.05, """ n,_ = pts.shape ninlier,models = [],[] - for i in xrange(max_iter): + for i in range(max_iter): if neighbors is None: p = pts[np.random.choice(pts.shape[0],nsample,replace=False),:] else: @@ -43,7 +43,7 @@ def fit_plane_ransac(pts, neighbors=None,z_pos=None, dist_inlier=0.05, models.append(m) if models == []: - print "RANSAC plane fitting failed!" + print ("RANSAC plane fitting failed!") return #None else: #refit the model to inliers: ninlier = np.array(ninlier) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f105c63 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,13 @@ +cycler +h5py +matplotlib +opencv-python +nltk +numpy +Pillow +pygame +pyparsing +pytz +scipy +six +wget diff --git a/synth_utils.py b/synth_utils.py index ed8adc4..b517c61 100644 --- a/synth_utils.py +++ b/synth_utils.py @@ -233,6 +233,7 @@ def ssc(v): """ Returns the skew-symmetric cross-product matrix corresponding to v. """ + v += np.finfo("float").eps v /= np.linalg.norm(v) return np.array([[ 0, -v[2], v[1]], [ v[2], 0, -v[0]], @@ -271,7 +272,7 @@ def unrotate2d(pts): elif R[1,1]<0: R[:,1] *= -1 else: - print "Rotation matrix not understood" + print ("Rotation matrix not understood") return if R[0,0]<0 and R[1,1]<0: R *= -1 diff --git a/synthgen.py b/synthgen.py index 75e5aa2..fe303df 100644 --- a/synthgen.py +++ b/synthgen.py @@ -91,7 +91,7 @@ def filter(seg,area,label): # filter bad regions: filt = np.array(filt) area = area[filt] - R = [R[i] for i in xrange(len(R)) if filt[i]] + R = [R[i] for i in range(len(R)) if filt[i]] # sort the regions based on areas: aidx = np.argsort(-area) @@ -111,7 +111,7 @@ def sample_grid_neighbours(mask,nsample,step=3): y_m,x_m = np.where(mask) mask_idx = np.zeros_like(mask,'int32') - for i in xrange(len(y_m)): + for i in range(len(y_m)): mask_idx[y_m[i],x_m[i]] = i xp,xn = np.zeros_like(mask), np.zeros_like(mask) @@ -136,7 +136,7 @@ def sample_grid_neighbours(mask,nsample,step=3): Y = np.transpose(np.c_[ys,ys+s,ys-s,ys+s,ys-s][:,:,None],(1,2,0)) sample_idx = np.concatenate([Y,X],axis=1) mask_nn_idx = np.zeros((5,sample_idx.shape[-1]),'int32') - for i in xrange(sample_idx.shape[-1]): + for i in range(sample_idx.shape[-1]): mask_nn_idx[:,i] = mask_idx[sample_idx[:,:,i][:,0],sample_idx[:,:,i][:,1]] return mask_nn_idx @@ -215,9 +215,9 @@ def get_text_placement_mask(xyz,mask,plane,pad=2,viz=False): REGION : DICT output of TextRegions.get_regions PAD : number of pixels to pad the placement-mask by """ - _, contour,hier = cv2.findContours(mask.copy().astype('uint8'), + contour,hier = cv2.findContours(mask.copy().astype('uint8'), mode=cv2.RETR_CCOMP, - method=cv2.CHAIN_APPROX_SIMPLE) + method=cv2.CHAIN_APPROX_SIMPLE)[-2:] contour = [np.squeeze(c).astype('float') for c in contour] #plane = np.array([plane[1],plane[0],plane[2],plane[3]]) H,W = mask.shape[:2] @@ -226,7 +226,7 @@ def get_text_placement_mask(xyz,mask,plane,pad=2,viz=False): pts,pts_fp = [],[] center = np.array([W,H])/2 n_front = np.array([0.0,0.0,-1.0]) - for i in xrange(len(contour)): + for i in range(len(contour)): cnt_ij = contour[i] xyz = su.DepthCamera.plane2xyz(center, cnt_ij, plane) R = su.rot3d(plane[:3],n_front) @@ -248,7 +248,7 @@ def get_text_placement_mask(xyz,mask,plane,pad=2,viz=False): # the same scale as the target region: s = rescale_frontoparallel(pts_tmp,boxR,pts[0]) boxR *= s - for i in xrange(len(pts_fp)): + for i in range(len(pts_fp)): pts_fp[i] = s*((pts_fp[i]-mu[None,:]).dot(R2d.T) + mu[None,:]) # paint the unrotated contour points: @@ -258,7 +258,7 @@ def get_text_placement_mask(xyz,mask,plane,pad=2,viz=False): place_mask = 255*np.ones((int(np.ceil(COL))+pad, int(np.ceil(ROW))+pad), 'uint8') - pts_fp_i32 = [(pts_fp[i]+minxy[None,:]).astype('int32') for i in xrange(len(pts_fp))] + pts_fp_i32 = [(pts_fp[i]+minxy[None,:]).astype('int32') for i in range(len(pts_fp))] cv2.drawContours(place_mask,pts_fp_i32,-1,0, thickness=cv2.FILLED, lineType=8,hierarchy=hier) @@ -279,8 +279,7 @@ def get_text_placement_mask(xyz,mask,plane,pad=2,viz=False): plt.imshow(mask) plt.subplot(1,2,2) plt.imshow(~place_mask) - plt.hold(True) - for i in xrange(len(pts_fp_i32)): + for i in range(len(pts_fp_i32)): plt.scatter(pts_fp_i32[i][:,0],pts_fp_i32[i][:,1], edgecolors='none',facecolor='g',alpha=0.5) plt.show() @@ -318,7 +317,7 @@ def mean_seg(rgb,seg,label): plt.close(fignum) plt.figure(fignum) ims = [rgb,mim,depth,img] - for i in xrange(len(ims)): + for i in range(len(ims)): plt.subplot(2,2,i+1) plt.imshow(ims[i]) plt.show(block=False) @@ -337,9 +336,9 @@ def viz_regions(img,xyz,seg,planes,labels): xyz_region = xyz[mask,:] su.visualize_plane(xyz_region,np.array(planes[i])) - mym.view(180,180) - mym.orientation_axes() - mym.show(True) +# mym.view(180,180) +# mym.orientation_axes() +# mym.show(True) def viz_textbb(fignum,text_im, bb_list,alpha=1.0): """ @@ -349,12 +348,11 @@ def viz_textbb(fignum,text_im, bb_list,alpha=1.0): plt.close(fignum) plt.figure(fignum) plt.imshow(text_im) - plt.hold(True) H,W = text_im.shape[:2] - for i in xrange(len(bb_list)): + for i in range(len(bb_list)): bbs = bb_list[i] ni = bbs.shape[-1] - for j in xrange(ni): + for j in range(ni): bb = bbs[:,:,j] bb = np.c_[bb,bb[:,0]] plt.plot(bb[0,:], bb[1,:], 'r', linewidth=2, alpha=alpha) @@ -552,7 +550,7 @@ def char2wordBB(self, charBB, text): bb_idx = np.r_[0, np.cumsum([len(w) for w in wrds])] wordBB = np.zeros((2,4,len(wrds)), 'float32') - for i in xrange(len(wrds)): + for i in range(len(wrds)): cc = charBB[:,:,bb_idx[i]:bb_idx[i+1]] # fit a rotated-rectangle: @@ -570,7 +568,7 @@ def char2wordBB(self, charBB, text): cc[3,:]].T perm4 = np.array(list(itertools.permutations(np.arange(4)))) dists = [] - for pidx in xrange(perm4.shape[0]): + for pidx in range(perm4.shape[0]): d = np.sum(np.linalg.norm(box[perm4[pidx],:]-cc_tblr,axis=1)) dists.append(d) wordBB[:,:,i] = box[perm4[np.argmin(dists)],:].T @@ -626,10 +624,10 @@ def render_text(self,rgb,depth,seg,area,label,ninstance=1,viz=False): return [] res = [] - for i in xrange(ninstance): + for i in range(ninstance): place_masks = copy.deepcopy(regions['place_mask']) - print colorize(Color.CYAN, " ** instance # : %d"%i) + print (" ** instance # : %d"%i) idict = {'img':[], 'charBB':None, 'wordBB':None, 'txt':None} @@ -649,24 +647,10 @@ def render_text(self,rgb,depth,seg,area,label,ninstance=1,viz=False): reg_range = np.arange(NUM_REP * num_txt_regions) % num_txt_regions for idx in reg_range: ireg = reg_idx[idx] - try: - if self.max_time is None: - txt_render_res = self.place_text(img,place_masks[ireg], - regions['homography'][ireg], - regions['homography_inv'][ireg]) - else: - with time_limit(self.max_time): - txt_render_res = self.place_text(img,place_masks[ireg], - regions['homography'][ireg], - regions['homography_inv'][ireg]) - except TimeoutException, msg: - print msg - continue - except: - traceback.print_exc() - # some error in placing text on the region - continue - + txt_render_res = self.place_text(img,place_masks[ireg], + regions['homography'][ireg], + regions['homography_inv'][ireg]) + if txt_render_res is not None: placed = True img,text,bb,collision_mask = txt_render_res @@ -687,6 +671,6 @@ def render_text(self,rgb,depth,seg,area,label,ninstance=1,viz=False): viz_textbb(1,img, [idict['wordBB']], alpha=1.0) viz_masks(2,img,seg,depth,regions['label']) # viz_regions(rgb.copy(),xyz,seg,regions['coeff'],regions['label']) - if i < ninstance-1: - raw_input(colorize(Color.BLUE,'continue?',True)) + # if i < ninstance-1: + # input('continue?') return res diff --git a/text_utils.py b/text_utils.py index be6080b..2bc0e56 100644 --- a/text_utils.py +++ b/text_utils.py @@ -8,7 +8,8 @@ import os.path as osp import random, os import cv2 -import cPickle as cp + +import _pickle as cp import scipy.signal as ssig import scipy.stats as sstat import pygame, pygame.locals @@ -17,7 +18,6 @@ from PIL import Image import math from common import * -import codecs from logger import logger import nltk, re, pprint @@ -27,10 +27,12 @@ from nltk.text import Text from nltk.corpus.reader.chasen import * import subprocess +import pickle def sample_weighted(p_dict): - ps = p_dict.keys() - return p_dict[np.random.choice(ps,p=ps)] + key_list = list(p_dict.keys()) + chosen = key_list[np.random.randint(0, len(key_list))] + return p_dict[chosen] def move_bb(bbs, t): """ @@ -57,7 +59,7 @@ def crop_safe(arr, rect, bbs=[], pad=0): v1 = [min(arr.shape[0], rect[0]+rect[2]), min(arr.shape[1], rect[1]+rect[3])] arr = arr[v0[0]:v1[0],v0[1]:v1[1],...] if len(bbs) > 0: - for i in xrange(len(bbs)): + for i in range(len(bbs)): bbs[i,0] -= v0[0] bbs[i,1] -= v0[1] return arr, bbs @@ -195,9 +197,9 @@ def render_curved(self, font, word_text): # baseline state mid_idx = wl//2 BS = self.baselinestate.get_sample() - curve = [BS['curve'](i-mid_idx) for i in xrange(wl)] + curve = [BS['curve'](i-mid_idx) for i in range(wl)] curve[mid_idx] = -np.sum(curve) / (wl-1) - rots = [-int(math.degrees(math.atan(BS['diff'](i-mid_idx)/(font.size/2)))) for i in xrange(wl)] + rots = [-int(math.degrees(math.atan(BS['diff'](i-mid_idx)/(font.size/2)))) for i in range(wl)] bbs = [] # place middle char @@ -213,7 +215,7 @@ def render_curved(self, font, word_text): # render chars to the left and right: last_rect = rect ch_idx = [] - for i in xrange(wl): + for i in range(wl): #skip the middle character if i==mid_idx: bbs.append(mid_ch_bb) @@ -325,7 +327,7 @@ def bb_xywh2coords(self,bbs): """ n,_ = bbs.shape coords = np.zeros((2,4,n)) - for i in xrange(n): + for i in range(n): coords[:,:,i] = bbs[i,:2][:,None] coords[0,1,i] += bbs[i,2] coords[:,2,i] += bbs[i,2:4] @@ -431,13 +433,21 @@ def __init__(self, data_dir='data'): font_model_path = osp.join(data_dir, 'models/font_px2pt.cp') # get character-frequencies in the English language: - with open(char_freq_path,'r') as f: - self.char_freq = cp.load(f) + with open(char_freq_path,'rb') as f: + #self.char_freq = cp.load(f) + u = pickle._Unpickler(f) + u.encoding = 'latin1' + p = u.load() + self.char_freq = p # get the model to convert from pixel to font pt size: - with open(font_model_path,'r') as f: - self.font_model = cp.load(f) - + with open(font_model_path,'rb') as f: + #self.font_model = cp.load(f) + u = pickle._Unpickler(f) + u.encoding = 'latin1' + p = u.load() + self.font_model = p + # get the names of fonts to use: self.FONT_LIST = osp.join(data_dir, 'fonts/fontlist.txt') self.fonts = [os.path.join(data_dir,'fonts',f.strip()) for f in open(self.FONT_LIST)] @@ -455,7 +465,7 @@ def get_aspect_ratio(self, font, size=None): # get the [height,width] of each character: try: sizes = font.get_metrics(chars,size) - good_idx = [i for i in xrange(len(sizes)) if sizes[i] is not None] + good_idx = [i for i in range(len(sizes)) if sizes[i] is not None] sizes,w = [sizes[i] for i in good_idx], w[good_idx] sizes = np.array(sizes).astype('float')[:,[3,4]] r = np.abs(sizes[:,1]/sizes[:,0]) # width/height @@ -558,11 +568,11 @@ def __init__(self, min_nchar, fn, lang="ENG"): # convert fs into chasen file _, ext = os.path.splitext(os.path.basename(fn)) fn_chasen = fn.replace(ext, ".chasen") - print "Convert {} into {}".format(fn, fn_chasen) + print ("Convert {} into {}".format(fn, fn_chasen)) cmd = "mecab -Ochasen {} > {}".format(fn, fn_chasen) - print "The following cmd below was executed to convert into chasen (for Japanese)" - print "\t{}".format(cmd) + print ("The following cmd below was executed to convert into chasen (for Japanese)") + print ("\t{}".format(cmd)) p = subprocess.call(cmd, shell=True) data = ChasenCorpusReader('./', fn_chasen, encoding='utf-8') @@ -636,7 +646,7 @@ def center_align(self, lines): """ ls = [len(l) for l in lines] max_l = max(ls) - for i in xrange(len(lines)): + for i in range(len(lines)): l = lines[i].strip() dl = max_l-ls[i] lspace = dl//2 @@ -676,9 +686,9 @@ def h_lines(niter=100): lines[i] = lines[i][:len(lines[i])-lines[i][::-1].find(' ')].strip() if not np.all(self.is_good(lines,f)): - return #None + return else: - return lines + return [''.join(line) if type(line)==list else line for line in lines] def sample(self, nline_max,nchar_max,kind='WORD'): return self.fdict[kind](nline_max,nchar_max) @@ -708,7 +718,7 @@ def sample_line(self,nline_max,nchar_max): # get number of words: nword = [self.p_line_nword[2]*sstat.beta.rvs(a=self.p_line_nword[0], b=self.p_line_nword[1]) - for _ in xrange(nline)] + for _ in range(nline)] nword = [max(1,int(np.ceil(n))) for n in nword] lines = self.get_lines(nline, nword, nchar_max, f=0.35) @@ -724,7 +734,7 @@ def sample_para(self,nline_max,nchar_max): # get number of words: nword = [self.p_para_nword[2]*sstat.beta.rvs(a=self.p_para_nword[0], b=self.p_para_nword[1]) - for _ in xrange(nline)] + for _ in range(nline)] nword = [max(1,int(np.ceil(n))) for n in nword] lines = self.get_lines(nline, nword, nchar_max, f=0.35) diff --git a/visualize_results.py b/visualize_results.py index 92091ef..c143635 100644 --- a/visualize_results.py +++ b/visualize_results.py @@ -24,26 +24,25 @@ def viz_textbb(text_im, charBB_list, wordBB, alpha=1.0): plt.close(1) plt.figure(1) plt.imshow(text_im) - plt.hold(True) H,W = text_im.shape[:2] # plot the character-BB: - for i in xrange(len(charBB_list)): + for i in range(len(charBB_list)): bbs = charBB_list[i] ni = bbs.shape[-1] - for j in xrange(ni): + for j in range(ni): bb = bbs[:,:,j] bb = np.c_[bb,bb[:,0]] plt.plot(bb[0,:], bb[1,:], 'r', alpha=alpha/2) # plot the word-BB: - for i in xrange(wordBB.shape[-1]): + for i in range(wordBB.shape[-1]): bb = wordBB[:,:,i] bb = np.c_[bb,bb[:,0]] plt.plot(bb[0,:], bb[1,:], 'g', alpha=alpha) # visualize the indiv vertices: vcol = ['r','g','b','k'] - for j in xrange(4): + for j in range(4): plt.scatter(bb[0,j],bb[1,j],color=vcol[j]) plt.gca().set_xlim([0,W-1]) @@ -53,7 +52,7 @@ def viz_textbb(text_im, charBB_list, wordBB, alpha=1.0): def main(db_fname): db = h5py.File(db_fname, 'r') dsets = sorted(db['data'].keys()) - print "total number of images : ", colorize(Color.RED, len(dsets), highlight=True) + print ("total number of images : ", colorize(Color.RED, len(dsets), highlight=True)) for k in dsets: rgb = db['data'][k][...] charBB = db['data'][k].attrs['charBB'] @@ -61,12 +60,12 @@ def main(db_fname): txt = db['data'][k].attrs['txt'] viz_textbb(rgb, [charBB], wordBB) - print "image name : ", colorize(Color.RED, k, bold=True) - print " ** no. of chars : ", colorize(Color.YELLOW, charBB.shape[-1]) - print " ** no. of words : ", colorize(Color.YELLOW, wordBB.shape[-1]) - print " ** text : ", colorize(Color.GREEN, txt) + print ("image name : ", colorize(Color.RED, k, bold=True)) + print (" ** no. of chars : ", colorize(Color.YELLOW, charBB.shape[-1])) + print (" ** no. of words : ", colorize(Color.YELLOW, wordBB.shape[-1])) + print (" ** text : ", colorize(Color.GREEN, txt)) - if 'q' in raw_input("next? ('q' to exit) : "): + if 'q' in input("next? ('q' to exit) : "): break db.close()